diff --git a/deadlock-plugins/deadlock-extension/src/config.prod.ts b/deadlock-plugins/deadlock-extension/src/config.prod.ts index f1e1b88beec464f9c97464c99f823ec3260eaf5c..285c2bcaf3e43f9b6e19278b8359c8708b32a745 100644 --- a/deadlock-plugins/deadlock-extension/src/config.prod.ts +++ b/deadlock-plugins/deadlock-extension/src/config.prod.ts @@ -4,5 +4,6 @@ export const KEYCLOAK_TOKEN_CREATE_URL = 'https://auth.deadlock.io/auth/realms/D export const KEYCLOAK_USER_INFO_URL = 'https://auth.deadlock.io/auth/realms/Deadlock/protocol/openid-connect/userinfo'; export const REJECT_UNAUTHORIZED = true; export const ENABLE_HTTP_SERVER = false; -export const HTTP_SERVER_PORT = 8751; -export const HTTP_SERVER_URL = `http://localhost:${HTTP_SERVER_PORT}`; +export const ENABLE_AUTOMATIC_SAVE = true; +export const RECORDER_HTTP_SERVER_PORT = 8751; +export const RECORDER_HTTP_SERVER_URL = `http://localhost:${RECORDER_HTTP_SERVER_PORT}`; diff --git a/deadlock-plugins/deadlock-extension/src/config.ts b/deadlock-plugins/deadlock-extension/src/config.ts index 97cd39109dfcb0c9557fb3d070760ae1195b4fa6..dc9064f362bee81e9bf295ccad5adda4aa4077cf 100644 --- a/deadlock-plugins/deadlock-extension/src/config.ts +++ b/deadlock-plugins/deadlock-extension/src/config.ts @@ -6,5 +6,6 @@ export const KEYCLOAK_USER_INFO_URL = 'https://auth.dev.deadlock.io/auth/realms/Deadlock/protocol/openid-connect/userinfo'; export const REJECT_UNAUTHORIZED = false; export const ENABLE_HTTP_SERVER = false; +export const ENABLE_AUTOMATIC_SAVE = true; export const HTTP_SERVER_PORT = 8751; export const HTTP_SERVER_URL = `http://localhost:${HTTP_SERVER_PORT}`; diff --git a/deadlock-plugins/deadlock-extension/src/core/gitMission.ts b/deadlock-plugins/deadlock-extension/src/core/gitMission.ts index 673945eb5434300064b8be80f7277a6157b4eaa7..dbd69e6ec8f24bcfbd93e06d1b996d99554d9312 100644 --- a/deadlock-plugins/deadlock-extension/src/core/gitMission.ts +++ b/deadlock-plugins/deadlock-extension/src/core/gitMission.ts @@ -7,7 +7,12 @@ const util = require('util'); const exec = util.promisify(require('child_process').exec); const DEFAULT_REMOTE = 'origin'; -const DEFAULT_BRANCH = 'master'; + +export enum Branch { + MASTER = 'master', + DEFAULT = MASTER, + LIVE = 'live', +} export default class GitMission { private git: SimpleGit; @@ -55,6 +60,7 @@ export default class GitMission { const remotePath = this.getRemotePath(); await this.git.init(); + await this.git.addRemote(DEFAULT_REMOTE, remotePath); await this.git.addConfig('user.email', this.userConfig.getCurrentUserDetails().email, false, 'system'); await this.git.addConfig( @@ -88,20 +94,47 @@ export default class GitMission { return this.git.fetch(DEFAULT_REMOTE); } - pull() { - return this.git.pull(DEFAULT_REMOTE, DEFAULT_BRANCH, { '--rebase': 'true' }); + pull(branch?: string) { + return this.git.pull(DEFAULT_REMOTE, branch ?? Branch.DEFAULT, { '--rebase': 'true' }); } addAll() { return this.git.add('.'); } - commit(message) { - return this.git.commit(message); + commit(message: string, options?: string[]) { + return this.git.commit(message, options ?? []); } push() { - return this.git.push(DEFAULT_REMOTE, DEFAULT_BRANCH); + return this.git.push(DEFAULT_REMOTE); + } + + createLocalBranch(branch: string) { + return this.git.checkout(['-b', branch]); + } + + createRemoteBranch(branch: string) { + return this.git.push(['-u', DEFAULT_REMOTE, branch]); + } + + setUpstream(branch: string) { + return this.git.branch(['-u', DEFAULT_REMOTE, branch]); + } + + createBranch(branch: string) { + const createBranchLocally = this.createLocalBranch(branch); + const createRemoteBranch = this.createRemoteBranch(branch); + + return Promise.all([createBranchLocally, createRemoteBranch]); + } + + checkout(branch: string) { + return this.git.checkout(branch); + } + + merge(options?: string[]) { + return this.git.merge(options ?? []); } async isRemoteRepoExist() { diff --git a/deadlock-plugins/deadlock-extension/src/recorder/command-recorder.ts b/deadlock-plugins/deadlock-extension/src/recorder/command-recorder.ts index 99dbc5213f5a45d31760fca026d719aba6066c84..85bdbf9b52fb879aeff2b8a7071ef755231920e5 100644 --- a/deadlock-plugins/deadlock-extension/src/recorder/command-recorder.ts +++ b/deadlock-plugins/deadlock-extension/src/recorder/command-recorder.ts @@ -1,5 +1,5 @@ import GitMission from '../core/gitMission'; -import { error, commitAndPushCode, CommitFrom, log } from './utils'; +import { error, commitAndPushCode, CommitFrom, log, updateRemote } from './utils'; const async = require('async'); const fs = require('fs'); @@ -33,7 +33,7 @@ export default class CommandRecorder { if (!this.commandsInProgress.has(pid)) { this.commandsInProgress.set(pid, new Command(pid, command)); try { - this.queue.push(async () => await commitAndPushCode(this.gitMission, CommitFrom.Run)); + this.queue.push(async () => await updateRemote(this.gitMission, CommitFrom.Run)); } catch (e) { console.error('Cannot send user code to git'); console.error(e); diff --git a/deadlock-plugins/deadlock-extension/src/recorder/index.ts b/deadlock-plugins/deadlock-extension/src/recorder/index.ts index 7ed0b6d8e3c71f22f3d0e5d1db9100b74b1d5a8e..6e10a2b8208a669439ce221f9273b1a79dcf131a 100644 --- a/deadlock-plugins/deadlock-extension/src/recorder/index.ts +++ b/deadlock-plugins/deadlock-extension/src/recorder/index.ts @@ -1,3 +1,5 @@ +import { Branch } from './../core/gitMission'; +import { ENABLE_AUTOMATIC_SAVE } from './../config'; import CommandRecorder from './command-recorder'; import GitMission from '../core/gitMission'; import UserConfigNode from './userConfigNode'; @@ -6,6 +8,8 @@ import { copyProjectSources, clearFilesExceptGit, log, error, renameTempToUserGi import UserConfig from '../core/userConfig'; import HttpServer from './services/http-server'; import { ENABLE_HTTP_SERVER } from '../config'; +import FileWatcher from './services/file-watcher'; +import AutomaticSave from './services/automatic-save'; export default class Recorder { async setupProject(userConfig: UserConfig, gitMission?: GitMission) { log('Setup user project..'); @@ -29,6 +33,7 @@ export default class Recorder { async setupFromRemoteRepo(gitMission: GitMission) { log('Check if remote repo exist'); const isRemoteRepoExist = await gitMission.isRemoteRepoExist(); + if (isRemoteRepoExist) { // rm all except git directory pull remote code and setup log('Cleaning files to pull repo'); @@ -36,7 +41,14 @@ export default class Recorder { await clearFilesExceptGit(PROJECT_SRC_PATH); log('Pulling user repo'); - await gitMission.pull(); + + await gitMission.fetch(); + await gitMission.checkout(Branch.MASTER); + await gitMission.checkout(Branch.LIVE); + } else { + await gitMission.commit('initial commit', ['--allow-empty']); + await gitMission.createRemoteBranch(Branch.DEFAULT); + await gitMission.createBranch(Branch.LIVE); } } @@ -53,6 +65,8 @@ export default class Recorder { if (ENABLE_HTTP_SERVER) new HttpServer(gitMission); await this.setupFromRemoteRepo(gitMission); + + if (ENABLE_AUTOMATIC_SAVE) new AutomaticSave(PROJECT_DEADLOCK_DESKTOP_PATH, gitMission); } catch (e) { error('Cannot setup user repo.'); error(e); diff --git a/deadlock-plugins/deadlock-extension/src/recorder/package-lock.json b/deadlock-plugins/deadlock-extension/src/recorder/package-lock.json index 2201c649b518ba4720a877ab69f8b2feb5a59d57..851d67cb716f929309c6cc858c7b8b1f5dc3c274 100644 --- a/deadlock-plugins/deadlock-extension/src/recorder/package-lock.json +++ b/deadlock-plugins/deadlock-extension/src/recorder/package-lock.json @@ -9,6 +9,7 @@ "version": "1.0.0", "license": "MIT", "dependencies": { + "chokidar": "^3.5.3", "express": "^4.18.0" }, "devDependencies": { @@ -103,11 +104,31 @@ "node": ">= 0.6" } }, + "node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "engines": { + "node": ">=8" + } + }, "node_modules/body-parser": { "version": "1.20.0", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", @@ -131,6 +152,17 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -151,6 +183,32 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -275,6 +333,17 @@ "node": ">= 0.10.0" } }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/finalhandler": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", @@ -308,6 +377,19 @@ "node": ">= 0.6" } }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -326,6 +408,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -387,6 +480,44 @@ "node": ">= 0.10" } }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -451,6 +582,14 @@ "node": ">= 0.6" } }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/object-inspect": { "version": "1.12.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", @@ -483,6 +622,17 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -531,6 +681,17 @@ "node": ">= 0.8" } }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -623,6 +784,17 @@ "node": ">= 0.8" } }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", @@ -754,11 +926,25 @@ "negotiator": "0.6.3" } }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" + }, "body-parser": { "version": "1.20.0", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", @@ -778,6 +964,14 @@ "unpipe": "1.0.0" } }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "requires": { + "fill-range": "^7.0.1" + } + }, "bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -792,6 +986,21 @@ "get-intrinsic": "^1.0.2" } }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, "content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -891,6 +1100,14 @@ "vary": "~1.1.2" } }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, "finalhandler": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", @@ -915,6 +1132,12 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "optional": true + }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -930,6 +1153,14 @@ "has-symbols": "^1.0.1" } }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "requires": { + "is-glob": "^4.0.1" + } + }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -973,6 +1204,32 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -1016,6 +1273,11 @@ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + }, "object-inspect": { "version": "1.12.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", @@ -1039,6 +1301,11 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" + }, "proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -1072,6 +1339,14 @@ "unpipe": "1.0.0" } }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "requires": { + "picomatch": "^2.2.1" + } + }, "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -1140,6 +1415,14 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "requires": { + "is-number": "^7.0.0" + } + }, "toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", diff --git a/deadlock-plugins/deadlock-extension/src/recorder/package.json b/deadlock-plugins/deadlock-extension/src/recorder/package.json index 87dede28b70e8c1b91b241a2f24b8b6823b8303e..bb63dc16d2dd366d4d5ac941c1b8c0a1c20df485 100644 --- a/deadlock-plugins/deadlock-extension/src/recorder/package.json +++ b/deadlock-plugins/deadlock-extension/src/recorder/package.json @@ -9,6 +9,7 @@ "author": "", "license": "MIT", "dependencies": { + "chokidar": "^3.5.3", "express": "^4.18.0" }, "devDependencies": { diff --git a/deadlock-plugins/deadlock-extension/src/recorder/preStop.ts b/deadlock-plugins/deadlock-extension/src/recorder/preStop.ts index 081c4bded0b0982b05926d77e896a9ffb2b56727..d4d84eccb75c77b27f9ecf0924b7c123958dcf78 100644 --- a/deadlock-plugins/deadlock-extension/src/recorder/preStop.ts +++ b/deadlock-plugins/deadlock-extension/src/recorder/preStop.ts @@ -2,7 +2,7 @@ import UserConfigNode from './userConfigNode'; import GitMission from '../core/gitMission'; import { PROJECT_SRC_PATH, PROJECT_DEADLOCK_DESKTOP_PATH } from '../core/config'; -import { log, error, commitAndPushCode, CommitFrom } from './utils'; +import { log, error, updateRemote, CommitFrom } from './utils'; const util = require('util'); const exec = util.promisify(require('child_process').exec); @@ -39,7 +39,7 @@ async function containsDiff() { log('Save user code..'); const gitMission = await new GitMission(userConfig).init(); if (await containsDiff()) { - await commitAndPushCode(gitMission, CommitFrom.Auto); + await updateRemote(gitMission, CommitFrom.Auto); } } } catch (e) { diff --git a/deadlock-plugins/deadlock-extension/src/recorder/services/automatic-save.ts b/deadlock-plugins/deadlock-extension/src/recorder/services/automatic-save.ts new file mode 100644 index 0000000000000000000000000000000000000000..9be2e04fc9e1777b40d097e6bfe44c185f3e053d --- /dev/null +++ b/deadlock-plugins/deadlock-extension/src/recorder/services/automatic-save.ts @@ -0,0 +1,19 @@ +import { CommitFrom, getIgnorePatternFromIgnoreFile } from './../utils'; +import { FSWatcher } from 'chokidar'; +import FileWatcher from './file-watcher'; +import * as fs from 'fs'; +import { updateRemote } from '../utils'; +import GitMission from '../../core/gitMission'; + +export default class AutomaticSave { + constructor(private folderToWatch: string, private gitMission: GitMission) { + this.setupAutomaticSave(); + } + + async setupAutomaticSave() { + const ignoreFilePatterns = await getIgnorePatternFromIgnoreFile('/deadlock/.gitignore'); + new FileWatcher(this.folderToWatch, ['**/*'], ignoreFilePatterns, () => { + updateRemote(this.gitMission, CommitFrom.Auto); + }); + } +} diff --git a/deadlock-plugins/deadlock-extension/src/recorder/services/file-watcher.ts b/deadlock-plugins/deadlock-extension/src/recorder/services/file-watcher.ts new file mode 100644 index 0000000000000000000000000000000000000000..3a786802615d939f6f5e1b91c6f579d2aa425773 --- /dev/null +++ b/deadlock-plugins/deadlock-extension/src/recorder/services/file-watcher.ts @@ -0,0 +1,21 @@ +const chokidar = require('chokidar'); + +export default class FileWatcher { + constructor( + private folderToWatch: string, + private watchFilePatterns: string[], + private ignoreFilePatterns: string[], + private onFilesChangeAction: () => void, + ) { + this.setupWatcher(); + } + + setupWatcher() { + const watcher = chokidar.watch(this.watchFilePatterns, { + ignoreInitial: true, + cwd: this.folderToWatch, + ignored: this.ignoreFilePatterns, + }); + watcher.on('all', this.onFilesChangeAction); + } +} diff --git a/deadlock-plugins/deadlock-extension/src/recorder/services/http-server.ts b/deadlock-plugins/deadlock-extension/src/recorder/services/http-server.ts index 0c1b1d56c5de697a91dcb12884ad0ed095dedfc3..6c3d474cecb8c51c26176c519fe1b8b6adf52768 100644 --- a/deadlock-plugins/deadlock-extension/src/recorder/services/http-server.ts +++ b/deadlock-plugins/deadlock-extension/src/recorder/services/http-server.ts @@ -1,6 +1,6 @@ import GitMission from '../../core/gitMission'; import { Express } from 'express'; -import { commitAndPushCode, CommitFrom, log } from '../utils'; +import { updateRemote, CommitFrom, log } from '../utils'; import { HTTP_SERVER_PORT } from '../../config'; const express = require('express'); @@ -18,7 +18,7 @@ export default class HttpServer { setupSaveCodeEndpoints() { this.app.post('/save', async (req, res) => { try { - await commitAndPushCode(this.gitMission, CommitFrom.HttpServer); + await updateRemote(this.gitMission, CommitFrom.HttpServer); res.status(200).json({ message: 'Commit & push done.', }); diff --git a/deadlock-plugins/deadlock-extension/src/recorder/utils.ts b/deadlock-plugins/deadlock-extension/src/recorder/utils.ts index 9e58a09f559d397b6ab21f3753c15dc8576beb78..dcda0382dfa635af4dba02c4350fc82e5fb1c55b 100644 --- a/deadlock-plugins/deadlock-extension/src/recorder/utils.ts +++ b/deadlock-plugins/deadlock-extension/src/recorder/utils.ts @@ -1,3 +1,4 @@ +import { Branch } from './../core/gitMission'; import GitMission from '../core/gitMission'; import { PROJECT_SRC_PATH, PROJECT_DEADLOCK_DESKTOP_PATH } from '../core/config'; import { format } from 'date-fns'; @@ -113,9 +114,14 @@ export enum CommitFrom { HttpServer = 'HttpServer', } -export async function commitAndPushCode(gitMission: GitMission, from: CommitFrom) { +export async function updateRemote(gitMission: GitMission, from: CommitFrom) { + if (from === CommitFrom.Auto) commitAndPushCode(gitMission); + if (from === CommitFrom.Run) mergeMaster(gitMission); +} + +async function commitAndPushCode(gitMission: GitMission) { try { - log('Commit & push'); + log('Doing Commit & push'); await clearFilesExceptGit(PROJECT_SRC_PATH); copyGitUserFiles(PROJECT_DEADLOCK_DESKTOP_PATH, PROJECT_SRC_PATH, gitMission.author); @@ -127,6 +133,7 @@ export async function commitAndPushCode(gitMission: GitMission, from: CommitFrom ); const currentDate = format(new Date(), "HH'H'mm'_'dd/LL/y"); + await gitMission.checkout(Branch.LIVE); await gitMission.addAll(); await gitMission.commit(currentDate); await gitMission.push(); @@ -137,3 +144,34 @@ export async function commitAndPushCode(gitMission: GitMission, from: CommitFrom throw new Error(e); } } + +async function mergeMaster(gitMission: GitMission) { + try { + log('Merging live to master'); + + const currentDate = format(new Date(), "HH'H'mm'_'dd/LL/y"); + + await gitMission.checkout(Branch.DEFAULT); + await gitMission.merge(['--squash', '-X', 'theirs', Branch.LIVE]); + await gitMission.commit(currentDate); + await gitMission.push(); + log('Merge to master done'); + await gitMission.checkout(Branch.LIVE); + } catch (e) { + error(`[${e.status}] cannot commitAndPush code: ${e.stderr}`); + error(e.message); + throw new Error(e); + } +} + +export function getIgnorePatternFromIgnoreFile(ignoreFile: string): Promise<string[]> { + return fs.promises + .readFile(ignoreFile, { encoding: 'utf-8' }) + .then((fileContent: string) => { + return fileContent.split(/\s*\r?\n\s*/); + }) + .then((lines: string[]) => { + return lines.filter((line) => line.trimLeft().startsWith('#') || !!line.trim()).map((line) => `**/${line}`); + }) + .then((filesPatterns: string[]) => [...filesPatterns, '.git']); +}