From 1ed49c3340e0f06890b8ce77622703ca2558cec3 Mon Sep 17 00:00:00 2001 From: Alicia Sykes Date: Mon, 4 Mar 2024 19:34:35 +0000 Subject: [PATCH 1/4] =?UTF-8?q?=F0=9F=9A=91=20Hotfix:=20Use=20chokidar=20t?= =?UTF-8?q?o=20watch=20only=20for=20conf.yml=20changes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 4 +++- yarn.lock | 19 +++++++++++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 8e4f144a..bad17a50 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,8 @@ "lint": "vue-cli-service lint", "pm2-start": "npx pm2 start server.js", "build-watch": "vue-cli-service build --watch --mode production", - "build-and-start": "NODE_OPTIONS=--openssl-legacy-provider npm-run-all --parallel build-watch start", + "watch-config": "chokidar \"public/conf.yml\" --command \"npm run build\"", + "build-and-start": "NODE_OPTIONS=--openssl-legacy-provider npm-run-all --parallel watch-config start", "validate-config": "node services/config-validator", "health-check": "node services/healthcheck", "dependency-audit": "npx improved-yarn-audit --ignore-dev-deps" @@ -23,6 +24,7 @@ "@sentry/vue": "^7.102.1", "ajv": "^8.10.0", "axios": "^1.6.0", + "chokidar-cli": "^3.0.0", "connect-history-api-fallback": "^1.6.0", "crypto-js": "^4.2.0", "express": "^4.17.2", diff --git a/yarn.lock b/yarn.lock index d888702a..f53e4e4a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2824,7 +2824,17 @@ check-types@^8.0.3: resolved "https://registry.yarnpkg.com/check-types/-/check-types-8.0.3.tgz#3356cca19c889544f2d7a95ed49ce508a0ecf552" integrity sha512-YpeKZngUmG65rLudJ4taU7VLkOCTMhNl/u4ctNC56LQS/zJTyNH0Lrtwm1tfTsbLlwvlfsA2d1c8vCf/Kh2KwQ== -"chokidar@>=3.0.0 <4.0.0", chokidar@^3.4.1: +chokidar-cli@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/chokidar-cli/-/chokidar-cli-3.0.0.tgz#29283666063b9e167559d30f247ff8fc48794eb7" + integrity sha512-xVW+Qeh7z15uZRxHOkP93Ux8A0xbPzwK4GaqD8dQOYc34TlkqUhVSS59fK36DOp5WdJlrRzlYSy02Ht99FjZqQ== + dependencies: + chokidar "^3.5.2" + lodash.debounce "^4.0.8" + lodash.throttle "^4.1.1" + yargs "^13.3.0" + +"chokidar@>=3.0.0 <4.0.0", chokidar@^3.4.1, chokidar@^3.5.2: version "3.6.0" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== @@ -6134,6 +6144,11 @@ lodash.templatesettings@^4.0.0: dependencies: lodash._reinterpolate "^3.0.0" +lodash.throttle@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" + integrity sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ== + lodash.transform@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.transform/-/lodash.transform-4.6.0.tgz#12306422f63324aed8483d3f38332b5f670547a0" @@ -10014,7 +10029,7 @@ yargs-parser@^20.2.2: resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== -yargs@^13.3.2: +yargs@^13.3.0, yargs@^13.3.2: version "13.3.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== From a6a2ee232a59b3d3fd3db21339fece3f83ea6b54 Mon Sep 17 00:00:00 2001 From: Alicia Sykes Date: Mon, 4 Mar 2024 20:07:34 +0000 Subject: [PATCH 2/4] =?UTF-8?q?=F0=9F=A7=B1=20Writes=20script=20to=20watch?= =?UTF-8?q?=20for=20changes=20and=20trigger=20re-build?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 3 +-- services/watch-for-changes.js | 20 ++++++++++++++++++++ yarn.lock | 19 ++----------------- 3 files changed, 23 insertions(+), 19 deletions(-) create mode 100644 services/watch-for-changes.js diff --git a/package.json b/package.json index bad17a50..423a68ab 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "lint": "vue-cli-service lint", "pm2-start": "npx pm2 start server.js", "build-watch": "vue-cli-service build --watch --mode production", - "watch-config": "chokidar \"public/conf.yml\" --command \"npm run build\"", + "watch-config": "node services/watch-for-changes", "build-and-start": "NODE_OPTIONS=--openssl-legacy-provider npm-run-all --parallel watch-config start", "validate-config": "node services/config-validator", "health-check": "node services/healthcheck", @@ -24,7 +24,6 @@ "@sentry/vue": "^7.102.1", "ajv": "^8.10.0", "axios": "^1.6.0", - "chokidar-cli": "^3.0.0", "connect-history-api-fallback": "^1.6.0", "crypto-js": "^4.2.0", "express": "^4.17.2", diff --git a/services/watch-for-changes.js b/services/watch-for-changes.js new file mode 100644 index 00000000..c7faec2b --- /dev/null +++ b/services/watch-for-changes.js @@ -0,0 +1,20 @@ +const fs = require('fs'); +const { exec } = require('child_process'); + +const configFile = './public/conf.yml'; + +console.log(`Watching for file changes on ${configFile}`); + +fs.watch(configFile, (eventType, filename) => { + if (filename && eventType === 'change') { + console.log(`${filename} file Changed, running build...`); + exec('yarn build', (error, stdout, stderr) => { + if (error) { + console.error(`exec error: ${error}`); + return; + } + console.log(`stdout: ${stdout}`); + console.error(`stderr: ${stderr}`); + }); + } +}); diff --git a/yarn.lock b/yarn.lock index f53e4e4a..d888702a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2824,17 +2824,7 @@ check-types@^8.0.3: resolved "https://registry.yarnpkg.com/check-types/-/check-types-8.0.3.tgz#3356cca19c889544f2d7a95ed49ce508a0ecf552" integrity sha512-YpeKZngUmG65rLudJ4taU7VLkOCTMhNl/u4ctNC56LQS/zJTyNH0Lrtwm1tfTsbLlwvlfsA2d1c8vCf/Kh2KwQ== -chokidar-cli@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/chokidar-cli/-/chokidar-cli-3.0.0.tgz#29283666063b9e167559d30f247ff8fc48794eb7" - integrity sha512-xVW+Qeh7z15uZRxHOkP93Ux8A0xbPzwK4GaqD8dQOYc34TlkqUhVSS59fK36DOp5WdJlrRzlYSy02Ht99FjZqQ== - dependencies: - chokidar "^3.5.2" - lodash.debounce "^4.0.8" - lodash.throttle "^4.1.1" - yargs "^13.3.0" - -"chokidar@>=3.0.0 <4.0.0", chokidar@^3.4.1, chokidar@^3.5.2: +"chokidar@>=3.0.0 <4.0.0", chokidar@^3.4.1: version "3.6.0" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== @@ -6144,11 +6134,6 @@ lodash.templatesettings@^4.0.0: dependencies: lodash._reinterpolate "^3.0.0" -lodash.throttle@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" - integrity sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ== - lodash.transform@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.transform/-/lodash.transform-4.6.0.tgz#12306422f63324aed8483d3f38332b5f670547a0" @@ -10029,7 +10014,7 @@ yargs-parser@^20.2.2: resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== -yargs@^13.3.0, yargs@^13.3.2: +yargs@^13.3.2: version "13.3.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== From 1f6bb4846356303f107a6e0acca5450e0d60086f Mon Sep 17 00:00:00 2001 From: Alicia Sykes Date: Mon, 4 Mar 2024 20:21:33 +0000 Subject: [PATCH 3/4] =?UTF-8?q?=E2=9A=A1=20Implement=20debounce,=20to=20st?= =?UTF-8?q?op=20dup=20rebuild=20when=20file=20meta=20changes=20in=20Linux?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- services/watch-for-changes.js | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/services/watch-for-changes.js b/services/watch-for-changes.js index c7faec2b..51b2c8f9 100644 --- a/services/watch-for-changes.js +++ b/services/watch-for-changes.js @@ -1,20 +1,28 @@ const fs = require('fs'); const { exec } = require('child_process'); +const path = require('path'); -const configFile = './public/conf.yml'; +const configFile = path.resolve(__dirname, './public/conf.yml'); +let timeout = null; console.log(`Watching for file changes on ${configFile}`); fs.watch(configFile, (eventType, filename) => { if (filename && eventType === 'change') { - console.log(`${filename} file Changed, running build...`); - exec('yarn build', (error, stdout, stderr) => { - if (error) { - console.error(`exec error: ${error}`); - return; - } - console.log(`stdout: ${stdout}`); - console.error(`stderr: ${stderr}`); - }); + console.log(`${filename} file Changed, preparing to build...`); + // Clear the existing timeout, if there is one + if (timeout) clearTimeout(timeout); + // Set a new timeout + timeout = setTimeout(() => { + console.log('Running build...'); + exec('yarn build', (error, stdout, stderr) => { + if (error) { + console.error(`exec error: ${error}`); + return; + } + console.log(`stdout: ${stdout}`); + console.error(`stderr: ${stderr}`); + }); + }, 1000); // Adjust the debounce time as necessary, here it's 1000 milliseconds (1 second) } }); From 147016278a5b411eea49d4b84461b4c96cefe1d2 Mon Sep 17 00:00:00 2001 From: Alicia Sykes Date: Mon, 4 Mar 2024 21:29:53 +0000 Subject: [PATCH 4/4] =?UTF-8?q?=E2=9A=A1=20Auto-rebuild=20script=20done,?= =?UTF-8?q?=20with=20debounce=20and=20term=20logging?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- services/watch-for-changes.js | 90 +++++++++++++++++++++++++++-------- 1 file changed, 70 insertions(+), 20 deletions(-) diff --git a/services/watch-for-changes.js b/services/watch-for-changes.js index 51b2c8f9..a66000b2 100644 --- a/services/watch-for-changes.js +++ b/services/watch-for-changes.js @@ -1,28 +1,78 @@ const fs = require('fs'); const { exec } = require('child_process'); const path = require('path'); +const crypto = require('crypto'); -const configFile = path.resolve(__dirname, './public/conf.yml'); +// Default location of config file in container +const configFileName = '../public/conf.yml'; +// Real path of config file in container +const configFilePath = path.resolve(__dirname, configFileName); +// Amount of time to ignore file after change detected +const debounceTimeMs = 2000; + +// Store current timeout let timeout = null; +// Store last hash of file +let lastHash = null; -console.log(`Watching for file changes on ${configFile}`); +/** + * Calculate hash of file, used for de-bounce mechanism to + * prevent successive updates if file content not changed + */ +const hashFileContent = (filePath) => { + const content = fs.readFileSync(filePath, 'utf8'); + return crypto.createHash('sha256').update(content).digest('hex'); +}; -fs.watch(configFile, (eventType, filename) => { - if (filename && eventType === 'change') { - console.log(`${filename} file Changed, preparing to build...`); - // Clear the existing timeout, if there is one - if (timeout) clearTimeout(timeout); - // Set a new timeout - timeout = setTimeout(() => { - console.log('Running build...'); - exec('yarn build', (error, stdout, stderr) => { - if (error) { - console.error(`exec error: ${error}`); - return; - } - console.log(`stdout: ${stdout}`); - console.error(`stderr: ${stderr}`); - }); - }, 1000); // Adjust the debounce time as necessary, here it's 1000 milliseconds (1 second) +/** + * Just logs a given message to terminal so user knows what's happening + */ +const logInfo = (message, msgLevel = 'OUTPUT') => { + const RESET = '\x1b[0m'; + let logLevels = {}; + switch (msgLevel) { + case 'ERROR': logLevels = { col: '\x1b[31m', func: console.error }; break; + case 'WARNING': logLevels = { col: '\x1b[33m', func: console.warn }; break; + case 'INFO': logLevels = { col: '\x1b[36m', func: console.info }; break; + case 'SUCCESS': logLevels = { col: '\x1b[32m', func: console.log }; break; + default: logLevels = { col: RESET, func: console.log }; } -}); + logLevels.func(`${logLevels.col}\x1b[1m[${msgLevel}]${RESET} ${logLevels.col}${message}${RESET}\n`); +}; + +// Log initial message to user +logInfo(`When '${configFileName}' is updated, a rebuild will be triggered.\n`); + +/** + * Code to be executed when a watch event is triggered + * Will check correctly expected file and time frame, + * then ensure the hash is different from last hash, + * and then trigger -rebuild of frontend with yarn build + * outputting the stdrout and stderr to user's terminal + */ +const watchAction = (eventType, filename) => { + if (filename && eventType === 'change') { + if (timeout) clearTimeout(timeout); + timeout = setTimeout(() => { + const currentHash = hashFileContent(configFilePath); + if (currentHash !== lastHash) { + lastHash = currentHash; + logInfo(`${filename} file Changed, running build...`); + exec('yarn build', (error, stdout, stderr) => { + if (error) { + logInfo(error, 'ERROR'); + return; + } + logInfo(stdout); + logInfo(stderr, 'WARNING'); + logInfo('Build completed successfully.\n', 'SUCCESS'); + }); + } else { + logInfo(`${filename} file Detected change, but content is the same. Skipping....`, 'WARNING'); + } + }, debounceTimeMs); + } +}; + +// Watch given config path, with the watch action function +fs.watch(configFilePath, watchAction);