diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8619949d..8de0caab 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,7 +2,7 @@ name: CI on: [push, pull_request] jobs: - build: + test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -29,3 +29,42 @@ jobs: with: node-version: 12.x - run: npm test --ignore-scripts + create_tgz: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Setup node 20 + uses: actions/setup-node@v2 + with: + node-version: 20.x + - run: npm install + - run: npm run build + - run: npm pack + - run: mv $(ls | grep .tgz) umzug.tgz + - uses: actions/upload-artifact@v3 + with: + name: tarball + path: umzug.tgz + test_tgz: + runs-on: ubuntu-latest + needs: [create_tgz] + steps: + - uses: actions/checkout@v3 + - uses: actions/download-artifact@v3 + with: + name: tarball + - run: ls + - name: install tarball in examples directory + working-directory: examples/0.vanilla + run: | + rm -rf ../node_modules + npm init -y + npm install ../../umzug.tgz + - name: run example + run: | + cd examples/0.vanilla + node migrate up + node migrate down + node migrate create --name new-migration.js + node migrate up + - run: ls -R diff --git a/examples/0.vanilla/ignoreme/uzmug.json b/examples/0.vanilla/ignoreme/uzmug.json new file mode 100644 index 00000000..0637a088 --- /dev/null +++ b/examples/0.vanilla/ignoreme/uzmug.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/examples/0.vanilla/migrate.js b/examples/0.vanilla/migrate.js new file mode 100644 index 00000000..53e2f6e0 --- /dev/null +++ b/examples/0.vanilla/migrate.js @@ -0,0 +1,14 @@ +const { Umzug, JSONStorage } = require('umzug'); + +exports.migrator = new Umzug({ + migrations: { + glob: 'migrations/*.js', + }, + context: { directory: __dirname + '/ignoreme' }, + storage: new JSONStorage({ path: 'ignoreme/uzmug.json' }), + logger: console, +}); + +if (require.main === module) { + exports.migrator.runAsCLI(); +} diff --git a/examples/0.vanilla/migrations/2023.11.03T16.52.04.users-table.js b/examples/0.vanilla/migrations/2023.11.03T16.52.04.users-table.js new file mode 100644 index 00000000..fce1f71c --- /dev/null +++ b/examples/0.vanilla/migrations/2023.11.03T16.52.04.users-table.js @@ -0,0 +1,12 @@ +const { promises: fs } = require('fs'); + +/** @type {typeof import('../migrate').migrator['_types']['migration']} */ +exports.up = async ({ context }) => { + await fs.mkdir(context.directory, { recursive: true }); + await fs.writeFile(context.directory + '/users.json', JSON.stringify([], null, 2)); +}; + +/** @type {typeof import('../migrate').migrator['_types']['migration']} */ +exports.down = async ({ context }) => { + await fs.unlink(context.directory + '/users.json'); +}; diff --git a/examples/0.vanilla/readme.md b/examples/0.vanilla/readme.md new file mode 100644 index 00000000..c11689f2 --- /dev/null +++ b/examples/0.vanilla/readme.md @@ -0,0 +1,16 @@ +This example shows the simplest possible, node-only setup for Umzug. No typescript, no database, no dependencies. + +Note: +- The `context` for the migrations just contains a (gitignored) directory. +- The example migration just writes an empty file to the directory + +```bash +node migrate --help # show CLI help + +node migrate up # apply migrations +node migrate down # revert the last migration +node migrate create --name new-migration.js # create a new migration file + +node migrate up # apply migrations again +node migrate down --to 0 # revert all migrations +``` diff --git a/package-lock.json b/package-lock.json index ae6d3a13..b9738de0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -34,6 +34,7 @@ "eslint-plugin-mocha": "10.1.0", "eslint-plugin-prettier": "4.2.1", "eslint-plugin-unicorn": "44.0.2", + "execa": "^5.1.1", "expect-type": "0.14.2", "fs-syncer": "0.4.0", "jest": "29.1.2", @@ -45,7 +46,7 @@ "sinon": "14.0.0", "source-map-support": "0.5.21", "sqlite3": "npm:@vscode/sqlite3@5.0.8", - "strip-ansi": "^6.0.1", + "strip-ansi": "6.0.1", "ts-jest": "29.0.3", "ts-node": "10.9.1", "typescript": "4.8.4", @@ -3671,18 +3672,6 @@ "node": ">=14.18.0" } }, - "node_modules/default-browser/node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/default-browser/node_modules/mimic-fn": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", @@ -3695,21 +3684,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/default-browser/node_modules/npm-run-path": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", - "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", - "dev": true, - "dependencies": { - "path-key": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/default-browser/node_modules/onetime": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", @@ -3725,30 +3699,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/default-browser/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-browser/node_modules/strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/defaults": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", @@ -4853,6 +4803,39 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/execa/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/execa/node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/execa/node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/exit": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", @@ -6423,12 +6406,15 @@ } }, "node_modules/is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", "dev": true, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/is-string": { @@ -9493,18 +9479,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/np/node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/np/node_modules/locate-path": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", @@ -9573,21 +9547,6 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/np/node_modules/npm-run-path": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", - "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", - "dev": true, - "dependencies": { - "path-key": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/np/node_modules/onetime": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", @@ -9642,18 +9601,6 @@ "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, - "node_modules/np/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/np/node_modules/pkg-dir": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", @@ -9794,18 +9741,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/np/node_modules/strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/np/node_modules/terminal-link": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-3.0.0.tgz", @@ -9880,15 +9815,30 @@ } }, "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", "dev": true, "dependencies": { - "path-key": "^3.0.0" + "path-key": "^4.0.0" }, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/number-is-nan": { @@ -11700,12 +11650,15 @@ } }, "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", "dev": true, "engines": { - "node": ">=6" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/strip-indent": { @@ -15340,27 +15293,12 @@ "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", "dev": true }, - "is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "dev": true - }, "mimic-fn": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", "dev": true }, - "npm-run-path": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", - "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", - "dev": true, - "requires": { - "path-key": "^4.0.0" - } - }, "onetime": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", @@ -15369,18 +15307,6 @@ "requires": { "mimic-fn": "^4.0.0" } - }, - "path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "dev": true - }, - "strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", - "dev": true } } }, @@ -16176,6 +16102,27 @@ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true } } }, @@ -17325,9 +17272,9 @@ "dev": true }, "is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", "dev": true }, "is-string": { @@ -19614,12 +19561,6 @@ "integrity": "sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==", "dev": true }, - "is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "dev": true - }, "locate-path": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", @@ -19667,15 +19608,6 @@ "validate-npm-package-license": "^3.0.4" } }, - "npm-run-path": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", - "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", - "dev": true, - "requires": { - "path-key": "^4.0.0" - } - }, "onetime": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", @@ -19709,12 +19641,6 @@ "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", "dev": true }, - "path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "dev": true - }, "pkg-dir": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", @@ -19805,12 +19731,6 @@ "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", "dev": true }, - "strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", - "dev": true - }, "terminal-link": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-3.0.0.tgz", @@ -19860,12 +19780,20 @@ } }, "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", "dev": true, "requires": { - "path-key": "^3.0.0" + "path-key": "^4.0.0" + }, + "dependencies": { + "path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true + } } }, "number-is-nan": { @@ -21145,9 +21073,9 @@ "dev": true }, "strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", "dev": true }, "strip-indent": { diff --git a/package.json b/package.json index 7af89201..1e062c57 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "eslint-plugin-mocha": "10.1.0", "eslint-plugin-prettier": "4.2.1", "eslint-plugin-unicorn": "44.0.2", + "execa": "^5.1.1", "expect-type": "0.14.2", "fs-syncer": "0.4.0", "jest": "29.1.2", diff --git a/test/__snapshots__/examples.test.ts.snap b/test/__snapshots__/examples.test.ts.snap index ed3a6de1..99bd9590 100644 --- a/test/__snapshots__/examples.test.ts.snap +++ b/test/__snapshots__/examples.test.ts.snap @@ -1,5 +1,70 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`example 0.vanilla 1`] = ` +"\`node migrate --help\` output: + +... + +\`node migrate up\` output: + +{ event: 'migrating', name: '<>.users-table.js' } +{ + event: 'migrated', + name: '<>.users-table.js', + durationSeconds: ??? +} +{ event: 'up', message: 'applied 1 migrations.' } + +\`node migrate down\` output: + +{ event: 'reverting', name: '<>.users-table.js' } +{ + event: 'reverted', + name: '<>.users-table.js', + durationSeconds: ??? +} +{ event: 'down', message: 'reverted 1 migrations.' } + +\`node migrate create --name new-migration.js\` output: + +{ + event: 'created', + path: '<>/examples/0.vanilla/migrations/<>.new-migration.js' +} + +\`node migrate up\` output: + +{ event: 'migrating', name: '<>.users-table.js' } +{ + event: 'migrated', + name: '<>.users-table.js', + durationSeconds: ??? +} +{ event: 'migrating', name: '<>.new-migration.js' } +{ + event: 'migrated', + name: '<>.new-migration.js', + durationSeconds: ??? +} +{ event: 'up', message: 'applied 2 migrations.' } + +\`node migrate down --to 0\` output: + +{ event: 'reverting', name: '<>.new-migration.js' } +{ + event: 'reverted', + name: '<>.new-migration.js', + durationSeconds: ??? +} +{ event: 'reverting', name: '<>.users-table.js' } +{ + event: 'reverted', + name: '<>.users-table.js', + durationSeconds: ??? +} +{ event: 'down', message: 'reverted 2 migrations.' }" +`; + exports[`example 1.sequelize-typescript 1`] = ` "\`node migrate --help\` output: diff --git a/test/examples.test.ts b/test/examples.test.ts index 3ff88ca7..a07c3c40 100644 --- a/test/examples.test.ts +++ b/test/examples.test.ts @@ -1,16 +1,16 @@ import fs = require('fs'); import path = require('path'); -import childProcess = require('child_process'); import stripAnsi = require('strip-ansi'); +import execa = require('execa'); const examplesDir = path.join(__dirname, '../examples'); const examples = fs.readdirSync(examplesDir).filter(ex => /^\d/.exec(ex)); /** get rid of any untracked files, including newly-created migrations and the sqlite db file, so that each run is from scratch and has the same output (give or take timings etc.) */ const cleanup = (cwd: string) => { - childProcess.execSync('git checkout migrations && git clean migrations seeders db.sqlite -fx', { + execa.sync('git', ['diff', '--exit-code', '.'], { cwd }); + execa.sync('sh', ['-c', 'git checkout migrations && git clean migrations seeders db.sqlite ignoreme -fx'], { cwd, - stdio: 'inherit', }); }; @@ -28,13 +28,17 @@ examples.forEach(ex => { .map(line => line.split('#')[0].trim()) .filter(Boolean) .flatMap(cmd => { - let output = childProcess.execSync(`sh -c "${cmd} 2>&1"`, { cwd: dir }).toString().trim(); - output = stripAnsi(output); - output = cmd.startsWith('npm') || cmd.endsWith('--help') ? '...' : output; // npm commands and `--help` are formatted inconsistently and aren't v relevant - output = output.split(process.cwd()).join('<>'); // cwd varies by machine - output = output.replace(/durationSeconds: .*/g, 'durationSeconds: ???'); // migrations durations vary by a few milliseconds - output = output.replace(/\d{4}.\d{2}.\d{2}T\d{2}.\d{2}.\d{2}/g, '<>'); // the river of time flows only in one direction - return [`\`${cmd}\` output:`, output]; + try { + let output = execa.sync('sh', ['-c', `${cmd} 2>&1`], { cwd: dir }).stdout; + output = stripAnsi(output); + output = cmd.startsWith('npm') || cmd.endsWith('--help') ? '...' : output; // npm commands and `--help` are formatted inconsistently and aren't v relevant + output = output.split(process.cwd()).join('<>'); // cwd varies by machine + output = output.replace(/durationSeconds: .*/g, 'durationSeconds: ???'); // migrations durations vary by a few milliseconds + output = output.replace(/\d{4}.\d{2}.\d{2}T\d{2}.\d{2}.\d{2}/g, '<>'); // the river of time flows only in one direction + return [`\`${cmd}\` output:`, output]; + } catch (err: unknown) { + throw new Error(`Processing command "${cmd}" in ${dir} failed:\n${String(err)}`); + } }) .join('\n\n');