Publish App to Update Set from Server side code

Shane Crenshaw
Kilo Contributor

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;
}
1 ACCEPTED SOLUTION

TylerTeter
Kilo Guru

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.

View solution in original post

7 REPLIES 7

ARG645
Tera Guru

Shane,

 

Its not possible. The below line is the connection to the server side code from client side code. 

dd.setPreference('sysparm_ajax_processor', 'com.snc.apps.AppsAjaxProcessor');

in the above line, we are setting the script include name (com.snc.apps.AppsAjaxProcessor)for our Ajax call. This  OOB script include is not available and is restricted. 

 

Thank you,

Aman Gurram

Dang. Is the knowledge available to:

1) Somehow call AppsAjaxProcessor from server?
2) Recreate what publish to update set does?

Really need to be able to somehow publish an app scope to an update set.

TylerTeter
Kilo Guru

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.

TylerTeter I followed your method to the T, but I keep getting the following error thrown in the logs

Error running scripted hierarchical progress worker %s.%s: java.lang.NullPointerException: com.glide.worker.ScriptedHierarchicalWorker.populateScriptIncludeContext(ScriptedHierarchicalWorker.java:108)
com.glide.worker.ScriptedHierarchicalWorker.startWork(ScriptedHierarchicalWorker.java:64)
com.glide.worker.AbstractProgressWorker.startAndWait(AbstractProgressWorker.java:126)
com.glide.worker.HierarchicalProgressWorker.startAndWait(HierarchicalProgressWorker.java:35)
com.glide.worker.BackgroundProgressJob.execute(BackgroundProgressJob.java:59)
com.glide.schedule.JobExecutor.lambda$executeJob$0(JobExecutor.java:108)
com.glide.schedule.JobExecutor.executeJob(JobExecutor.java:111)
com.glide.schedule.JobExecutor.execute(JobExecutor.java:95)
com.glide.schedule_v2.SchedulerWorkerThread.executeJob(SchedulerWorkerThread.java:329)
com.glide.schedule_v2.SchedulerWorkerThread.lambda$process$0(SchedulerWorkerThread.java:192)
com.glide.worker.TransactionalWorkerThread.executeInTransaction(TransactionalWorkerThread.java:35)
com.glide.schedule_v2.SchedulerWorkerThread.process(SchedulerWorkerThread.java:192)
com.glide.schedule_v2.SchedulerWorkerThread.run(SchedulerWorkerThread.java:100)

 

For references, this is the script that I am calling:

// Scripted Rest Service

var body = request.body.data;
var app_id = body["id"];
var name = body["name"];
var version = body["version"];
var description = body["description"];
var update_set_id = gs.generateGUID();
var progress_name = "APPEXPORTJOB_" + name;

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 GlobalAppExport(); //hacky bit - I copy pasted your "MyRequest" class here.
g_req.setPreference('sysparm_function', 'publishToUpdateSet');
g_req.setPreference('sysparm_sys_id', app_id); //hacky bit
g_req.setPreference('sysparm_update_set_id', update_set_id);
g_req.setPreference('sysparm_name', name);
g_req.setPreference('sysparm_version', version);
g_req.setPreference('sysparm_description', description);	

worker.putConstructorArg('g_request',g_req); //hacky bit
worker.start();

var trackerID = worker.getProgressID();


return {
    "app_id": app_id,
    "update_set_id": update_set_id,
    "name": name,
    "tracker_id": trackerID,
    "version": version,
    "description": description,
};

 

Any thoughts on what might be throwing this error?