From 7316dae28ad1325cdfbdb70f94463913ede754b8 Mon Sep 17 00:00:00 2001 From: Brandon Keepers Date: Sun, 19 Mar 2017 22:20:30 -0500 Subject: [PATCH 1/5] Update development docs --- CONTRIBUTING.md | 37 ------------------------------------- docs/development.md | 27 +++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 37 deletions(-) delete mode 100644 CONTRIBUTING.md create mode 100644 docs/development.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 79247bfa13..0000000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,37 +0,0 @@ -# Contributing - -## Running Locally - -0. Clone the repository with `git clone https://github.com/bkeepers/PRobot.git` -0. Make sure you have a recent version of [Node.js](https://nodejs.org/) installed -0. Run `$ script/bootstrap` to install all the project dependencies -0. Install [ngrok](https://ngrok.com/download) (`$ brew cask install ngrok` on a mac), which will expose the local server to the internet so GitHub can send webhooks -0. Run `$ script/tunnel` to start ngrok, which should output something like `Forwarding https://4397efc6.ngrok.io -> localhost:3000` -0. [Register an integration](https://developer.github.com/early-access/integrations/creating-an-integration/) on GitHub with: - - **Callback URL** and **Webhook URL**: The full ngrok url above. For example: `https://4397efc6.ngrok.io/` - - **Secret:** `development` - - **Permissions & events** needed will depend on how you use the bot, but for development it may be easiest to enable everything. -0. Download the private key and move it to `private-key.pem` in the project directory -0. Edit `.env` and fill in all the environment variables -0. With `ngrok` still running, open another terminal and run `$ script/server` to start the server on http://localhost:3000 - -Whenever you com back to work on the app after you've already had it running once, then you need to: - -0. Run `$ script/server` -0. Run `$ script/tunnel` in another window -0. `ngrok` will use a different URL every time it is restarted, so you will have to go into the [settings for your Integration](https://github.com/settings/installations) and update all the URLs. - -## Testing - -To test with a real GitHub repository, you'll need to create a test repository and install the integration you created above: - -0. Open up the settings for your installation and click "Install" -0. Create a `.probot.js` in your repository with: - on("issues.opened").comment("Hello World! Your bot is working!"); -0. Open a new issue. Your bot should post a comment (you may need to refresh to see it). - -## Debugging - -0. Always run `$ script/bootstrap` and restart the server if package.json has changed. -0. To turn on verbose logging, start server by running: `$ LOG_LEVEL=debug script/server` -0. To see what requests are going out, start the server by running: `$ LOG_LEVEL=trace script/server` diff --git a/docs/development.md b/docs/development.md new file mode 100644 index 0000000000..b4d2657449 --- /dev/null +++ b/docs/development.md @@ -0,0 +1,27 @@ +# Development + +To run a plugin locally, you'll need to create a GitHub Integration and configure it to deliver webhooks to your local machine. + +1. Make sure you have a recent version of [Node.js](https://nodejs.org/) installed +1. Install [ngrok](https://ngrok.com/download) (`$ brew cask install ngrok` on a mac), which will expose the local server to the internet so GitHub can send webhooks +1. Run `$ ngrok http 3000` to start ngrok, which should output something like `Forwarding https://4397efc6.ngrok.io -> localhost:3000` +1. [Create a new GitHub Integration](https://github.com/settings/integrations/new) with: + - **Callback URL** and **Webhook URL**: The full ngrok url above. For example: `https://4397efc6.ngrok.io/` + - **Secret:** `development` + - **Permissions & events** needed will depend on how you use the bot, but for development it may be easiest to enable everything. +1. Download the private key and move it to `private-key.pem` in the project directory +1. Edit `.env` and set `INTEGRATION_ID` to the ID of the integration you just created. +1. With `ngrok` still running, open another terminal and run `$ npm start` to start the server on http://localhost:3000 + +You'll need to create a test repository and install your Integration by clicking the "Install" button on the settings page. + +Whenever you com back to work on the app after you've already had it running once, then you need to: + +1. Run `$ npm start` +1. Run `$ ngrok http 3000` in another terminal window +1. `ngrok` will use a different URL every time it is restarted, so you will have to go into the [settings for your Integration](https://github.com/settings/integrations) and update all the URLs. + +## Debugging + +1. Always run `$ npm install` and restart the server if package.json has changed. +1. To turn on verbose logging, start server by running: `$ LOG_LEVEL=trace npm start` From e11927dfcd7c81b38f5f93c2b705888238bb5171 Mon Sep 17 00:00:00 2001 From: Brandon Keepers Date: Sun, 19 Mar 2017 22:56:17 -0500 Subject: [PATCH 2/5] Add API docs --- docs/api.md | 98 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 docs/api.md diff --git a/docs/api.md b/docs/api.md new file mode 100644 index 0000000000..de0a32976c --- /dev/null +++ b/docs/api.md @@ -0,0 +1,98 @@ +# API + +This is the official probot API. Anything not documented here is subject to change without notice. + +## Robot + +The `robot` parameter available to plugins is an instance of [`Robot`](/lib/robot.js). + +```js +module.exports = robot => { + // your code here +}; +``` + +### on + +`robot.on` will listen for any GitHub [GitHub webhooks](https://developer.github.com/webhooks/), which are fired for almost every significant action that users take on GitHub. The `on` method takes a callback, which will be invoked with two arguments when GitHub delivers a webhook: + +- `event` - the event that was triggered, including `event.payload` which has the payload from GitHub. +- [`context`](#context) - helpers for extracting information from the event, which can be passed to GitHub API calls + +```js +module.exports = robot => { + robot.on('push', (event, context) => { + // Code was pushed to the repo, what should we do with it? + robot.log(event); + }); +}; +``` + +Most events also include an "action". For example, the [`issues`](https://developer.github.com/v3/activity/events/types/#issuesevent) event has actions of `assigned`, `unassigned`, `labeled`, `unlabeled`, `opened`, `edited`, `milestoned`, `demilestoned`, `closed`, and `reopened`. Often, your bot will only care about one type of action, so you can append it to the event name with a `.`: + +```js +module.exports = robot => { + robot.on('issues.opened', event => { + // An issue was just opened. + }); +}; +``` + +### auth + +`robot.auth(id)` will return an authenticated GitHub client that can be used to make API calls. It takes the ID of the installation, which can be extracted from an event: + +```js +module.exports = function(robot) { + robot.on('issues.opened', async (event, context) => { + const github = await robot.auth(event.payload.installation.id); + }); +}; +``` + +> Note: `robot.auth` is asynchronous, so it needs to be prefixed with a [`await`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await) to wait for the magic to happen. + +The `github` object returned from authenticating is an instance of the [github Node.js module](https://github.com/mikedeboer/node-github), which wraps the [GitHub API](https://developer.github.com/v3/) and allows you to do almost anything programmatically that you can do through a web browser. + +### log + +`robot.log` is a logger backed by [bunyan](https://github.com/trentm/node-bunyan). + +```js +robot.log("This is a debug message"); +robot.log.debug("…so is this"); +robot.log.trace("Now we're talking"); +robot.log.info("I thought you should know…"); +robot.log.warn("Woah there"); +robot.log.error("ETOOMANYLOGS"); +robot.log.fatal("Goodbye, cruel world!"); +``` + +The default log level is `debug`, but you can change it by setting the `LOG_LEVEL` environment variable to `trace`, `info`, `warn`, `error`, or `fatal`. + +## Context + +[Context](/lib/context.js) has helpers for extracting information from the webhook event, which can be passed to GitHub API calls. + +### `repo` + +Return the `owner` and `repo` params for making API requests against a repository. The object passed in will be merged with the repo params. + +```js +const params = context.repo({path: '.github/stale.yml'}) +// Returns: {owner: 'username', repo: 'reponame', path: '.github/stale.yml'} +``` + +### `issue` + +Return the `owner`, `repo`, and `number` params for making API requests against an issue or pull request. The object passed in will be merged with the repo params. + + +```js +const params = context.issue({body: 'Hello World!'}) +// Returns: {owner: 'username', repo: 'reponame', number: 123, body: 'Hello World!'} +``` + +### isBot + +Returns a boolean if the actor on the event was a bot. From c3d80ea2569d3a1278f387e4d17b44638123b57c Mon Sep 17 00:00:00 2001 From: Brandon Keepers Date: Sun, 19 Mar 2017 23:01:03 -0500 Subject: [PATCH 3/5] Tweak README --- README.md | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 5bb90a909a..38eb417bc8 100644 --- a/README.md +++ b/README.md @@ -8,19 +8,18 @@ If you've ever thought, "wouldn't it be cool if GitHub could…"; imma stop you > > –Documentation on [GitHub Integrations](https://developer.github.com/early-access/integrations/) -Some companies provide [hosted integrations](https://github.com/integrations) that you can install, but there's also a bunch of really cool things you can build yourself, and Probot aims to make that easy. +There are some great services that offer [hosted integrations](https://github.com/integrations), but you can build a bunch of really cool things yourself. Probot aims to make that easy. -Here are a few examples of things you can build: +## Plugins -- [autoresponder](https://github.com/probot/autoresponder) replies to opened issues with the contents of `.github/ISSUE_REPLY_TEMPLATE.md` -- [stale](https://github.com/probot/stale) closes abandoned issues after a period of inactivity. +Bots are implemented as plugins, which are easy to write, deploy, and share. Here are just a few examples of things probot can do: -Browse all [probot plugins](https://github.com/search?q=topic%3Aprobot-plugin+org%3Aprobot&type=Repositories). +- [stale](https://github.com/probot/stale) - closes abandoned issues after a period of inactivity. +- [owners](https://github.com/probot/owners) - @mentions people in Pull Requests based on contents of the OWNERS file +- [configurer](https://github.com/probot/configurer) - syncs repository settings defined in `.github/config.yml` to GitHub, enabling Pull Requests for repository settings. -## Contributing - -Most of the interesting things are built with [plugins](docs/plugins.md), so consider starting by writing a new plugin or improving one of the [existing ones](https://github.com/search?q=topic%3Aprobot-plugin+org%3Aprobot&type=Repositories). +Check out [all probot plugins](https://github.com/search?q=topic%3Aprobot-plugin&type=Repositories). -See [CONTRIBUTING.md](CONTRIBUTING.md) for other ways to contribute. +## Contributing -[![Join the chat at https://gitter.im/bkeepers/PRobot](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/bkeepers/PRobot?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +Most of the interesting things are built with plugins, so consider starting by [writing a new plugin](docs/plugins.md) or improving one of the [existing ones](https://github.com/search?q=topic%3Aprobot-plugin&type=Repositories). From 989586b29309d950051ae2fdde649f59a5ff8697 Mon Sep 17 00:00:00 2001 From: Brandon Keepers Date: Sun, 19 Mar 2017 23:11:59 -0500 Subject: [PATCH 4/5] Update plugin docs --- docs/plugins.md | 64 ++++++++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 36 deletions(-) diff --git a/docs/plugins.md b/docs/plugins.md index b182a5586a..c7c0ec99a2 100644 --- a/docs/plugins.md +++ b/docs/plugins.md @@ -1,6 +1,6 @@ -## Plugins +# Plugins -A plugin is just a [node module](https://nodejs.org/api/modules.html) that exports a function: +A plugin is just a [Node.js module](https://nodejs.org/api/modules.html) that exports a function: ```js module.exports = robot => { @@ -10,7 +10,7 @@ module.exports = robot => { The `robot` parameter is an instance of [`Robot`](/lib/robot.js) and gives you access to all of the bot goodness. -### Receiving GitHub webhooks +## Receiving GitHub webhooks [GitHub webhooks](https://developer.github.com/webhooks/) are fired for almost every significant action that users take on GitHub, whether it's pushes to code, opening or closing issues, opening or merging pull requests, or commenting on a discussion. @@ -18,7 +18,7 @@ Many robots will spend their entire day responding to these actions. `robot.on` ```js module.exports = robot => { - robot.on('push', event => { + robot.on('push', async (event, context) => { // Code was pushed to the repo, what should we do with it? robot.log(event); }); @@ -31,27 +31,21 @@ Most events also include an "action". For example, the [`issues`](https://develo ```js module.exports = robot => { - robot.on('issues.opened', event => { + robot.on('issues.opened', async (event, context) => { // An issue was just opened. }); }; ``` -### Interacting with GitHub +## Interacting with GitHub -Probot uses [GitHub Integrations](https://developer.github.com/early-access/integrations/): - -> Integrations are a new way to extend GitHub. They can be installed directly on organizations and user accounts and granted access to specific repositories. They come with granular permissions and built-in webhooks. Integrations are first class actors within GitHub. -> -> –Documentation on [GitHub Integrations](https://developer.github.com/early-access/integrations/) - -An integration is a first-class actor on GitHub, like a user (e.g. [@defunkt](https://github/defunkt)) or a organization (e.g. [@github](https://github.com/github)). That means it can be given access to repositories and perform actions through the API like [commenting on an issue](https://developer.github.com/v3/issues/comments/#create-a-comment) or [creating a status](https://developer.github.com/v3/repos/statuses/#create-a-status). The integration is given access to a repository or repositories by being "installed" on a user or organization account. +Probot uses [GitHub Integrations](https://developer.github.com/early-access/integrations/). An integration is a first-class actor on GitHub, like a user (e.g. [@defunkt](https://github/defunkt)) or a organization (e.g. [@github](https://github.com/github)). The integration is given access to a repository or repositories by being "installed" on a user or organization account and can perform actions through the API like [commenting on an issue](https://developer.github.com/v3/issues/comments/#create-a-comment) or [creating a status](https://developer.github.com/v3/repos/statuses/#create-a-status). Each event delivered includes an ID of the installation that triggered it, which can be used to authenticate. `robot.auth(id)` will give your plugin an authenticated GitHub client that can be used to make API calls. ```js -module.exports = function(robot) { - robot.on('issues.opened', event => { +module.exports = robot => { + robot.on('issues.opened', async (event, context) => { const github = await robot.auth(event.payload.installation.id); // do something useful with the github client }); @@ -65,8 +59,8 @@ The `github` object returned from authenticating is an instance of the [github N Here is an example of an autoresponder plugin that comments on opened issues: ```js -module.exports = function(robot) { - robot.on('issues.opened', async function(event, context) { +module.exports = robot => { + robot.on('issues.opened', async (event, context) => { const github = await robot.auth(event.payload.installation.id); // `context` extracts information from the event, which can be passed to @@ -82,18 +76,26 @@ module.exports = function(robot) { See the [full API docs](https://mikedeboer.github.io/node-github/) to see all the ways you can interact with GitHub. Some API endpoints are not available on GitHub Integrations yet, so check [which ones are available](https://developer.github.com/early-access/integrations/available-endpoints/) first. -### Running plugins +## Running plugins -TODO: link to docs on getting running in development +Before you can run your plugin against GitHub, you'll need to set up your [development environment](development.md) and configure a GitHub Integration for testing. You will the the ID and private key of a GitHub Integration to run the bot. +Once you have an integration created, install `probot`: + +``` +$ npm install -g probot ``` -$ npm install -g https://github.com/probot/probot -$ probot run ./autoresponder.js +and run your bot, replacing `9999` and `private-key.pem` below with the ID and path to the private key of your integration. + +``` +$ probot run -i 9999 -P private-key.pem ./autoresponder.js Listening on http://localhost:3000 ``` -### Distributing +Once your bot is running, you'll need to use `ngrok` to receive GitHub webhooks as described in the [development](development.md) documentation. + +## Publishing your bot Plugins can be published in NPM modules, which can either be deployed as stand-alone bots, or combined with other plugins. @@ -104,18 +106,8 @@ $ curl -L https://github.com/probot/plugin-template/archive/master.tar.gz | tar $ mv plugin-template probot-myplugin && cd probot-myplugin ``` -### Logging - -Probot uses [bunyan](https://github.com/trentm/node-bunyan) for logging. You can call it with `robot.log`. - -```js -robot.log("This is a debug message"); -robot.log.debug("…so is this"); -robot.log.trace("Now we're talking"); -robot.log.info("I thought you should know…"); -robot.log.warn("Woah there"); -robot.log.error("ETOOMANYLOGS"); -robot.log.fatal("Goodbye, cruel world!"); -``` +## Next -The default log level is `debug`, but you can change it by setting the `LOG_LEVEL` environment variable to `trace`, `info`, `warn`, `error`, or `fatal`. +- [See the full Probot API](api.md) +- [Tips for development](development.md) +- [Deploy your plugin](deployment.md) From 6ac5b45464c2b580fa4478299a3b79e75295156c Mon Sep 17 00:00:00 2001 From: Brandon Keepers Date: Sun, 19 Mar 2017 23:18:26 -0500 Subject: [PATCH 5/5] Start of deploy docs --- docs/deployment.md | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/docs/deployment.md b/docs/deployment.md index b7a7d8bbdc..c3fa4ddde6 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -1,10 +1,12 @@ -# Deployment +## Deploy -Every plugin can either be deployed as a stand-alone bot, or combined with other plugins. +Every plugin can either be deployed as a stand-alone bot, or combined with other plugins in one deployment. + +> **Heads up!** Note that most [plugins in the @probot organization](https://github.com/search?q=topic%3Aprobot-plugin+org%3Aprobot&type=Repositories) have an official hosted integration that you can use for your open source project. Use the hosted instance if you don't want to deploy your own. ## Combining plugins -To deploy a bot that includes multiple plugins, create a new app that has them both listed as dependencies in `package.json`: +To deploy a bot that includes multiple plugins, create a new app that has the plugins listed as dependencies in `package.json`: ```json { @@ -26,9 +28,6 @@ To deploy a bot that includes multiple plugins, create a new app that has them b } ``` -### Deploying to Heroku +## Heroku -0. [![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy) - Click this button and pick an **App Name** that Heroku is happy with, like `your-name-probot`. Before you can complete this, you'll need config variables from the next step. -0. In another tab, [create an integration](https://developer.github.com/early-access/integrations/creating-an-integration/) on GitHub, using `https://your-app-name.herokuapp.com/` as the **Homepage URL**, **Callback URL**, and **Webhook URL**. The permissions and events that your bot needs access to will depend on what you use it for. -0. After creating your GitHub integration, go back to the Heroku tab and fill in the configuration variables with the values for the GitHub Integration -0. Create a `.probot.yml` file in your repository. See [Configuring](#configuring). +TODO: Generic docs for deploying a plugin to Heroku