Skip to content

Instantly share code, notes, and snippets.

@jeffdonthemic
Last active January 2, 2016 10:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jeffdonthemic/8290347 to your computer and use it in GitHub Desktop.
Save jeffdonthemic/8290347 to your computer and use it in GitHub Desktop.
Sample script for with Promises for updating an Apex class in Force.com using the Tooling API with node.
var Q = require("q"),
request = require('request');
// call with the following
// var apexClassId = "01pi0000004kbvAAAQ"; // the id of the apex class to update
// var newCode = "public class Test1 { public void sayHelloOnceAgain() { } }"; // pass in some code
// var connetion = resp object from nforce org.authenticate
function updateApex(apexClassId, newCode, connection) {
var deferred = Q.defer();
var bearer = connection.access_token;
console.log("==== STARTING NEW DEPLOY ====");
createContainer()
.then(addUpdatedCode)
.then(deploy)
.then(function(results) {
deferred.resolve(results);
})
.fail(function(err) {
console.log("== failure: " + err);
deferred.reject(err);
});
function deleteContainer(metadataContainerId) {
var deferred = Q.defer();
var options = {
url: connection.instance_url + '/services/data/v28.0/tooling/sobjects/MetadataContainer/' + metadataContainerId,
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + bearer
}
};
function callback(error, response, body) {
if (!error && response.statusCode == 204) {
console.log("Deleted deployment container: " + metadataContainerId);
deferred.resolve("Deployment complete!");
} else {
console.log(response.statusCode);
var result = JSON.parse(body);
deferred.reject("Failed to delete metadata container.");
console.log(result);
}
}
// make the request
request(options, callback);
return deferred.promise;
}
function checkDeployState(containerAsyncRequestId) {
var options = {
url: connection.instance_url + '/services/data/v28.0/tooling/sobjects/ContainerAsyncRequest/' + containerAsyncRequestId,
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + bearer
}
};
function callback(error, response, body) {
if (!error && response.statusCode == 200) {
var result = JSON.parse(body);
if (result.State === "Queued") {
console.log("Status is currently queued. Checking deploy state again.");
checkDeployState(containerAsyncRequestId);
} else {
if (result.State === "Completed") {
console.log("W00t! Code successfully deployed");
} else if (result.State === "Failed") {
console.log("Deployment failed with: ");
console.log(result.CompilerErrors);
} else if (result.State === "Error") {
console.log("Deployment failed with error: ");
console.log(result.ErrorMsg);
} else {
console.log("Deploy finished with a status of: " + result.State);
console.log(result);
}
deleteContainer(result.MetadataContainerId);
}
} else {
var result = JSON.parse(body);
console.log(result);
}
}
// make the request
request(options, callback);
}
function createContainer() {
var deferred = Q.defer();
var options = {
url: connection.instance_url + '/services/data/v28.0/tooling/sobjects/MetadataContainer',
method: 'POST',
body: '{"Name":"AwesomeContainer"}',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + bearer
}
};
function callback(error, response, body) {
if (!error && response.statusCode == 201) {
var result = JSON.parse(body);
console.log("Created MetadataContainer: " + result.id)
deferred.resolve(result.id);
} else {
console.log(response.statusCode);
var result = JSON.parse(body);
deferred.reject("Failed to create a metadata container.");
console.log(result);
}
}
// make the request
request(options, callback);
return deferred.promise;
}
function addUpdatedCode(metadataContainerId) {
var deferred = Q.defer();
var options = {
url: connection.instance_url + '/services/data/v28.0/tooling/sobjects/ApexClassMember',
method: 'POST',
body: '{"MetadataContainerId":"'+metadataContainerId+'", "ContentEntityId":"'+apexClassId+'", "body": "'+newCode+'"}',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + bearer
}
};
function callback(error, response, body) {
if (!error && response.statusCode == 201) {
var result = JSON.parse(body);
console.log("Created ApexClassMember: " + result.id)
deferred.resolve(metadataContainerId);
} else {
console.log(response.statusCode);
var result = JSON.parse(body);
deferred.reject("Failed to add updated code.");
console.log(result);
}
}
// make the request
request(options, callback);
return deferred.promise;
}
function deploy(metadataContainerId) {
var deferred = Q.defer();
var options = {
url: connection.instance_url + '/services/data/v28.0/tooling/sobjects/ContainerAsyncRequest',
method: 'POST',
body: '{"MetadataContainerId":"'+metadataContainerId+'", "isCheckOnly": false}',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + bearer
}
};
function callback(error, response, body) {
if (!error && response.statusCode == 201) {
var result = JSON.parse(body);
console.log("Deployed code with id: " + result.id);
// check the state of the deployment
checkDeployState(result.id);
deferred.resolve(metadataContainerId);
} else {
console.log(response.statusCode);
var result = JSON.parse(body);
deferred.reject("Failed to deploy code.");
console.log(result);
}
}
// make the request
request(options, callback);
return deferred.promise;
}
return deferred.promise;
}
exports.updateApex = updateApex;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment