diff --git a/Server Side/Update Sets Scopes Issues Fix Automation/FixUpdatesScope.js b/Server Side/Update Sets Scopes Issues Fix Automation/FixUpdatesScope.js new file mode 100644 index 0000000000..1418a12d8c --- /dev/null +++ b/Server Side/Update Sets Scopes Issues Fix Automation/FixUpdatesScope.js @@ -0,0 +1,4 @@ +var util = new global.UpdateSetUtilCustom(); +var message = util.fixScopeBatch(current); +gs.addInfoMessage(message); +action.setRedirectURL(current); diff --git a/Server Side/Update Sets Scopes Issues Fix Automation/PreventCompletiononScopeConflict.js b/Server Side/Update Sets Scopes Issues Fix Automation/PreventCompletiononScopeConflict.js new file mode 100644 index 0000000000..e6b5289709 --- /dev/null +++ b/Server Side/Update Sets Scopes Issues Fix Automation/PreventCompletiononScopeConflict.js @@ -0,0 +1,8 @@ +(function executeRule(current, previous /*null when async*/) { + var util = new global.UpdateSetUtilCustom(); + if (util.checkForScopeConflict(current)) { + current.setAbortAction(true); + gs.addErrorMessage('This update set has a scope conflict in it. Please click the "Fix Updates Scope" button to fix.'); + action.setRedirectURL(current); + } +})(current, previous); diff --git a/Server Side/Update Sets Scopes Issues Fix Automation/UpdateSetUtilCustom.js b/Server Side/Update Sets Scopes Issues Fix Automation/UpdateSetUtilCustom.js new file mode 100644 index 0000000000..40383657d5 --- /dev/null +++ b/Server Side/Update Sets Scopes Issues Fix Automation/UpdateSetUtilCustom.js @@ -0,0 +1,88 @@ +var UpdateSetUtilCustom = Class.create(); +UpdateSetUtilCustom.prototype = { + initialize: function() {}, + + fixScopeBatch: function(grParent) { + var grUpdate = new GlideRecord('sys_update_xml'); + grUpdate.addEncodedQuery('update_set.parent.parent=' + grParent.getValue('sys_id') + '^ORupdate_set.parent=' + grParent.getValue('sys_id') + '^ORupdate_set=' + grParent.getValue('sys_id') + '^ORupdate_set.base_update_set=' + grParent.getValue('sys_id')); + grUpdate.query(); + + var count = 0; + var newUpdateSets = {}; + + while (grUpdate.next()) { + if (!grUpdate.getValue('application')) { // No app, should be in a global update set + if (grUpdate.update_set.application != 'global' && grUpdate.update_set.application.scope != 'global') { + count++; + + if (!newUpdateSets['global']) { + newUpdateSets['global'] = { + 'name': 'Global', + 'updates': [] + }; + } + newUpdateSets['global']['updates'].push(grUpdate.getValue('sys_id')); + } + } + // We don't have the same scope for each update. + else if (grUpdate.application != grUpdate.update_set.application) { + count++; + + if (!newUpdateSets[grUpdate.getValue('application')]) { + newUpdateSets[grUpdate.getValue('application')] = { + 'name': grUpdate.getDisplayValue('application'), + 'updates': [] + }; + } + newUpdateSets[grUpdate.getValue('application')]['updates'].push(grUpdate.getValue('sys_id')); + } + } + + var parentName = grParent.getValue('name'); + var keys = Object.keys(newUpdateSets); + for (i in keys) { + var updates = newUpdateSets[keys[i]]['updates']; + // Create new update set in the correct scope. + var grNewSet = GlideRecord('sys_update_set'); + grNewSet.initialize(); + grNewSet.setValue('application', keys[i]); + grNewSet.setValue('name', parentName + ' - ' + newUpdateSets[keys[i]]['name']); + grNewSet.setValue('parent', grParent.getValue('sys_id')); + var newSetSysId = grNewSet.insert(); + + for (ii in updates) { + // Get each update and set the new update set. + var updateSysId = updates[ii]; + var grUpdate = new GlideRecord('sys_update_xml'); + if (grUpdate.get(updateSysId)) { + grUpdate.setValue('update_set', newSetSysId); + grUpdate.update(); + } + } + } + if (count > 0) { + return count + ' updates were in the wrong scope. ' + keys.length + ' new update sets were created and associated with this parent update set.'; + } + return 'No update scope issues were found.'; + }, + + checkForScopeConflict: function(grParent) { + var application = grParent.getValue('application'); + var query = 'update_set=' + grParent.getValue('sys_id') + '^application!=' + application + '^ORapplication=NULL'; + if (grParent.application == 'global' || grParent.application.scope == 'global') { + query = 'update_set=' + grParent.getValue('sys_id') + '^application!=' + application + '^applicationISNOTEMPTY^application.scope!=global'; + } + + var grUpdate = new GlideRecord('sys_update_xml'); + grUpdate.addEncodedQuery(query); + grUpdate.setLimit(1); + grUpdate.query(); + + if (grUpdate.hasNext()) { + return true; + } + return false; + }, + + type: 'UpdateSetUtilCustom' +}; diff --git a/Server Side/Update Sets Scopes Issues Fix Automation/readme.md b/Server Side/Update Sets Scopes Issues Fix Automation/readme.md new file mode 100644 index 0000000000..a8a628ed48 --- /dev/null +++ b/Server Side/Update Sets Scopes Issues Fix Automation/readme.md @@ -0,0 +1,35 @@ +ServiceNow Developers work with update set batching and many times it happens that customer updates gets captured in a wrong scope. As of Xanadu release, there is no way to fix these scoping issues in child updates. +This utility will perform following and implement a way of taking in a parent/batch update set: + +- Navigate all children, all updates in children. + +- Determine scope issues with updates. + +- Create new update set in correct scopes. + +- Move updates to those new update sets. + +- Associate them with parent/batch. + +- Stop action on completion of update sets if there are any scope issues found and direct the user to click on the Fix Scope button. + + + +This functionality has following: + +- Business rule to abort transaction if scoping issues are found in batched update sets. +- Script include which does job of scoping issues conflict as well as logic for fixing batch scope issues. +- UI action which can be used by developers to fix scoping issues conflict. + +![image](https://github.com/user-attachments/assets/0a7c5127-7c15-4bb6-bf96-17de3b81a334) + +![image](https://github.com/user-attachments/assets/87872d20-f2c2-42ac-8c69-d095cc7ddaf3) + +![image](https://github.com/user-attachments/assets/94890946-395c-476f-a9b9-b81e94a801c9) + +![image](https://github.com/user-attachments/assets/96bcea79-a06e-4891-aace-3bbba81e9cb4) + + + + +