blob: bfd7613814767c9c7a630dd2ca46900620fd7d0e [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
*
* main() will be invoked when you Run This Action.
*
* @param Whisk actions accept a single parameter,
* which must be a JSON object.
*
* In this case, the params variable will look like:
* {
* "cloudant_package": "xxxx",
* "action": "xxxx",
* "pull_request": {
* "html_url": "xxxx",
* "state": "xxxx",
* "number": "xxxx",
* "updated_at": "xxxx",
* "base": {
* "repo": {
* "full_name": "xxxx"
* }
* }
* },
* "label": {
* "name": "xxxx"
* }
* }
* except cloudant_package, rest of the params are
* sent with webhook POST request.
* cloudant_package should be set as a bound parameter while
* deploying this action.
*
* @return which must be a JSON object.
* It will be the output of this action.
*
*/
// require the OpenWhisk npm package
var openwhisk = require("openwhisk");
// global variable for openwhisk object and cloudant package
var wsk;
var packageName;
function main(params) {
// instantiate the openwhisk instance before you can use it
wsk = openwhisk();
// read Params
var cloudantPackage = params["cloudant_package"];
var pullRequest = params["pull_request"];
var action = params["action"];
// validate cloudant package is set in params
if (typeof cloudantPackage === 'undefined' || cloudantPackage === null) {
return "Cloudant package is not specified. Please set \"cloudant_package\" bound parameter.";
}
// access namespace as environment variables
var namespace = process.env["__OW_NAMESPACE"];
// Cloudant package can be accessed using /namespace/package
packageName = "/" + namespace + "/" + cloudantPackage;
console.log("Action: " + action);
console.log("Cloudant Package Name: " + packageName);
// pull request labels
var ready = "ready";
var review = "review";
// action is set to "closed" for closed pull request
// stop tracking pull request if its closed
// delete it from the datastore
if (action === "closed") {
return stopTracking(pullRequest);
}
// make sure pull request is still open
if (pullRequest.state !== "closed") {
// when pull request is labeled to either "ready" or "review"
if (action === "labeled") {
if (params.label.name === ready) {
console.log("PR#" + pullRequest.number + " is now " + ready + ".");
return track(pullRequest, ready.toUpperCase());
} else if (params.label.name === review) {
console.log("PR#" + pullRequest.number + " is now in " + review + ".");
return track(pullRequest, review.toUpperCase());
}
// when pull request label ("ready" or "review") is removed
} else if (action === "unlabeled") {
if (params.label.name === ready) {
console.log("PR#" + pullRequest.number + " is no longer " + ready + ".");
return stopTracking(pullRequest, ready.toUpperCase());
} else if (params.label.name === review) {
console.log("PR#" + pullRequest.number + " is no longer in " + review + ".");
return stopTracking(pullRequest, review.toUpperCase());
}
} else if (params.action === "synchronize") {
return refreshLastUpdate(pullRequest);
}
} else {
console.log("Received event for closed PR#" + pullRequest.number + ". That\'s curious...\n" + params);
}
return {
message: "[" + pullRequest.base.repo["full_name"] + "] PR#" + pullRequest.number + " - No interesting changes"
};}
// read document from cloudant data store
// return the doc if it exists
function getExistingDocument(id) {
return wsk.actions.invoke({
actionName: packageName + "/read-document",
params: { "docid": id },
blocking: true,
})
.then(activation => {
console.log("Found pull request in database with ID " + id);
return activation.response.result;
})
// it could be possible that the doc with this ID doesn't exist and
// therefore return "undefined" instead of exiting with error
.catch(function (err) {
console.log("Error fetching pull request from database for: " + id);
console.log(err)
return undefined;
});
}
function refreshLastUpdate(pullRequest){
var id = pullRequest["html_url"]
// get the existing doc, set lastUpdate to pullRequest["updated_at"]
return getExistingDocument(id)
.then(function (existingDoc) {
if (existingDoc && existingDoc.pr) {
existingDoc.lastUpdate = id;
console.log("Refreshing lastUpdate: " + id);
return wsk.actions.invoke({
actionName: packageName + "/update-document",
params: {
doc: existingDoc
}
});
} else {
return {
message: "Not refreshing lastUpdate because PR is not tracked"
};
}
})
.catch(function (err) {
console.log("Error fetching pull request from DB: " + id)
return err;
});
}
// write a document in cloudant data store
// updates an existing doc if it exist
function writeDocument (doc) {
return wsk.actions.invoke({
actionName: packageName + "/create-document",
params: { "doc": doc },
blocking: true,
})
.then(activation => {
console.log("Created new document with ID " + activation.response.result.id);
return activation.response.result;
})
.catch(function (err) {
console.log("Error creating document");
return err;
});
}
function track(pullRequest, state) {
var doc = undefined;
return getExistingDocument(pullRequest["html_url"])
.then(function (existingDoc) {
if (existingDoc) {
// update pull request if it exists
existingDoc.state = state;
existingDoc.pr = pullRequest;
existingDoc.lastUpdate = pullRequest["updated_at"];
// createDocument updates doc if _rev and _id exist
doc = existingDoc;
} else {
// the doc does not exist, create one
doc = {
"_id": pullRequest["html_url"],
"pr": pullRequest,
"state": state,
"lastUpdate": pullRequest["updated_at"]
};
console.log("Here is the new document")
console.log(doc)
}
return writeDocument(doc);
});
}
function stopTracking(pullRequest, ifInState) {
var id = pullRequest["html_url"];
// get the existing doc
// if it matches the ifInState, then delete it and
// stop tracking this pull request
return getExistingDocument(id)
.then(function (existingDoc) {
if (existingDoc) {
if (!ifInState || existingDoc.state === ifInState) {
return wsk.actions.invoke({
actionName: packageName + "/delete-document",
params: {
docid: existingDoc._id,
docrev: existingDoc._rev
}
})
.then (function () {
return {
message: "Successfully stopped tracking " + id
};
});
} else {
return {
message: "Refusing to delete doc because it is not in state " + ifInState + " " + id
};
}
} else {
return {
message: "Refusing to delete doc because it does not exist " + id
};
}
});
}