- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎10-22-2018 08:11 AM
In ServiceNow you have the ability to view your app --> click 'Publish to Update Set'. I am needing to mimic this functionality in a script include or a rest script. Is there anyway to do this?
Here is the client script that the UI does, but I cannot for the life of me figure out how to mimic this in a scripted Rest script or a script include.
Thanks!
function publishApp(updateSetId)
{
var dd = new GlideModal("hierarchical_progress_viewer");
dd.on("beforeclose", function ()
{
var notification = {
"getAttribute": function (name)
{
return 'true';
}
};
CustomEvent.fireTop(GlideUI.UI_NOTIFICATION + '.update_set_change', notification);
window.location.href = "sys_update_set.do?sys_id=" + updateSetId;
});
dd.setTitle("Progress");
dd.setPreference('sysparm_function', 'publishToUpdateSet');
dd.setPreference('sysparm_update_set_id', updateSetId);
dd.setPreference('sysparm_sys_id', this.appId);
dd.setPreference('sysparm_name', this.inferredUsName);
dd.setPreference('sysparm_version', this.versionField.value);
dd.setPreference('sysparm_description', this.descriptionField.value);
dd.setPreference('sysparm_include_data', this.includeDataField.checked);
dd.setPreference('sysparm_progress_name', "Publishing application");
dd.setPreference('sysparm_ajax_processor', 'com.snc.apps.AppsAjaxProcessor');
dd.setPreference('sysparm_show_done_button', 'true');
dd.render();
GlideModal.prototype.get('publish_app_dialog').destroy();
return dd;
}
Solved! Go to Solution.

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎12-26-2018 12:19 PM
It's possible to do an equivalent Server Side call, you just have to do a little reverse engineering to make it work. I can't professionally endorse it, so proceed at your own risk.
First of all, you can emulate it by using the rather undocumented GlideScriptedHierarchicalWorker API.
Here is an adaptation of a code example:
var worker = new GlideScriptedHierarchicalWorker();
worker.setProgressName(progress_name);
worker.setBackground(true);
worker.setCannotCancel(true);
worker.setScriptIncludeName("com.snc.apps.AppsAjaxProcessor");
worker.setScriptIncludeMethod("publishToUpdateSet");
var g_req = new MyRequest(); //hacky bit
g_req.setPreference('sysparm_sys_id',ID); //hacky bit
... more preferences here
worker.putConstructorArg('g_request',g_req); //hacky bit
worker.start();
trackerID = worker.getProgressID();
Explaining the Hacky Bit, and "MyRequest", To make it work, you have to make the AbstractAjaxProcessor script think it's interacting with a standard g_request. So you need to make an object that has the function "getParameter". This is the OOB Ajax method for parsing out parameters. Then pass that object with all your parameters to the constructor, again this is the OOB AbstractAjaxProcessor initialize function.
Here is an script include you can use for MyRequest
var MyRequest = Class.create();
MyRequest.prototype = {
initialize: function() {
this.parms = {};
},
setPreference: function(key, value){
this.parms[key] = value;
},
getParameter: function(key){
return this.parms[key];
},
type: 'MyRequest'
};
I learned this the hard way, but my biggest external resource was http://www.cavucode.com/blog/2015/4/8/fujiforty-hierarchicalworker-and-progress-viewer - I just had to fill in the gaps.

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎05-28-2020 10:51 PM
When I was doing some research a year ago for this, my use case was actually for upgrading applications (ie, publishing and installing scoped apps), versus this use case for exporting to update sets. I'd probably have to mock up a prototype myself to get you a true working version.
Just from a quick glance though, I see you are missing the preference, sysparm_include_data, that might be required. Or there might be some other required field.
And I am not sure if your inputs are all formatted correctly like it expects. Basically you have to put yourself in the mind set of calling some unknown function and copy what you see from the client side code, and mimic it.
Hopefully ServiceNow will one day expose more of these actions as APIs, instead of these hidden java package code calls.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎09-23-2021 04:34 AM
Tyler, Shane,
I never needed to do this server side until recently as I needed to publish multiple apps to update sets easily in preparation for cloning. I didn't want to have to open each app individually and do it - I wanted it as part of my automated cloning preparation.
Anyway, I was able to crack this nut and mimic what com.snc.apps.AppsAjaxProcessor::publishToUpdateSet does. You can create a script include with a method called publishAppToUpdateSet (or whatever) that takes the sys_id of the application as an argument. This solution does NOT include Demo data. If you need that, you're on your own 🙂
DISCLAIMER: I have tested this with some small (scoped not global) apps <300 files by comparing my update sets with the update sets created by the OOB SN Ajax. I have only seen the OOB SN Ajax publish files from 3 tables: sys_app, sys_metadata, and sys_package_dependency_m2m. If it publishes files from other tables, I am not aware.
Here's the basics of the code - no error checking included. Note: GlideUpdateManager's saveRecord() function returns a boolean value - true for success, false otherwise.
publishAppToUpdateSet: function(app_id) {
// app_id is the sys_id of the application's record in the sys_app table.
// We'll be using GlideUpdateManager2 to create sys_update_xml records for the update set
var GUM = new GlideUpdateManager2();
// First, create an update set for the application. Feel free to set other update set fields as desired
var us = new GlideRecord('sys_update_set');
us.initialize();
us.name = '<Whatever you want to call it>';
us.application = app_id;
var set_id = us.insert();
// Make the update set current (GlideUpdateManager2 always uses the current update set)
new GlideUpdateSet().set(set_id);
// Get the GlideRecord for the application from sys_app and add it to the update set.
var grApp = new GlideRecord('sys_app');
grApp.get(app_id);
GUM.saveRecord(grApp);
// Now we need to loop through all of the application's files in sys_metadata that have an
// update_name (some don't) and add them to the update set.
// Note that we'll use GlideRecordUtil().getGr() to get a GlideRecord of the correct class for the file
var grMeta = new GlideRecord('sys_metadata');
grMeta.addEncodedQuery('sys_scope=' + app_id + '^sys_update_name!=NULL');
grMeta.query();
while(grMeta.next()) {
var appFile = new GlideRecordUtil().getGr('sys_metadata', grMeta.sys_id);
GUM.saveRecord(appFile);
}
// Finally, there may be package dependency records that need to be added to the update set
var grDep = new GlideRecord('sys_package_dependency_m2m');
grDep.addEncodedQuery('sys_package=' + app_id);
grDep.query();
while(grDep.next()) {
GUM.saveRecord(grDep);
}
// Add code for publishing other files here....
},

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎11-29-2021 07:43 AM
I've been exploring Cloning Automation steps as of late, and this is a major pain point for us, to export all our apps and re-import them afterwards. I'll be exploring your approach sooner than later! Thanks for the comment Norm!