You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@openwhisk.apache.org by GitBox <gi...@apache.org> on 2017/10/24 13:56:36 UTC

[GitHub] mrutkows closed pull request #602: Adding manifest for incubator-openwhisk-githubslackbot

mrutkows closed pull request #602: Adding manifest for incubator-openwhisk-githubslackbot
URL: https://github.com/apache/incubator-openwhisk-wskdeploy/pull/602
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/tests/apps/openwhisk-githubslackbot/README.md b/tests/apps/openwhisk-githubslackbot/README.md
new file mode 100644
index 0000000..b8bad67
--- /dev/null
+++ b/tests/apps/openwhisk-githubslackbot/README.md
@@ -0,0 +1,90 @@
+# GitHub Slack Bot
+
+[Github Slack Bot](https://github.com/apache/incubator-openwhisk-GitHubSlackBot)
+is an application designed to post updates to Slack when a GitHub pull request is
+ready to merge or a list of pull requests are under review for certain days and
+haven't merged.
+
+You can find detailed Architecture and Usage at
+[incubator-openwhisk-githubslackbot](https://github.com/apache/incubator-openwhisk-GitHubSlackBot).
+
+Github Slack Bot application is dependent on three major components:
+
+1. [Cloudant Package](https://github.com/apache/incubator-openwhisk-package-cloudant)
+2. [GitHub Package](https://github.com/apache/incubator-openwhisk-catalog/tree/master/packages/github)
+3. [Slack Package](https://github.com/apache/incubator-openwhisk-catalog/tree/master/packages/slack)
+
+
+#### `manifest.yaml` for Cloudant Package 
+
+```yaml
+    dependencies:
+        cloudant-package:
+            location: /whisk.system/cloudant
+            inputs:
+                username: $CLOUDANT_USERNAME
+                password: $CLOUDANT_PASSWORD
+                host: ${CLOUDANT_USERNAME}.cloudant.com
+```
+
+#### `manifest.yaml` for Github Package 
+
+```yaml
+    dependencies:
+            github-package:
+                location: /whisk.system/github
+                inputs:
+                    username: $GITHUB_USERNAME
+                    repository: $GITHUB_REPOSITORY
+                    accessToken: $GITHUB_ACCESSTOKEN
+```
+
+#### `manifest.yaml` for Slack Package 
+
+
+```yaml
+    dependencies:
+        slack-package:
+            location: /whisk.system/slack
+            inputs:
+                username: $SLACK_USERNAME 
+                url: $SLACK_URL
+                channel: $SLACK_CHANNEL
+```
+### Step 1: Deploy
+
+
+Export the following env. variables before running `wskdeploy`:
+
+```
+CLOUDANT_USERNAME
+CLOUDANT_PASSWORD
+CLOUDANT_DATABASE
+GITHUB_USERNAME
+GITHUB_REPOSITORY
+GITHUB_ACCESSTOKEN
+SLACK_USERNAME
+SLACK_URL
+SLACK_CHANNEL
+```
+Deploy it using `wskdeploy`:
+
+```
+wskdeploy -p tests/apps/openwhisk-githubslackbot
+```
+
+### Step 2: Verify
+
+```
+$ wsk package get TrackPRsInCloudant 
+$ wsk package get GitHubWebHook
+$ wsk package get PostPRToSlack
+$ wsk action get track-pull-requests
+$ wsk action get find-delayed-pull-requests
+$ wsk action get post-to-slack
+$ wsk trigger get GitHubWebHookTrigger
+$ wsk trigger get Every12Hours
+$ wsk rule get RuleToTrackPullRequests
+$ wsk rule get RuleToPostGitHubPRsToSlack
+```
+
diff --git a/tests/apps/openwhisk-githubslackbot/actions/find-delayed-pull-requests.js b/tests/apps/openwhisk-githubslackbot/actions/find-delayed-pull-requests.js
new file mode 100644
index 0000000..bee7c95
--- /dev/null
+++ b/tests/apps/openwhisk-githubslackbot/actions/find-delayed-pull-requests.js
@@ -0,0 +1,250 @@
+/*
+ * 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",
+  *         "github_username": "xxxx",
+  *         "github_access_token": "xxxx",
+  *     }
+  *
+  * @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;
+//global variable for GitHub username and access token
+var githubUsername;
+var githubAccessToken;
+
+// predetermined threshold for pull requests duration
+// pull requests needs attention if they are older than this threshold
+var limits = {
+    "READY": {
+        amount: 3,
+        unit: "days"
+    },
+    "REVIEW": {
+        amount: 4,
+        unit: "days"
+    }
+};
+
+function main(params) {
+    // instantiate the openwhisk instance before you can use it
+    wsk = openwhisk();
+
+    // read Params
+    var cloudantPackage = params["cloudant_package"];
+    githubUsername = params["github_username"];
+    githubAccessToken = params["github_access_token"];
+
+    // validate cloudant package is set in params
+    if (typeof cloudantPackage === "undefined" || cloudantPackage === null) {
+        return {
+            "error": "Cloudant package is not specified. Please set \"cloudant_package\" bound parameter."
+        };
+    }
+
+    // validate github username is set in params
+    if (typeof githubUsername === "undefined" || githubUsername === null) {
+        return {
+            "error": "GitHub username is not specified. Please set \"github_username\" bound parameter."
+        };
+    }
+
+    // validate github access token is set in params
+    if (typeof githubAccessToken === "undefined" || githubAccessToken === null) {
+        return {
+            "error": "GitHub access token is not specified. Please set \"github_access_token\" bound parameter."
+        };
+    }
+
+    // access namespace as environment variables
+    var namespace = process.env["__OW_NAMESPACE"];
+
+    // Cloudant package can be accessed using /namespace/package
+    packageName = "/" + namespace + "/" + cloudantPackage;
+
+    // get list of pull requests from cloudant database
+    return wsk.actions.invoke({
+        actionName: packageName + "/list-documents",
+        params: { "include_docs": true },
+        blocking: true
+    })
+    .then(activation => {
+        console.log("Found " + activation.response.result.total_rows + " docs.");
+        var listOfIDs = activation.response.result.rows.map(function (row) {
+            return row.id;
+        });
+        return listOfIDs;
+    })
+    .then(function (listOfIds) {
+        return Promise.all(listOfIds.map(getExistingDocument));
+    })
+    .then(function (trackedPrDocs) {
+        // filter to only PRs that are "too old"
+        return trackedPrDocs.filter(prIsTooOld);
+    })
+    .then(function (oldPrDocs) {
+        // filter to only PRs that are still open
+        // because of the undefined order we receive Github events, it is
+        // possible that we are still tracking a PR that has since been closed.
+        var stillOpenPromises = oldPrDocs.map(isStillOpen);
+        return Promise.all(stillOpenPromises)
+            .then(function (isPrOpenArray) {
+                var delayedPRs = oldPrDocs.filter(function (prDoc, index) {
+                    return isPrOpenArray[index];
+                });
+                return {
+                    prs: delayedPRs
+                };
+            });
+        });
+}
+
+function isStillOpen(prDoc) {
+    // fetch updated record from GitHub
+    return fetchPrFromGithub(prDoc)
+        .then(function (latest) {
+            if (latest.state === "closed") {
+                console.log("PR#" + prDoc.pr.number + " is now closed, but still being tracked - deleting it from Cloudant.");
+                // delete from Cloudant - don"t bother waiting for result
+                stopTracking(prDoc.pr);
+                return false;
+            } else {
+                console.log("PR#" + prDoc.pr.number + " is still open.");
+                return true;
+            }
+        });
+}
+
+// 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 a document 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 document from database for: " + id);
+        console.log(err)
+        return undefined;
+    });
+}
+
+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.invoke.actions({
+                        actionName: packageName + "/delete-document",
+                        params: {
+                            docid: existingDoc._id,
+                            docrev: existingDoc._rev
+                        }
+                    })
+                    .then (function () {
+                        return {
+                            message: "Sucessfully 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
+                };
+            }
+        });
+}
+
+function fetchPrFromGithub(prDoc) {
+    var authorizationHeader = "Basic " + new Buffer(githubUsername + ":" + githubAccessToken).toString("base64");
+    var options = {
+        method: "GET",
+        url: prDoc.pr.url,
+        json: true,
+        headers: {
+            "Content-Type": "application/json",
+            "Authorization": authorizationHeader,
+            "User-Agent": githubUsername
+        }
+    };
+    var request = require("request");
+    return new Promise(function (resolve, reject) {
+        request(options, function (error, response, body) {
+            if (error) {
+                reject({
+                    response: response,
+                    error: error,
+                    body: body
+                });
+            } else {
+                if (response.statusCode == 200) {
+                    resolve(body);
+                } else {
+                    reject({
+                        statusCode: response.statusCode,
+                        response: body
+                    });
+                }
+            }
+        });
+    });
+}
+
+function prIsTooOld(prDoc) {
+    var moment = require("moment");
+    // read lastUpdate from github
+    var readyMoment = moment(prDoc.lastUpdate);
+    // depeneding on the state of pull request, "READY" or "REVIEW"
+    // read the limit amount and days
+    var limit = limits[prDoc.state];
+    // moment.diff() returns difference between today and
+    // when pull request was last updated (in days as limit.unit is days)
+    // return true if the pull request was updated certain (limit.amount) days ago
+    return (moment().diff(readyMoment, limit.unit) >= limit.amount);
+}
diff --git a/tests/apps/openwhisk-githubslackbot/actions/post-to-slack.js b/tests/apps/openwhisk-githubslackbot/actions/post-to-slack.js
new file mode 100644
index 0000000..adc4a5a
--- /dev/null
+++ b/tests/apps/openwhisk-githubslackbot/actions/post-to-slack.js
@@ -0,0 +1,116 @@
+/*
+ * 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:
+  *     {
+  *         "prs": "xxxx",
+  *         "slack_package": "xxxx",
+  *     }
+  *
+  * @return which must be a JSON object.
+  *         It will be the output of this action.
+  *
+  */
+
+function main(params) {
+    // require the OpenWhisk npm package
+    var openwhisk = require("openwhisk");
+
+    // instantiate the openwhisk instance before you can use it
+    wsk = openwhisk();
+
+    //read Params
+    var prs = params.prs;
+    var slackPackage = params.slack_package;
+
+    if (prs.length === 0) {
+        return {
+            message: "Yeay! No old PRs!"
+        };
+    }
+
+    var messages = ["Hello Whisk Devs! It looks like we have some Pull Requests that may require a little love:\n"];
+
+    prs.sort(byDescendingAge);
+
+    for (var i = 0; i < prs.length; i++) {
+        // read pr from a document
+        var doc = prs[i];
+        var pr = doc.pr;
+        console.log("PR:" + doc._id);
+        // find out how many days old a pull request is.
+        var age = getPrAge(doc, "days");
+        var ageString = age + " " + (age === 1 ? "day" : "days");
+        var message;
+        if(doc.state === "READY") {
+            message = "has been marked \"ready\" for more than " + ageString
+        } else {
+            message = "has been under \"review\" without comments for more than " + ageString
+        }
+        messages.push("<" + pr["html_url"] + "|[" + pr.base.repo["full_name"] + "] PR #" + pr.number + "> " + message);
+    }
+
+    console.log(messages.join("\n"));
+
+    // access namespace as environment variables
+    var namespace = process.env["__OW_NAMESPACE"];
+
+    // Slack package can be accessed using /namespace/package
+    packageName = "/" + namespace + "/" + slackPackage;
+
+    return wsk.actions.invoke({
+        actionName: packageName + "/post",
+        params: {
+            "text": messages.join("\n"),
+        },
+        blocking: true
+    })
+    .then(activation => {
+        console.log("Posted messages to slack");
+        return {
+            message: activation
+        };
+    })
+    .catch(function (err) {
+        console.log("Error posting messages to slack")
+        return {
+            error: err
+        };
+    });
+}
+
+function byDescendingAge(pr1, pr2) {
+    var age1 = getPrAge(pr1, "hours");
+    var age2 = getPrAge(pr2, "hours");
+    // sort descending
+    return age2 - age1;
+}
+
+function getPrAge(pr, unit) {
+    var moment = require("moment");
+    // instantiate moment with last update of a pull request
+    var readyMoment = moment(pr.lastUpdate);
+    // difference between now and last update in "hours" or "days"
+    return moment().diff(readyMoment, unit);
+}
diff --git a/tests/apps/openwhisk-githubslackbot/actions/track-pull-requests.js b/tests/apps/openwhisk-githubslackbot/actions/track-pull-requests.js
new file mode 100644
index 0000000..108c67d
--- /dev/null
+++ b/tests/apps/openwhisk-githubslackbot/actions/track-pull-requests.js
@@ -0,0 +1,248 @@
+/*
+ * 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: "Sucessfully 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
+                };
+            }
+        });
+}
diff --git a/tests/apps/openwhisk-githubslackbot/manifest.yaml b/tests/apps/openwhisk-githubslackbot/manifest.yaml
new file mode 100644
index 0000000..6cf0529
--- /dev/null
+++ b/tests/apps/openwhisk-githubslackbot/manifest.yaml
@@ -0,0 +1,90 @@
+# OpenWhisk Whisk Deploy manifest for incubator-openwhisk-githubslackbot
+# Installing openwhisk actions, triggers, and rules for OpenWhisk building block
+#   Cloudant Package
+#   GitHub Package
+#   Slack Package
+#   Alarm Trigger
+#   
+
+# Deployment using this manifest file creates following OpenWhisk components:
+#   Package:    TrackPRsInCloudant
+#   Package:    GitHubWebHook
+#   Pacakge:    PostPRToSlack
+#   Package:    githubslackbot
+#   Action:     githubslackbot/track-pull-requests
+#   Action:     githubslackbot/find-delayed-pull-requests
+#   Action:     githubslackbot/post-to-slack
+#   Sequence:   githubslackbot/SequenceToPostGitHubPRsToSlack
+#   Trigger:    GitHubWebHookTrigger, Every12Hours
+#   Rule:       RuleToTrackPullRequests, RuleToPostGitHubPRsToSlack
+
+# This manifest file reads following env. variables:
+#   CLOUDANT_USERNAME
+#   CLOUDANT_PASSWORD
+#   CLOUDANT_DATABASE
+#   GITHUB_USERNAME
+#   GITHUB_REPOSITORY
+#   GITHUB_ACCESSTOKEN
+#   SLACK_USERNAME
+#   SLACK_URL
+#   SLACK_CHANNEL
+
+packages:
+    githubslackbot:
+        dependencies:
+            TrackPRsInCloudant:
+                location: /whisk.system/cloudant
+                inputs:
+                    username: $CLOUDANT_USERNAME
+                    password: $CLOUDANT_PASSWORD
+                    host: ${CLOUDANT_USERNAME}.cloudant.com
+                    database: $CLOUDANT_DATABASE
+            GitHubWebHook:
+                location: /whisk.system/github
+                inputs:
+                    username: $GITHUB_USERNAME
+                    repository: $GITHUB_REPOSITORY
+                    accessToken: $GITHUB_ACCESSTOKEN
+            PostPRToSlack:
+                location: /whisk.system/slack
+                inputs:
+                    username: $SLACK_USERNAME
+                    url: $SLACK_URL
+                    channel: \#${SLACK_CHANNEL}
+        triggers:
+            GitHubWebHookTrigger:
+                feed: GitHubWebHook/webhook
+                inputs:
+                    events: pull-request
+            Every12Hours:
+                feed: /whisk.system/alarms/alarm
+                inputs:
+                    cron: "0 */12 * * *"
+        actions:
+            track-pull-requests:
+                function: actions/track-pull-requests.js
+                inputs:
+                    cloudant_package: TrackPRsInCloudant
+            find-delayed-pull-requests:
+                function: actions/find-delayed-pull-requests.js
+                inputs:
+                    cloudant_package: TrackPRsInCloudant
+                    github_username: $GITHUB_USERNAME
+                    github_access_token: $GITHUB_ACCESSTOKEN
+            post-to-slack:
+                function: actions/post-to-slack.js
+                inputs:
+                    slack_package: PostPRToSlack
+        sequences:
+            SequenceToPostGitHubPRsToSlack:
+                actions: find-delayed-pull-requests, post-to-slack
+        rules:
+            RuleToTrackPullRequests:
+                trigger: GitHubWebHookTrigger
+                action: track-pull-requests
+            RuleToPostGitHubPRsToSlack:
+                trigger: Every12Hours
+                action: SequenceToPostGitHubPRsToSlack
+
+                    
+


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services