diff --git a/package-lock.json b/package-lock.json index c58e01e70a..aa6b8599cd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5854,6 +5854,16 @@ "@types/node": "*" } }, + "node_modules/@types/inquirer": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/@types/inquirer/-/inquirer-9.0.3.tgz", + "integrity": "sha512-CzNkWqQftcmk2jaCWdBTf9Sm7xSw4rkI1zpU/Udw3HX5//adEZUIm9STtoRP1qgWj0CWQtJ9UTvqmO2NNjhMJw==", + "dev": true, + "dependencies": { + "@types/through": "*", + "rxjs": "^7.2.0" + } + }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", @@ -6371,6 +6381,15 @@ "@types/jest": "*" } }, + "node_modules/@types/through": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/@types/through/-/through-0.0.30.tgz", + "integrity": "sha512-FvnCJljyxhPM3gkRgWmxmDZyAQSiBQQWLI0A0VFL0K7W1oRUrPJSqNO0NvTnLkBcotdlp3lKvaT0JrnyRDkzOg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/tough-cookie": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.2.tgz", @@ -8828,8 +8847,7 @@ "node_modules/chardet": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" }, "node_modules/chart.js": { "version": "2.9.4", @@ -9086,7 +9104,6 @@ "version": "2.6.1", "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", - "dev": true, "engines": { "node": ">=6" }, @@ -9135,7 +9152,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", - "dev": true, "engines": { "node": ">=0.8" } @@ -10509,7 +10525,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", - "dev": true, "dependencies": { "clone": "^1.0.2" }, @@ -11068,6 +11083,11 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" + }, "node_modules/ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -13140,7 +13160,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, "dependencies": { "chardet": "^0.7.0", "iconv-lite": "^0.4.24", @@ -13154,7 +13173,6 @@ "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -21642,8 +21660,7 @@ "node_modules/mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" }, "node_modules/nan": { "version": "2.17.0", @@ -25386,7 +25403,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -28117,7 +28133,6 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "dev": true, "engines": { "node": ">=0.12.0" } @@ -28158,7 +28173,6 @@ "version": "7.8.0", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz", "integrity": "sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==", - "dev": true, "dependencies": { "tslib": "^2.1.0" } @@ -30258,7 +30272,6 @@ "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, "dependencies": { "os-tmpdir": "~1.0.2" }, @@ -31296,7 +31309,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", - "dev": true, "dependencies": { "defaults": "^1.0.3" } @@ -34456,6 +34468,7 @@ "version": "6.4.0-beta.13", "license": "MIT", "dependencies": { + "inquirer": "^9.1.4", "semver": "^7.3.8" }, "bin": { @@ -34464,6 +34477,7 @@ "devDependencies": { "@swc/cli": "^0.1.61", "@swc/core": "^1.3.35", + "@types/inquirer": "^9.0.3", "@types/node": "^16.18.11", "@types/semver": "^7.3.13", "rimraf": "^4.1.2" @@ -34475,6 +34489,295 @@ "integrity": "sha512-vzLe5NaNMjIE3mcddFVGlAXN1LEWueUsMsOJWaT6wWMJGyljHAWHznqfnKUQWGzu7TLPrGvWdNAsvQYW+C0xtw==", "dev": true }, + "packages/release-tool/node_modules/ansi-escapes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.0.0.tgz", + "integrity": "sha512-IG23inYII3dWlU2EyiAiGj6Bwal5GzsgPMwjYGvc1HPE2dgbj4ZB5ToWBKSquKw74nB3TIuOwaI6/jSULzfgrw==", + "dependencies": { + "type-fest": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/release-tool/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "packages/release-tool/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "packages/release-tool/node_modules/bl": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-5.1.0.tgz", + "integrity": "sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==", + "dependencies": { + "buffer": "^6.0.3", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "packages/release-tool/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "packages/release-tool/node_modules/chalk": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz", + "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "packages/release-tool/node_modules/cli-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", + "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", + "dependencies": { + "restore-cursor": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/release-tool/node_modules/cli-width": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.0.0.tgz", + "integrity": "sha512-ZksGS2xpa/bYkNzN3BAw1wEjsLV/ZKOf/CCrJ/QOBsxx6fOARIkwTutxp1XIOIohi6HKmOFjMoK/XaqDVUpEEw==", + "engines": { + "node": ">= 12" + } + }, + "packages/release-tool/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "packages/release-tool/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/release-tool/node_modules/figures": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-5.0.0.tgz", + "integrity": "sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg==", + "dependencies": { + "escape-string-regexp": "^5.0.0", + "is-unicode-supported": "^1.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/release-tool/node_modules/inquirer": { + "version": "9.1.4", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.1.4.tgz", + "integrity": "sha512-9hiJxE5gkK/cM2d1mTEnuurGTAoHebbkX0BYl3h7iEg7FYfuNIom+nDfBCSWtvSnoSrWCeBxqqBZu26xdlJlXA==", + "dependencies": { + "ansi-escapes": "^6.0.0", + "chalk": "^5.1.2", + "cli-cursor": "^4.0.0", + "cli-width": "^4.0.0", + "external-editor": "^3.0.3", + "figures": "^5.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^6.1.2", + "run-async": "^2.4.0", + "rxjs": "^7.5.7", + "string-width": "^5.1.2", + "strip-ansi": "^7.0.1", + "through": "^2.3.6", + "wrap-ansi": "^8.0.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "packages/release-tool/node_modules/is-interactive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", + "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/release-tool/node_modules/is-unicode-supported": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", + "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/release-tool/node_modules/log-symbols": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-5.1.0.tgz", + "integrity": "sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==", + "dependencies": { + "chalk": "^5.0.0", + "is-unicode-supported": "^1.1.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/release-tool/node_modules/ora": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/ora/-/ora-6.1.2.tgz", + "integrity": "sha512-EJQ3NiP5Xo94wJXIzAyOtSb0QEIAUu7m8t6UZ9krbz0vAJqr92JpcK/lEXg91q6B9pEGqrykkd2EQplnifDSBw==", + "dependencies": { + "bl": "^5.0.0", + "chalk": "^5.0.0", + "cli-cursor": "^4.0.0", + "cli-spinners": "^2.6.1", + "is-interactive": "^2.0.0", + "is-unicode-supported": "^1.1.0", + "log-symbols": "^5.1.0", + "strip-ansi": "^7.0.1", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/release-tool/node_modules/restore-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", + "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/release-tool/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/release-tool/node_modules/strip-ansi": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", + "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "packages/release-tool/node_modules/type-fest": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.6.0.tgz", + "integrity": "sha512-RqTRtKTzvPpNdDUp1dVkKQRunlPITk4mXeqFlAZoJsS+fLRn8AdPK0TcQDumGayhU7fjlBfiBjsq3pe3rIfXZQ==", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "packages/release-tool/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "packages/semver": { "name": "@k8slens/semver", "version": "6.4.0-beta.13", diff --git a/packages/release-tool/package.json b/packages/release-tool/package.json index 8a69fbd404..95bcc9c495 100644 --- a/packages/release-tool/package.json +++ b/packages/release-tool/package.json @@ -16,11 +16,13 @@ "devDependencies": { "@swc/cli": "^0.1.61", "@swc/core": "^1.3.35", + "@types/inquirer": "^9.0.3", "@types/node": "^16.18.11", "@types/semver": "^7.3.13", "rimraf": "^4.1.2" }, "dependencies": { + "inquirer": "^9.1.4", "semver": "^7.3.8" } } diff --git a/packages/release-tool/src/index.ts b/packages/release-tool/src/index.ts index 9780874afd..6133e7c31c 100755 --- a/packages/release-tool/src/index.ts +++ b/packages/release-tool/src/index.ts @@ -3,12 +3,16 @@ * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ +import assert from "assert"; import child_process from "child_process"; import { readFile } from "fs/promises"; -import { createInterface } from "readline"; +import inquirer from "inquirer"; +import { createInterface, ReadLine } from "readline"; import semver from "semver"; import { promisify } from "util"; +type SemVer = semver.SemVer; + const { SemVer, valid: semverValid, @@ -18,53 +22,6 @@ const { const exec = promisify(child_process.exec); const spawn = promisify(child_process.spawn); -const repoRoot = (await exec("git rev-parse --show-toplevel")).stdout.trim(); - -if (process.cwd() !== repoRoot) { - console.error("It looks like you are running this script from the 'scripts' directory. This script assumes it is run from the root of the git repo"); - process.exit(1); -} - -const currentVersion = new SemVer(JSON.parse((await readFile("./lerna.json", "utf-8"))).version); - -await spawn("npm", ["run", "bump-version"], { - stdio: "inherit", -}); - -const newVersion = new SemVer(JSON.parse((await readFile("./lerna.json", "utf-8"))).version); -const newVersionMilestone = `${newVersion.major}.${newVersion.minor}.${newVersion.patch}`; -const prBranch = `release/v${newVersion.format()}`; - -await spawn("git", ["checkout", "-b", prBranch], { - stdio: "inherit", -}); -await spawn("git", ["add", "lerna.json", "packages/*/package.json"], { - stdio: "inherit", -}); -await spawn("git", ["commit", "-sm", `"Release ${newVersion.format()}"`], { - stdio: "inherit", -}); -await spawn("git", ["fetch", "--tags", "--force"], { - stdio: "inherit", -}); - -const actualTags = (await exec("git tag --list", { encoding: "utf-8" })).stdout.split(/\r?\n/).map(line => line.trim()); -const [previousReleasedVersion] = actualTags - .map((value) => semverValid(value)) - .filter((v): v is string => typeof v === "string") - .sort(semverRcompare) - .filter(version => semverLte(version, currentVersion)); - -const getMergedPrsArgs = [ - "gh", - "pr", - "list", - "--limit=500", // Should be big enough, if not we need to release more often ;) - "--state=merged", - "--base=master", - "--json mergeCommit,title,author,labels,number,milestone,mergedAt", -]; - interface GithubPrData { author: { login: string; @@ -93,156 +50,254 @@ interface ExtendedGithubPrData extends Omit { mergedAt: Date; } -console.log("retreiving last 500 PRs to create release PR body..."); -const mergedPrs = JSON.parse((await exec(getMergedPrsArgs.join(" "), { encoding: "utf-8" })).stdout) as GithubPrData[]; -const milestoneRelevantPrs = mergedPrs.filter(pr => pr.milestone?.title === newVersionMilestone); -const relaventPrsQuery = await Promise.all( - milestoneRelevantPrs.map(async pr => ({ - pr, - stdout: (await exec(`git tag v${previousReleasedVersion} --no-contains ${pr.mergeCommit.oid}`)).stdout, - })), -); -const relaventPrs = relaventPrsQuery - .filter(query => query.stdout) - .map(query => query.pr) - .filter(pr => pr.labels.every(label => label.name !== "skip-changelog")) - .map(pr => ({ ...pr, mergedAt: new Date(pr.mergedAt) } as ExtendedGithubPrData)) - .sort((left, right) => { - const leftAge = left.mergedAt.valueOf(); - const rightAge = right.mergedAt.valueOf(); +async function getCurrentBranch(): Promise { + return (await exec("git branch --show-current")).stdout.trim(); +} - if (leftAge === rightAge) { - return 0; - } +async function getAbsolutePathToRepoRoot(): Promise { + return (await exec("git rev-parse --show-toplevel")).stdout.trim(); +} - if (leftAge > rightAge) { - return 1; - } - - return -1; +async function fetchAllGitTags(): Promise { + await spawn("git", ["fetch", "--tags", "--force"], { + stdio: "inherit", }); -const enhancementPrLabelName = "enhancement"; -const bugfixPrLabelName = "bug"; + return (await exec("git tag --list", { encoding: "utf-8" })) + .stdout + .split(/\r?\n/) + .map(line => line.trim()); +} -const isEnhancementPr = (pr: ExtendedGithubPrData) => pr.labels.some(label => label.name === enhancementPrLabelName); -const isBugfixPr = (pr: ExtendedGithubPrData) => pr.labels.some(label => label.name === bugfixPrLabelName); +async function bumpPackageVersions(): Promise { + await spawn("npm", ["run", "bump-version"], { + stdio: "inherit", + }); +} -const prLines = { - enhancement: [] as string[], - bugfix: [] as string[], - maintenence: [] as string[], -}; +function findClosestVersionTagLessThanVersion(tags: string[], version: SemVer): string { + const lessThanTags = tags + .map((value) => semverValid(value)) + .filter((v): v is string => typeof v === "string") + .sort(semverRcompare) + .filter(version => semverLte(version, version)); -function getPrEntry(pr: ExtendedGithubPrData) { + assert(lessThanTags.length > 0, `Cannot find version tag less than ${version.format()}`); + + return lessThanTags[0]; +} + +async function getCurrentVersionOfSubPackage(packageName: string): Promise { + const packageJson = JSON.parse(await readFile(`./packages/${packageName}/package.json`, "utf-8")); + + return new SemVer(packageJson.version); +} + +async function checkCurrentWorkingDirectory(): Promise { + const repoRoot = await getAbsolutePathToRepoRoot(); + + if (process.cwd() !== repoRoot) { + console.error("It looks like you are running this script from the 'scripts' directory. This script assumes it is run from the root of the git repo"); + process.exit(1); + } +} + +function formatSemverForMilestone(version: SemVer): string { + return `${version.major}.${version.minor}.${version.patch}`; +} + +async function createReleaseBranchAndCommit(prBase: string, version: SemVer, prBody: string): Promise { + const prBranch = `release/v${version.format()}`; + + await spawn("git", ["checkout", "-b", prBranch], { + stdio: "inherit", + }); + await spawn("git", ["add", "lerna.json", "packages/*/package.json"], { + stdio: "inherit", + }); + await spawn("git", ["commit", "-sm", `"Release ${version.format()}"`], { + stdio: "inherit", + }); + await spawn("git", ["push", "--set-upstream", "origin", prBranch], { + stdio: "inherit", + }); + + await spawn("gh", [ + "pr", + "create", + "--base", prBase, + "--title", `Release ${version.format()}`, + "--label", "skip-changelog", + "--label", "release", + "--milestone", formatSemverForMilestone(version), + "--body-file", prBody, + ], { + stdio: "inherit" + }); +} + +function sortExtendedGithubPrData(left: ExtendedGithubPrData, right: ExtendedGithubPrData): number { + const leftAge = left.mergedAt.valueOf(); + const rightAge = right.mergedAt.valueOf(); + + if (leftAge === rightAge) { + return 0; + } + + if (leftAge > rightAge) { + return 1; + } + + return -1; +} + +async function getRelaventPRs(milestone: string, previousReleasedVersion: string): Promise { + console.log("retreiving previous 500 PRs..."); + + const getMergedPrsArgs = [ + "gh", + "pr", + "list", + "--limit=500", // Should be big enough, if not we need to release more often ;) + "--state=merged", + "--base=master", + "--json mergeCommit,title,author,labels,number,milestone,mergedAt", + ]; + + const mergedPrs = JSON.parse((await exec(getMergedPrsArgs.join(" "), { encoding: "utf-8" })).stdout) as GithubPrData[]; + const milestoneRelevantPrs = mergedPrs.filter(pr => pr.milestone?.title === milestone); + const relaventPrsQuery = await Promise.all( + milestoneRelevantPrs.map(async pr => ({ + pr, + stdout: (await exec(`git tag v${previousReleasedVersion} --no-contains ${pr.mergeCommit.oid}`)).stdout, + })), + ); + + return relaventPrsQuery + .filter(query => query.stdout) + .map(query => query.pr) + .filter(pr => pr.labels.every(label => label.name !== "skip-changelog")) + .map(pr => ({ ...pr, mergedAt: new Date(pr.mergedAt) } as ExtendedGithubPrData)) + .sort(sortExtendedGithubPrData); +} + +function formatPrEntry(pr: ExtendedGithubPrData) { return `- ${pr.title} (**[#${pr.number}](https://github.com/lensapp/lens/pull/${pr.number})**) https://github.com/${pr.author.login}`; } -const rl = createInterface(process.stdin); -const prBase = (await exec("git branch --show-current")).stdout.trim(); +const isEnhancementPr = (pr: ExtendedGithubPrData) => pr.labels.some(label => label.name === "enhancement"); +const isBugfixPr = (pr: ExtendedGithubPrData) => pr.labels.some(label => label.name === "bug"); -function askQuestion(question: string): Promise { - return new Promise(resolve => { - function _askQuestion() { - console.log(question); - - rl.once("line", (answer) => { - const cleaned = answer.trim().toLowerCase(); - - if (cleaned === "y") { - resolve(true); - } else if (cleaned === "n") { - resolve(false); - } else { - _askQuestion(); - } - }); - } - - _askQuestion(); - }); -} - -async function handleRelaventPr(pr: ExtendedGithubPrData) { - if (prBase !== "master" && !(await askQuestion(`Would you like to use #${pr.number}: ${pr.title}? - Y/N`))) { - return; - } - - if (prBase !== "master") { +const cherrypickCommitWith = (rl: ReadLine) => async (commit: string) => { try { - await spawn("git", ["cherry-pick", pr.mergeCommit.oid], { - stdio: "inherit", - }); - } catch { - console.error(`Failed to cherry-pick ${pr.mergeCommit.oid}, please resolve conflicts and then press enter here:`); - await new Promise(resolve => rl.once("line", () => resolve())); + await spawn("git", ["cherry-pick", commit], { + stdio: "inherit", + }); + } catch { + console.error(`Please resolve conflicts and then press enter here...`); + await new Promise(resolve => rl.once("line", () => resolve())); + } +}; + +async function pickWhichCommitsToUse(prs: ExtendedGithubPrData[]): Promise { + console.log("Pick which commits to use..."); + const answers = await inquirer.prompt>>(prs.map(pr => ({ + message: `#${pr.number}: ${pr.title}`, + type: "checkbox", + default: true, + name: pr.number, + }))); + + return prs.filter(pr => answers[pr.number]); +} + +function formatChangelog(previousReleasedVersion: string, prs: ExtendedGithubPrData[]): string { + const enhancementPrLines: string[] = []; + const bugPrLines: string[] = []; + const maintenencePrLines: string[] = []; + + for (const pr of prs) { + if (isEnhancementPr(pr)) { + enhancementPrLines.push(formatPrEntry(pr)); + } else if (isBugfixPr(pr)) { + bugPrLines.push(formatPrEntry(pr)); + } else { + maintenencePrLines.push(formatPrEntry(pr)); } } - if (isEnhancementPr(pr)) { - prLines.enhancement.push(getPrEntry(pr)); - } else if (isBugfixPr(pr)) { - prLines.bugfix.push(getPrEntry(pr)); - } else { - prLines.maintenence.push(getPrEntry(pr)); + if (enhancementPrLines.length > 0) { + enhancementPrLines.unshift("## 🚀 Features", ""); + enhancementPrLines.push(""); } + + if (bugPrLines.length > 0) { + bugPrLines.unshift("## 🐛 Bug Fixes", ""); + bugPrLines.push(""); + } + + if (maintenencePrLines.length > 0) { + maintenencePrLines.unshift("## 🧰 Maintenance", ""); + maintenencePrLines.push(""); + } + + return [ + `## Changes since ${previousReleasedVersion}`, + "", + ...enhancementPrLines, + ...bugPrLines, + ...maintenencePrLines, + ].join("\n"); } -for (const pr of relaventPrs) { - await handleRelaventPr(pr); +async function cherrypickCommits(prs: ExtendedGithubPrData[]): Promise { + const rl = createInterface(process.stdin); + const cherrypickCommit = cherrypickCommitWith(rl); + + for (const pr of prs) { + await cherrypickCommit(pr.mergeCommit.oid); + } + + rl.close(); } -rl.close(); +async function pickRelaventPrs(prs: ExtendedGithubPrData[], isMasterBranch: boolean): Promise { + if (isMasterBranch) { + return prs; + } -const prBodyLines = [ - `## Changes since ${previousReleasedVersion}`, - "", - ...( - prLines.enhancement.length > 0 - ? [ - "## 🚀 Features", - "", - ...prLines.enhancement, - "", - ] - : [] - ), - ...( - prLines.bugfix.length > 0 - ? [ - "## 🐛 Bug Fixes", - "", - ...prLines.bugfix, - "", - ] - : [] - ), - ...( - prLines.maintenence.length > 0 - ? [ - "## 🧰 Maintenance", - "", - ...prLines.maintenence, - "", - ] - : [] - ), -]; -const prBody = prBodyLines.join("\n"); + const selectedPrs = await pickWhichCommitsToUse(prs); -await spawn("git", ["push", "--set-upstream", "origin", prBranch], { - stdio: "inherit", -}); + await cherrypickCommits(selectedPrs); -await spawn("gh", [ - "pr", - "create", - "--base", prBase, - "--title", `Release ${newVersion.format()}`, - "--label", "skip-changelog", - "--label", "release", - "--milestone", `${newVersion.major}.${newVersion.minor}.${newVersion.patch}`, - "--body-file", prBody, -], { - stdio: "inherit" -}); + return selectedPrs; +} + +async function createRelease(): Promise { + await checkCurrentWorkingDirectory(); + + const currentK8slensCoreVersion = await getCurrentVersionOfSubPackage("core"); + const prBase = await getCurrentBranch(); + const isMasterBranch = prBase === "master"; + const tags = await fetchAllGitTags(); + const previousReleasedVersion = findClosestVersionTagLessThanVersion(tags, currentK8slensCoreVersion); + + if (isMasterBranch) { + await bumpPackageVersions(); + } + + const prMilestone = formatSemverForMilestone(await getCurrentVersionOfSubPackage("core")); + const relaventPrs = await getRelaventPRs(prMilestone, previousReleasedVersion); + const selectedPrs = await pickRelaventPrs(relaventPrs, isMasterBranch); + const prBody = formatChangelog(previousReleasedVersion, selectedPrs); + + if (!isMasterBranch) { + await bumpPackageVersions(); + } + + const newK8slensCoreVersion = await getCurrentVersionOfSubPackage("core"); + + await createReleaseBranchAndCommit(prBase, newK8slensCoreVersion, prBody); +} + +await createRelease();