Skip to content
This repository was archived by the owner on Oct 1, 2021. It is now read-only.

Commit 1596dfe

Browse files
committed
feat: require toVersion in migrate()
1 parent 1c923e2 commit 1596dfe

File tree

7 files changed

+65
-59
lines changed

7 files changed

+65
-59
lines changed

.travis.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,13 @@ jobs:
3636
firefox: latest
3737
script: npx aegir test -t browser -- --browsers FirefoxHeadless
3838

39+
- stage: test
40+
name: sharness
41+
os:
42+
- linux
43+
- osx
44+
script: cd ./test/sharness && make
45+
3946
notifications:
4047
email: false
4148

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,30 +77,30 @@ Example:
7777

7878
```js
7979
const migrations = require('ipfs-repo-migrations')
80-
const getVersion = require('ipfs-repo-migrations/repo/version')
8180

8281
const repoPath = 'some/repo/path'
83-
const repoVersion = await getVersion(repoPath)
82+
const currentRepoVersion = 7
83+
const latestVersion = migrations.getLatestMigrationVersion()
8484

85-
if(repoVersion < migrations.getLatestMigrationVersion()){
85+
if(currentRepoVersion < latestVersion){
8686
// Old repo! Lets migrate to latest version!
87-
await migrations.migrate(repoPath)
87+
await migrations.migrate(repoPath, latestVersion)
8888
}
8989
```
9090

9191
To migrate your repository using the CLI, see the [how to run migrations](./run.md) tutorial.
9292

9393
## API
9494

95-
### `.migrate(path, {toVersion, ignoreLock, repoOptions, onProgress, isDryRun}) -> Promise<void>`
95+
### `.migrate(path, toVersion, {ignoreLock, repoOptions, onProgress, isDryRun}) -> Promise<void>`
9696

9797
Executes a forward migration to a specific version, or to the latest version if a specific version is not specified.
9898

9999
**Arguments:**
100100

101101
* `path` (string, mandatory) - path to the repo to be migrated
102+
* `toVersion` (int, mandatory) - version to which the repo should be migrated.
102103
* `options` (object, optional) - options for the migration
103-
* `options.toVersion` (int, optional) - version to which the repo should be migrated. Defaults to the latest migration version.
104104
* `options.ignoreLock` (bool, optional) - if true will not lock the repo when applying migrations. Use with caution.
105105
* `options.repoOptions` (object, optional) - options that are passed to migrations, that use them to construct the datastore. (options are the same as for IPFSRepo).
106106
* `options.onProgress` (function, optional) - callback that is called after finishing execution of each migration to report progress.

src/commands.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ async function migrate ({ repoPath, migrations, to, dry, revertOk }) {
3636
}
3737

3838
if (!to) {
39-
to = migrator.getLatestMigrationVersion()
39+
to = migrator.getLatestMigrationVersion(migrations)
4040
}
4141

4242
const version = await repoVersion.getVersion(repoPath)
@@ -63,7 +63,7 @@ async function migrate ({ repoPath, migrations, to, dry, revertOk }) {
6363
if (version === to) {
6464
return chalk.yellow('Nothing to migrate! Versions matches')
6565
} else if (version < to) {
66-
await migrator.migrate(repoPath, options)
66+
await migrator.migrate(repoPath, to, options)
6767
} else if (revertOk) {
6868
await migrator.revert(repoPath, to, options)
6969
} else {

src/index.js

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -42,17 +42,18 @@ exports.getLatestMigrationVersion = getLatestMigrationVersion
4242
* Signature of the progress callback is: function(migrationObject: object, currentMigrationNumber: int, totalMigrationsCount: int)
4343
*
4444
* @param {string} path - Path to initialized (!) JS-IPFS repo
45+
* @param {int} toVersion - Version to which the repo should be migrated.
4546
* @param {Object} options - Options for migration
46-
* @param {int?} options.toVersion - Version to which the repo should be migrated, if undefined repo will be migrated to the latest version.
4747
* @param {boolean?} options.ignoreLock - Won't lock the repo for applying the migrations. Use with caution.
4848
* @param {object?} options.repoOptions - Options that are passed to migrations, that can use them to correctly construct datastore. Options are same like for IPFSRepo.
4949
* @param {function?} options.onProgress - Callback which will be called after each executed migration to report progress
5050
* @param {boolean?} options.isDryRun - Allows to simulate the execution of the migrations without any effect.
5151
* @param {array?} options.migrations - Array of migrations to migrate. If undefined, the bundled migrations are used. Mainly for testing purpose.
5252
* @returns {Promise<void>}
5353
*/
54-
async function migrate (path, { toVersion, ignoreLock = false, repoOptions, onProgress, isDryRun = false, migrations }) {
54+
async function migrate (path, toVersion, {ignoreLock = false, repoOptions, onProgress, isDryRun = false, migrations }) {
5555
migrations = migrations || defaultMigrations
56+
onProgress = onProgress || (() => {})
5657

5758
if (!path) {
5859
throw new errors.RequiredParameterError('Path argument is required!')
@@ -62,10 +63,13 @@ async function migrate (path, { toVersion, ignoreLock = false, repoOptions, onPr
6263
throw new errors.NotInitializedRepoError(`Repo in path ${path} is not initialized!`)
6364
}
6465

65-
if (toVersion && (!Number.isInteger(toVersion) || toVersion <= 0)) {
66+
if (!toVersion) {
67+
throw new errors.RequiredParameterError('toVersion argument is required!')
68+
}
69+
70+
if (!Number.isInteger(toVersion) || toVersion <= 0) {
6671
throw new errors.InvalidValueError('Version has to be positive integer!')
6772
}
68-
toVersion = toVersion || getLatestMigrationVersion(migrations)
6973

7074
if (toVersion > getLatestMigrationVersion(migrations)) {
7175
throw new errors.InvalidValueError('The ipfs-repo-migrations package does not have migration for version: ' + toVersion)
@@ -74,13 +78,12 @@ async function migrate (path, { toVersion, ignoreLock = false, repoOptions, onPr
7478
const currentVersion = await repoVersion.getVersion(path)
7579

7680
if (currentVersion === toVersion) {
77-
log('Nothing to migrate, skipping migrations.')
81+
log('Nothing to migrate.')
7882
return
7983
}
8084

8185
if (currentVersion > toVersion) {
82-
log(`Current repo's version (${currentVersion}) is higher then toVersion (${toVersion}), nothing to migrate.`)
83-
return
86+
throw new errors.InvalidValueError(`Current repo's version (${currentVersion}) is higher then toVersion (${toVersion}), you probably wanted to revert it?`)
8487
}
8588

8689
let lock
@@ -110,7 +113,7 @@ async function migrate (path, { toVersion, ignoreLock = false, repoOptions, onPr
110113
throw e
111114
}
112115

113-
typeof onProgress === 'function' && onProgress(migration, counter, totalMigrations) // Reports on migration process
116+
onProgress(migration, counter, totalMigrations) // Reports on migration process
114117
log(`Migrating to version ${migration.version} finished`)
115118
}
116119

@@ -141,6 +144,7 @@ exports.migrate = migrate
141144
*/
142145
async function revert (path, toVersion, { ignoreLock = false, repoOptions, onProgress, isDryRun = false, migrations }) {
143146
migrations = migrations || defaultMigrations
147+
onProgress = onProgress || (() => {})
144148

145149
if (!path) {
146150
throw new errors.RequiredParameterError('Path argument is required!')
@@ -160,13 +164,12 @@ async function revert (path, toVersion, { ignoreLock = false, repoOptions, onPro
160164

161165
const currentVersion = await repoVersion.getVersion(path)
162166
if (currentVersion === toVersion) {
163-
log('Nothing to revert, skipping reverting.')
167+
log('Nothing to revert.')
164168
return
165169
}
166170

167171
if (currentVersion < toVersion) {
168-
log(`Current repo's version (${currentVersion}) is lower then toVersion (${toVersion}), nothing to revert.`)
169-
return
172+
throw new errors.InvalidValueError(`Current repo's version (${currentVersion}) is lower then toVersion (${toVersion}), you probably wanted to migrate it?`)
170173
}
171174

172175
const reversibility = verifyReversibility(migrations, currentVersion, toVersion)
@@ -204,7 +207,7 @@ async function revert (path, toVersion, { ignoreLock = false, repoOptions, onPro
204207
throw e
205208
}
206209

207-
typeof onProgress === 'function' && onProgress(migration, counter, totalMigrations) // Reports on migration process
210+
onProgress(migration, counter, totalMigrations) // Reports on migration process
208211
log(`Reverting to version ${migration.version} finished`)
209212
}
210213

test/index.spec.js

Lines changed: 28 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,9 @@ function createMigrations () {
3838
]
3939
}
4040

41-
function createOptions (toVersion) {
41+
function createOptions () {
4242
return {
4343
migrations: createMigrations(),
44-
toVersion
4544
}
4645
}
4746

@@ -123,7 +122,7 @@ describe('index.js', () => {
123122
const options = createOptions()
124123

125124
await expect(migrator.revert('/some/path', 3, options))
126-
.to.eventually.be.fulfilled()
125+
.to.eventually.be.rejectedWith(errors.InvalidValueError).with.property('code', errors.InvalidValueError.code)
127126

128127
expect(lockStub.called).to.be.false()
129128
})
@@ -266,61 +265,58 @@ describe('index.js', () => {
266265
it('should error with out path argument', () => {
267266
const options = createOptions()
268267

269-
return expect(migrator.migrate(undefined, options))
268+
return expect(migrator.migrate(undefined, undefined, options))
269+
.to.eventually.be.rejectedWith(errors.RequiredParameterError).with.property('code', errors.RequiredParameterError.code)
270+
})
271+
272+
it('should error with out toVersion argument', () => {
273+
const options = createOptions()
274+
275+
return expect(migrator.migrate('/some/path', undefined, options))
270276
.to.eventually.be.rejectedWith(errors.RequiredParameterError).with.property('code', errors.RequiredParameterError.code)
271277
})
272278

273279
it('should error with invalid toVersion argument', () => {
274-
const invalidValues = ['eight', '-1', '1', -1]
280+
const invalidValues = ['eight', '-1', '1', -1, {}]
275281

276282
return Promise.all(
277-
invalidValues.map((invalidValue) => expect(migrator.migrate('/some/path', createOptions(invalidValue)))
283+
invalidValues.map((invalidValue) => expect(migrator.migrate('/some/path', invalidValue, createOptions()))
278284
.to.eventually.be.rejectedWith(errors.InvalidValueError).with.property('code', errors.InvalidValueError.code))
279285
)
280286
})
281287

282288
it('should error if migrations does not exist', () => {
283-
const options = createOptions(5)
284-
285-
return expect(migrator.migrate('/some/path', options))
286-
.to.eventually.be.rejectedWith(errors.InvalidValueError).with.property('code', errors.InvalidValueError.code)
287-
})
288-
289-
it('should use latest migration\'s version if no toVersion is provided', async () => {
290289
const options = createOptions()
291-
getVersionStub.returns(2)
292-
293-
await expect(migrator.migrate('/some/path', options))
294-
.to.eventually.be.fulfilled()
295290

296-
setVersionStub.calledOnceWithExactly('/some/path', 4) // 4 is the latest migration's version
291+
return expect(migrator.migrate('/some/path', 5, options))
292+
.to.eventually.be.rejectedWith(errors.InvalidValueError).with.property('code', errors.InvalidValueError.code)
297293
})
298294

299295
it('should not migrate if current repo version and toVersion matches', async () => {
300296
getVersionStub.returns(2)
301-
const options = createOptions(2)
297+
const options = createOptions()
302298

303-
await expect(migrator.migrate('/some/path', options))
299+
await expect(migrator.migrate('/some/path', 2, options))
304300
.to.eventually.be.fulfilled()
305301

306302
expect(lockStub.called).to.be.false()
307303
})
308304

309305
it('should not migrate if current repo version is higher then toVersion', async () => {
310306
getVersionStub.returns(3)
311-
const options = createOptions(2)
307+
const options = createOptions()
312308

313-
await expect(migrator.migrate('/some/path', options))
314-
.to.eventually.be.fulfilled()
309+
await expect(migrator.migrate('/some/path', 2, options))
310+
.to.eventually.be.rejectedWith(errors.InvalidValueError).with.property('code', errors.InvalidValueError.code)
315311

316312
expect(lockStub.called).to.be.false()
317313
})
318314

319315
it('should migrate expected migrations', async () => {
320-
const options = createOptions(3)
316+
const options = createOptions()
321317
getVersionStub.returns(1)
322318

323-
await expect(migrator.migrate('/some/path', options))
319+
await expect(migrator.migrate('/some/path', 3, options))
324320
.to.eventually.be.fulfilled()
325321

326322
expect(lockCloseStub.calledOnce).to.be.true()
@@ -335,11 +331,11 @@ describe('index.js', () => {
335331
})
336332

337333
it('should not have any side-effects when in dry run', async () => {
338-
const options = createOptions(4)
334+
const options = createOptions()
339335
options.isDryRun = true
340336
getVersionStub.returns(2)
341337

342-
await expect(migrator.migrate('/some/path', options))
338+
await expect(migrator.migrate('/some/path', 4, options))
343339
.to.eventually.be.fulfilled()
344340

345341
expect(lockCloseStub.called).to.be.false()
@@ -354,7 +350,7 @@ describe('index.js', () => {
354350
options.ignoreLock = true
355351
getVersionStub.returns(2)
356352

357-
await expect(migrator.migrate('/some/path', options))
353+
await expect(migrator.migrate('/some/path', 4, options))
358354
.to.eventually.be.fulfilled()
359355

360356
expect(lockCloseStub.called).to.be.false()
@@ -369,11 +365,11 @@ describe('index.js', () => {
369365
})
370366

371367
it('should report progress when progress callback is supplied', async () => {
372-
const options = createOptions(4)
368+
const options = createOptions()
373369
options.onProgress = sinon.stub()
374370
getVersionStub.returns(2)
375371

376-
await expect(migrator.migrate('/some/path', options))
372+
await expect(migrator.migrate('/some/path', 4, options))
377373
.to.eventually.be.fulfilled()
378374

379375
expect(options.onProgress.getCall(0).calledWith(sinon.match.any, 1, 2)).to.be.true()
@@ -382,10 +378,10 @@ describe('index.js', () => {
382378

383379
it('should unlock repo when error is thrown', async () => {
384380
getVersionStub.returns(2)
385-
const options = createOptions(4)
381+
const options = createOptions()
386382
options.migrations[3].migrate = sinon.stub().rejects()
387383

388-
await expect(migrator.migrate('/some/path', options))
384+
await expect(migrator.migrate('/some/path', 4, options))
389385
.to.eventually.be.rejected()
390386

391387
expect(lockCloseStub.calledOnce).to.be.true()

test/integration-test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ module.exports = (setup, cleanup) => {
2323
)
2424

2525
it('migrate forward', async () => {
26-
await migrator.migrate(dir, { migrations: migrations })
26+
await migrator.migrate(dir, migrator.getLatestMigrationVersion(migrations), { migrations: migrations })
2727

2828
const store = new Datastore(dir, { extension: '', createIfMissing: false })
2929

@@ -37,7 +37,7 @@ module.exports = (setup, cleanup) => {
3737
})
3838

3939
it('revert', async () => {
40-
await migrator.migrate(dir, { migrations: migrations })
40+
await migrator.migrate(dir, migrator.getLatestMigrationVersion(migrations), { migrations: migrations })
4141

4242
await migrator.revert(dir, 1, { migrations: migrations })
4343

test/sharness/t0010-basic-commands.sh

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ test_description="Test installation and some basic commands"
88

99
# setup temp repo
1010
rm -rf ./tmp
11-
cp -r ../test-repo ./tmp
11+
cp -r ../fixtures/test-repo ./tmp
1212
IPFS_PATH=$(echo `pwd`/tmp)
1313
export IPFS_PATH
1414

@@ -29,9 +29,9 @@ test_expect_success "jsipfs-migrations help succeeds" '
2929

3030
test_expect_success "jsipfs-migrations status shows migrations are needed" $'
3131
jsipfs-migrations status --migrations ../test/test-migrations > status.txt &&
32-
grep "There are migrations to be applied!" status.txt &&
32+
grep "Repo is out of date" status.txt &&
3333
grep "Current repo version: 1" status.txt &&
34-
grep "Last migration\'s version: 2" status.txt
34+
grep "Latest migration version: 2" status.txt
3535
'
3636

3737
test_expect_success "jsipfs-migrations successfully migrate to latest version" $'
@@ -41,9 +41,9 @@ test_expect_success "jsipfs-migrations successfully migrate to latest version" $
4141

4242
test_expect_success "jsipfs-migrations status shows NO migrations are needed" $'
4343
jsipfs-migrations status --migrations ../test/test-migrations > status.txt &&
44-
grep "Nothing to migrate!" status.txt &&
44+
grep "Nothing to migrate" status.txt &&
4545
grep "Current repo version: 2" status.txt &&
46-
grep "Last migration\'s version: 2" status.txt
46+
grep "Latest migration version: 2" status.txt
4747
'
4848

4949
test_expect_success "jsipfs-migrations successfully reverts" $'

0 commit comments

Comments
 (0)