diff --git a/backend/__tests__/dal/admin-uids.spec.ts b/backend/__tests__/dal/admin-uids.spec.ts index aecf35355..daadbbcab 100644 --- a/backend/__tests__/dal/admin-uids.spec.ts +++ b/backend/__tests__/dal/admin-uids.spec.ts @@ -6,7 +6,7 @@ describe("AdminUidsDal", () => { it("should return true for existing admin user", async () => { //GIVEN const uid = new ObjectId().toHexString(); - AdminUidsDal.getCollection().insertOne({ + await AdminUidsDal.getCollection().insertOne({ _id: new ObjectId(), uid: uid, }); @@ -17,7 +17,7 @@ describe("AdminUidsDal", () => { it("should return false for non-existing admin user", async () => { //GIVEN - AdminUidsDal.getCollection().insertOne({ + await AdminUidsDal.getCollection().insertOne({ _id: new ObjectId(), uid: "admin", }); diff --git a/package.json b/package.json index 30a4b388d..e247ca245 100644 --- a/package.json +++ b/package.json @@ -29,11 +29,11 @@ "start-fe": "turbo run start --filter @monkeytype/frontend", "docker": "cd backend && docker compose up", "audit-fe": "cd frontend && npm run audit", - "release": "node ./bin/release.mjs", - "release-fe": "node ./bin/release.mjs --fe", - "release-be": "node ./bin/release.mjs --be", - "release-no-deploy": "node ./bin/release.mjs --no-deploy", - "release-dry": "node ./bin/release.mjs --dry", + "release": "monkeytype-release", + "release-fe": "monkeytype-release --fe", + "release-be": "monkeytype-release --be", + "release-no-deploy": "monkeytype-release --no-deploy", + "release-dry": "monkeytype-release --dry", "hotfix": "npm run build-fe && cd frontend && npm run deploy-live && cd .. && sh ./bin/purgeCfCache.sh", "pretty-check": "prettier --check .", "pretty-check-be": "prettier --check ./backend", @@ -54,6 +54,7 @@ "node": "20.16.0" }, "devDependencies": { + "@monkeytype/release": "workspace:*", "@commitlint/cli": "17.7.1", "@commitlint/config-conventional": "17.7.0", "conventional-changelog": "4.0.0", @@ -68,7 +69,6 @@ "lint-staged": "13.2.3", "only-allow": "1.2.1", "prettier": "2.5.1", - "readline-sync": "1.4.10", "turbo": "2.0.9", "typescript": "5.5.4", "wait-for-localhost-cli": "3.2.0" diff --git a/packages/eslint-config/index.js b/packages/eslint-config/index.js index f757881ea..46af1081d 100644 --- a/packages/eslint-config/index.js +++ b/packages/eslint-config/index.js @@ -31,6 +31,14 @@ module.exports = { "no-duplicate-imports": ["error"], "no-constant-condition": ["error"], "no-constant-binary-expression": "error", + "no-unused-vars": [ + "warn", + { + argsIgnorePattern: "^(_|e|event)", + caughtErrorsIgnorePattern: "^(_|e|error)", + varsIgnorePattern: "^_", + }, + ], "import/no-duplicates": "off", "import/no-unresolved": [ "error", diff --git a/packages/release/.eslintrc.cjs b/packages/release/.eslintrc.cjs new file mode 100644 index 000000000..922de4abe --- /dev/null +++ b/packages/release/.eslintrc.cjs @@ -0,0 +1,5 @@ +/** @type {import("eslint").Linter.Config} */ +module.exports = { + root: true, + extends: ["@monkeytype/eslint-config"], +}; diff --git a/bin/deployBackend.sh b/packages/release/bin/deployBackend.sh similarity index 100% rename from bin/deployBackend.sh rename to packages/release/bin/deployBackend.sh diff --git a/bin/purgeCfCache.sh b/packages/release/bin/purgeCfCache.sh similarity index 100% rename from bin/purgeCfCache.sh rename to packages/release/bin/purgeCfCache.sh diff --git a/packages/release/package.json b/packages/release/package.json new file mode 100644 index 000000000..ef127a4f9 --- /dev/null +++ b/packages/release/package.json @@ -0,0 +1,23 @@ +{ + "name": "@monkeytype/release", + "private": true, + "type": "module", + "scripts": { + "dev": "nodemon --watch src --exec 'node ./src/index.js --dry'", + "dev-changelog": "nodemon ./src/buildChangelog.js", + "lint": "eslint \"./**/*.js\"" + }, + "devDependencies": { + "@monkeytype/eslint-config": "workspace:*", + "eslint": "8.57.0", + "nodemon": "3.1.4" + }, + "bin": { + "monkeytype-release": "./src/index.js" + }, + "dependencies": { + "@octokit/rest": "20.1.1", + "dotenv": "16.4.5", + "readline-sync": "1.4.10" + } +} diff --git a/bin/buildChangelog.mjs b/packages/release/src/buildChangelog.js similarity index 98% rename from bin/buildChangelog.mjs rename to packages/release/src/buildChangelog.js index 6bc330c92..2f1f832f1 100644 --- a/bin/buildChangelog.mjs +++ b/packages/release/src/buildChangelog.js @@ -1,4 +1,3 @@ -import conventionalChangelog from "conventional-changelog"; import { exec } from "child_process"; // const stream = conventionalChangelog( @@ -41,7 +40,7 @@ async function getLog() { return new Promise((resolve, reject) => { exec( `git log --oneline $(git describe --tags --abbrev=0 @^)..@ --pretty="format:${lineDelimiter}%H${logDelimiter}%h${logDelimiter}%s${logDelimiter}%b"`, - (err, stdout, stderr) => { + (err, stdout, _stderr) => { if (err) { reject(err); } @@ -250,7 +249,7 @@ function convertStringToLog(logString) { //split message using regex based on fix(language): spelling mistakes in Nepali wordlist and quotes (sapradhan) (#4528) //scope is optional, username is optional, pr number is optional - const [__, type, scope, message, message2, message3] = title.split( + const [_, type, scope, message, message2, message3] = title.split( /^(\w+)(?:\(([^)]+)\))?:\s+(.+?)\s*(?:\(([^)]+)\))?(?:\s+\(([^)]+)\))?(?:\s+\(([^)]+)\))?$/ ); diff --git a/bin/release.mjs b/packages/release/src/index.js old mode 100644 new mode 100755 similarity index 80% rename from bin/release.mjs rename to packages/release/src/index.js index f285f97e0..d802a9c39 --- a/bin/release.mjs +++ b/packages/release/src/index.js @@ -1,12 +1,10 @@ import { execSync } from "child_process"; import { Octokit } from "@octokit/rest"; import dotenv from "dotenv"; -import { readFileSync } from "fs"; +import fs, { readFileSync } from "fs"; import readlineSync from "readline-sync"; -import path from "path"; -import fs from "fs"; +import path, { dirname } from "path"; import { fileURLToPath } from "url"; -import { dirname } from "path"; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); @@ -18,6 +16,9 @@ const isFrontend = args.includes("--fe"); const noDeploy = args.includes("--no-deploy"); const isBackend = args.includes("--be"); const isDryRun = args.includes("--dry"); +const noSyncCheck = args.includes("--no-sync-check"); + +const PROJECT_ROOT = path.resolve(__dirname, "../../../"); const runCommand = (command, force) => { if (isDryRun && !force) { @@ -35,19 +36,41 @@ const runCommand = (command, force) => { } }; +const runProjectRootCommand = (command, force) => { + if (isDryRun && !force) { + console.log(`[Dry Run] Command: ${command}`); + return "[Dry Run] Command executed."; + } else { + try { + const output = execSync(`cd ${PROJECT_ROOT} && ${command}`, { + stdio: "pipe", + }).toString(); + return output; + } catch (error) { + console.error(`Error executing command ${command}`); + console.error(error); + process.exit(1); + } + } +}; + const checkBranchSync = () => { console.log("Checking if local master branch is in sync with origin..."); - if (isDryRun) { + if (noSyncCheck) { + console.log("Skipping sync check."); + } else if (isDryRun) { console.log("[Dry Run] Checking sync..."); } else { try { // Fetch the latest changes from the remote repository - runCommand("git fetch origin"); + runProjectRootCommand("git fetch origin"); // Get the commit hashes of the local and remote master branches - const localMaster = runCommand("git rev-parse master").trim(); - const remoteMaster = runCommand("git rev-parse origin/master").trim(); + const localMaster = runProjectRootCommand("git rev-parse master").trim(); + const remoteMaster = runProjectRootCommand( + "git rev-parse origin/master" + ).trim(); if (localMaster !== remoteMaster) { console.error( @@ -65,8 +88,12 @@ const checkBranchSync = () => { const getCurrentVersion = () => { console.log("Getting current version..."); - const packageJson = JSON.parse(readFileSync("./package.json", "utf-8")); - return packageJson.version; + + const rootPackageJson = JSON.parse( + readFileSync(`${PROJECT_ROOT}/package.json`, "utf-8") + ); + + return rootPackageJson.version; }; const incrementVersion = (currentVersion) => { @@ -134,7 +161,7 @@ const buildProject = () => { filter = "--filter @monkeytype/backend"; } - runCommand("npx turbo lint test validate-json build " + filter); + runProjectRootCommand("npx turbo lint test validate-json build " + filter); }; const deployBackend = () => { @@ -144,7 +171,9 @@ const deployBackend = () => { const deployFrontend = () => { console.log("Deploying frontend..."); - runCommand("cd frontend && npx firebase deploy -P live --only hosting"); + runProjectRootCommand( + "cd frontend && npx firebase deploy -P live --only hosting" + ); }; const purgeCache = () => { @@ -155,7 +184,9 @@ const purgeCache = () => { const generateChangelog = async () => { console.log("Generating changelog..."); - const changelog = runCommand("node bin/buildChangelog.mjs", true); + const p = path.resolve(__dirname, "./buildChangelog.js"); + + const changelog = runCommand(`node ${p}`, true); return changelog; }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cea3e4b34..84e7440d9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,6 +14,9 @@ importers: '@commitlint/config-conventional': specifier: 17.7.0 version: 17.7.0 + '@monkeytype/release': + specifier: workspace:* + version: link:packages/release conventional-changelog: specifier: 4.0.0 version: 4.0.0 @@ -50,9 +53,6 @@ importers: prettier: specifier: 2.5.1 version: 2.5.1 - readline-sync: - specifier: 1.4.10 - version: 1.4.10 turbo: specifier: 2.0.9 version: 2.0.9 @@ -528,6 +528,28 @@ importers: specifier: 9.1.0 version: 9.1.0(eslint@8.57.0) + packages/release: + dependencies: + '@octokit/rest': + specifier: 20.1.1 + version: 20.1.1 + dotenv: + specifier: 16.4.5 + version: 16.4.5 + readline-sync: + specifier: 1.4.10 + version: 1.4.10 + devDependencies: + '@monkeytype/eslint-config': + specifier: workspace:* + version: link:../eslint-config + eslint: + specifier: 8.57.0 + version: 8.57.0 + nodemon: + specifier: 3.1.4 + version: 3.1.4 + packages/shared-types: dependencies: '@monkeytype/contracts': @@ -2196,6 +2218,58 @@ packages: resolution: {integrity: sha512-pwK+BfEBZJbKdNYpHHRTNBwBoqrN/iIMO0AiGvYsp3Hoaq0WbgGSWQR6SCldZovoDpY3yje5lkFUe6gsDgJ2vg==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + '@octokit/auth-token@4.0.0': + resolution: {integrity: sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==} + engines: {node: '>= 18'} + + '@octokit/core@5.2.0': + resolution: {integrity: sha512-1LFfa/qnMQvEOAdzlQymH0ulepxbxnCYAKJZfMci/5XJyIHWgEYnDmgnKakbTh7CH2tFQ5O60oYDvns4i9RAIg==} + engines: {node: '>= 18'} + + '@octokit/endpoint@9.0.5': + resolution: {integrity: sha512-ekqR4/+PCLkEBF6qgj8WqJfvDq65RH85OAgrtnVp1mSxaXF03u2xW/hUdweGS5654IlC0wkNYC18Z50tSYTAFw==} + engines: {node: '>= 18'} + + '@octokit/graphql@7.1.0': + resolution: {integrity: sha512-r+oZUH7aMFui1ypZnAvZmn0KSqAUgE1/tUXIWaqUCa1758ts/Jio84GZuzsvUkme98kv0WFY8//n0J1Z+vsIsQ==} + engines: {node: '>= 18'} + + '@octokit/openapi-types@22.2.0': + resolution: {integrity: sha512-QBhVjcUa9W7Wwhm6DBFu6ZZ+1/t/oYxqc2tp81Pi41YNuJinbFRx8B133qVOrAaBbF7D/m0Et6f9/pZt9Rc+tg==} + + '@octokit/plugin-paginate-rest@11.3.1': + resolution: {integrity: sha512-ryqobs26cLtM1kQxqeZui4v8FeznirUsksiA+RYemMPJ7Micju0WSkv50dBksTuZks9O5cg4wp+t8fZ/cLY56g==} + engines: {node: '>= 18'} + peerDependencies: + '@octokit/core': '5' + + '@octokit/plugin-request-log@4.0.1': + resolution: {integrity: sha512-GihNqNpGHorUrO7Qa9JbAl0dbLnqJVrV8OXe2Zm5/Y4wFkZQDfTreBzVmiRfJVfE4mClXdihHnbpyyO9FSX4HA==} + engines: {node: '>= 18'} + peerDependencies: + '@octokit/core': '5' + + '@octokit/plugin-rest-endpoint-methods@13.2.2': + resolution: {integrity: sha512-EI7kXWidkt3Xlok5uN43suK99VWqc8OaIMktY9d9+RNKl69juoTyxmLoWPIZgJYzi41qj/9zU7G/ljnNOJ5AFA==} + engines: {node: '>= 18'} + peerDependencies: + '@octokit/core': ^5 + + '@octokit/request-error@5.1.0': + resolution: {integrity: sha512-GETXfE05J0+7H2STzekpKObFe765O5dlAKUTLNGeH+x47z7JjXHfsHKo5z21D/o/IOZTUEI6nyWyR+bZVP/n5Q==} + engines: {node: '>= 18'} + + '@octokit/request@8.4.0': + resolution: {integrity: sha512-9Bb014e+m2TgBeEJGEbdplMVWwPmL1FPtggHQRkV+WVsMggPtEkLKPlcVYm/o8xKLkpJ7B+6N8WfQMtDLX2Dpw==} + engines: {node: '>= 18'} + + '@octokit/rest@20.1.1': + resolution: {integrity: sha512-MB4AYDsM5jhIHro/dq4ix1iWTLGToIGk6cWF5L6vanFaMble5jTX/UBQyiv05HsWnwUtY8JrfHy2LWfKwihqMw==} + engines: {node: '>= 18'} + + '@octokit/types@13.5.0': + resolution: {integrity: sha512-HdqWTf5Z3qwDVlzCrP8UJquMwunpDiMPt5er+QjGzL4hqr/vBVY/MauQgS1xWxCDT1oMx1EULyqxncdCY/NVSQ==} + '@one-ini/wasm@0.1.1': resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==} @@ -3172,6 +3246,9 @@ packages: resolution: {integrity: sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww==} engines: {node: '>= 10.0.0'} + before-after-hook@2.2.3: + resolution: {integrity: sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==} + bignumber.js@9.1.2: resolution: {integrity: sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==} @@ -4009,6 +4086,9 @@ packages: engines: {node: ^10.13 || ^12 || >=14} hasBin: true + deprecation@2.3.1: + resolution: {integrity: sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==} + destroy@1.2.0: resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} @@ -8971,6 +9051,9 @@ packages: resolution: {integrity: sha512-HXSMyIcf2XTvwZ6ZZQLfxfViRm/yTGoRgDeTbojtq6rezeyKB0sTBcKH2fhddnteAHRcHiKgr/ACpbgjGOC6RQ==} engines: {node: '>=12.18.2'} + universal-user-agent@6.0.1: + resolution: {integrity: sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==} + universalify@2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} @@ -11525,6 +11608,69 @@ snapshots: '@npmcli/name-from-folder@2.0.0': {} + '@octokit/auth-token@4.0.0': {} + + '@octokit/core@5.2.0': + dependencies: + '@octokit/auth-token': 4.0.0 + '@octokit/graphql': 7.1.0 + '@octokit/request': 8.4.0 + '@octokit/request-error': 5.1.0 + '@octokit/types': 13.5.0 + before-after-hook: 2.2.3 + universal-user-agent: 6.0.1 + + '@octokit/endpoint@9.0.5': + dependencies: + '@octokit/types': 13.5.0 + universal-user-agent: 6.0.1 + + '@octokit/graphql@7.1.0': + dependencies: + '@octokit/request': 8.4.0 + '@octokit/types': 13.5.0 + universal-user-agent: 6.0.1 + + '@octokit/openapi-types@22.2.0': {} + + '@octokit/plugin-paginate-rest@11.3.1(@octokit/core@5.2.0)': + dependencies: + '@octokit/core': 5.2.0 + '@octokit/types': 13.5.0 + + '@octokit/plugin-request-log@4.0.1(@octokit/core@5.2.0)': + dependencies: + '@octokit/core': 5.2.0 + + '@octokit/plugin-rest-endpoint-methods@13.2.2(@octokit/core@5.2.0)': + dependencies: + '@octokit/core': 5.2.0 + '@octokit/types': 13.5.0 + + '@octokit/request-error@5.1.0': + dependencies: + '@octokit/types': 13.5.0 + deprecation: 2.3.1 + once: 1.4.0 + + '@octokit/request@8.4.0': + dependencies: + '@octokit/endpoint': 9.0.5 + '@octokit/request-error': 5.1.0 + '@octokit/types': 13.5.0 + universal-user-agent: 6.0.1 + + '@octokit/rest@20.1.1': + dependencies: + '@octokit/core': 5.2.0 + '@octokit/plugin-paginate-rest': 11.3.1(@octokit/core@5.2.0) + '@octokit/plugin-request-log': 4.0.1(@octokit/core@5.2.0) + '@octokit/plugin-rest-endpoint-methods': 13.2.2(@octokit/core@5.2.0) + + '@octokit/types@13.5.0': + dependencies: + '@octokit/openapi-types': 22.2.0 + '@one-ini/wasm@0.1.1': {} '@opentelemetry/api@1.8.0': {} @@ -12581,6 +12727,8 @@ snapshots: - encoding - supports-color + before-after-hook@2.2.3: {} + bignumber.js@9.1.2: {} binary-extensions@1.13.1: {} @@ -13495,6 +13643,8 @@ snapshots: transitivePeerDependencies: - supports-color + deprecation@2.3.1: {} + destroy@1.2.0: {} detect-file@1.0.0: {} @@ -19600,6 +19750,8 @@ snapshots: transitivePeerDependencies: - supports-color + universal-user-agent@6.0.1: {} + universalify@2.0.1: {} unpipe@1.0.0: {}