Skip to content

Commit

Permalink
implemented mutex for config colors
Browse files Browse the repository at this point in the history
  • Loading branch information
J2-Tech committed Nov 19, 2024
1 parent 47c0f5e commit 97d45b0
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 39 deletions.
50 changes: 45 additions & 5 deletions controllers/configController.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const fs = require('fs');
const path = require('path');
const { Mutex } = require('async-mutex');
const jiraAPIController = require('../controllers/jiraAPIController');
const { JSDOM } = require('jsdom');
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
Expand All @@ -14,19 +15,58 @@ const defaultConfig = {
issueColors: {}
};

exports.loadConfig = function () {
// Create a mutex
const mutex = new Mutex();

const issueColorsToUpdate = {};

exports.loadConfig = async function () {
return await mutex.runExclusive( async () => {
return readSettingsInternal();
});
}

function readSettingsInternal() {
if (!fs.existsSync(configPath)) {
fs.writeFileSync(configPath, JSON.stringify(defaultConfig, null, 2), 'utf8');
}
return JSON.parse(fs.readFileSync(configPath, 'utf8'));
}

exports.setSetting = function (key, value) {
const config = exports.loadConfig();
config[key] = value;
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf8');
exports.setSetting = async function (key, value) {
return await mutex.runExclusive(async () => {
const config = readSettingsInternal();
config[key] = value;
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf8');
});
}

/**
* Accumulate issue colors to update.
* @param {string} issueKey - The issue key.
* @param {string} color - The color to update.
*/
exports.accumulateIssueColor = async function(issueKey, color) {
await mutex.runExclusive(async () => {
issueColorsToUpdate[issueKey.toLowerCase()] = color;
});
};

/**
* Save accumulated issue colors.
*/
exports.saveAccumulatedIssueColors = async function() {
await mutex.runExclusive(async () => {
const config = readSettingsInternal();
config.issueColors = { ...config.issueColors, ...issueColorsToUpdate };
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf8');
// Clear the accumulated colors after saving
for (const key in issueColorsToUpdate) {
delete issueColorsToUpdate[key];
}
});
};

exports.ensureConfigDirExists = async function(req) {
if (!fs.existsSync(configDir)) {
fs.mkdirSync(configDir);
Expand Down
68 changes: 37 additions & 31 deletions controllers/jiraController.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const configController = require('./configController');
const dayjs = require('dayjs');
const path = require('path');

exports.getParentIssueColor = async function(settings, req, issue) {
exports.getParentIssueColor = async function(settings, req, issue, newIssueColorKeys) {
if (issue.fields.parent) {
const parentIssue = await jiraAPIController.getIssue(req, issue.fields.parent.id);
if (parentIssue && parentIssue.fields) {
Expand All @@ -13,46 +13,50 @@ exports.getParentIssueColor = async function(settings, req, issue) {
}
if (settings.issueColors[parentIssue.key.toLowerCase()]) {
return settings.issueColors[parentIssue.key.toLowerCase()];
}
if (parentIssue.fields[configController.loadConfig().issueColorField]) {
const jiraColor = parentIssue.fields[configController.loadConfig().issueColorField];
switch (jiraColor) {
case 'purple': return '#8777D9';
case 'blue': return '#2684FF';
case 'green': return '#57D9A3';
case 'teal': return '#00C7E6';
case 'yellow': return '#FFC400';
case 'orange': return '#FF7452';
case 'grey': return '#6B778C';
case 'dark_purple': return '#5243AA';
case 'dark_blue': return '#0052CC';
case 'dark_green': return '#00875A';
case 'dark_teal': return '#00A3BF';
case 'dark_yellow': return '#FF991F';
case 'dark_orange': return '#DE350B';
case 'dark_grey': return '#253858';
default: return jiraColor;
}else {
let color = process.env.DEFAULT_ISSUE_COLOR || '#2a75fe';
if (parentIssue.fields[settings.issueColorField]) {
const jiraColor = parentIssue.fields[settings.issueColorField];
switch (jiraColor) {
case 'purple': color = '#8777D9'; break;
case 'blue': color = '#2684FF'; break;
case 'green': color = '#57D9A3'; break;
case 'teal': color = '#00C7E6'; break;
case 'yellow': color = '#FFC400'; break;
case 'orange': color = '#FF7452'; break;
case 'grey': color = '#6B778C'; break;
case 'dark_purple': color = '#5243AA'; break;
case 'dark_blue': color = '#0052CC'; break;
case 'dark_green': color = '#00875A'; break;
case 'dark_teal': color = '#00A3BF'; break;
case 'dark_yellow': color = '#FF991F'; break;
case 'dark_orange': color = '#DE350B'; break;
case 'dark_grey': color = '#253858'; break;
default: color = jiraColor; break;
}
await configController.accumulateIssueColor(parentIssue.key, color);
settings.issueColors[parentIssue.key.toLowerCase()] = color;
return color;
}

}

}
}
return null;
}

exports.determineIssueColor = async function(req, issue) {
const settings = configController.loadConfig();
exports.determineIssueColor = async function(settings, req, issue) {
const defaultColor = process.env.DEFAULT_ISSUE_COLOR || '#2a75fe';

let color = settings.issueColors[issue.issueKey.toLowerCase()];
if (!color) {
// get the issue details
const issueDetails = await jiraAPIController.getIssue(req, issue.issueId);
color = await exports.getParentIssueColor(settings, req, issueDetails);
if (!color && issue.issueType) {
const issueTypeLower = issue.issueType.toLowerCase();
color = settings.issueColors[issueTypeLower] || defaultColor;
}
configController.setSetting('issueColors', { ...settings.issueColors, [issue.issueKey.toLowerCase()]: color });
}
return color;
}
Expand All @@ -73,8 +77,10 @@ exports.getUsersWorkLogsAsEvent = async function(req, start, end) {
const worklogs = await getFilteredWorklogs(req, issue, filterStartTime, filterEndTime);
return Promise.all(worklogs);
});
const worklogs = await Promise.all(worklogPromises);
return worklogs.flat();
const worklogs = await Promise.all(worklogPromises)
const flatLogs = worklogs.flat();
await configController.saveAccumulatedIssueColors();
return flatLogs;
});
};

Expand All @@ -88,12 +94,13 @@ function extractIssues(issues) {
}));
}

function getFilteredWorklogs(req, issue, filterStartTime, filterEndTime) {
async function getFilteredWorklogs(req, issue, filterStartTime, filterEndTime) {
const settings = await configController.loadConfig();
return jiraAPIController.getIssueWorklogs(req, issue.issueId, filterEndTime.getTime(), filterStartTime.getTime())
.then(result => {
const worklogs = result.worklogs;
const filteredLogs = worklogs.filter(worklog => filterWorklog(req, worklog, filterStartTime, filterEndTime));
const promises = filteredLogs.map(worklog => exports.formatWorklog(req, worklog, issue));
const promises = filteredLogs.map(worklog => exports.formatWorklog(settings, req, worklog, issue));
return promises;
});
}
Expand All @@ -111,9 +118,8 @@ function filterWorklog(req, worklog, filterStartTime, filterEndTime) {
return condition;
}

exports.formatWorklog = async function (req, worklog, issue) {
const color = await exports.determineIssueColor(req, issue);
const settings = configController.loadConfig();
exports.formatWorklog = async function (settings, req, worklog, issue) {
const color = await exports.determineIssueColor(settings, req, issue);
const showIssueTypeIcons = settings.showIssueTypeIcons || false;

let title = `<b class="plywood-event-title">${issue.issueKey} - ${issue.summary}</b> <span class="comment">${worklog.comment || ''}</span>`;
Expand Down
14 changes: 14 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"start": "node ./bin/www"
},
"dependencies": {
"async-mutex": "^0.5.0",
"cookie-parser": "~1.4.6",
"dayjs": "^1.11.13",
"dotenv": "^16.4.5",
Expand Down
6 changes: 3 additions & 3 deletions routes/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,16 @@ router.post('/saveConfig', async (req, res) => {
await configController.ensureConfigDirExists(req);
const config = req.body;
for ( key in config ) {
configController.setSetting(key, config[key]);
await configController.setSetting(key, config[key]);
}
res.json({ message: 'Configuration saved successfully' }).status(200);
});

router.post('/saveIssueColor', async (req, res) => {
const { issueKey, color } = req.body;
const config = configController.loadConfig();
const config = await configController.loadConfig();
config.issueColors[issueKey.toLowerCase()] = color;
configController.setSetting('issueColors', config.issueColors);
await configController.setSetting('issueColors', config.issueColors);
res.json({ message: 'Issue color saved successfully' }).status(200);

});
Expand Down

0 comments on commit 97d45b0

Please sign in to comment.