Rework docs for website

This commit is contained in:
Brandon Keepers 2017-08-18 07:46:23 -05:00
parent e21eb51194
commit 0158c1f167
No known key found for this signature in database
GPG Key ID: F9533396D5FACBF6
11 changed files with 275 additions and 8 deletions

19
docs/README.md Normal file
View File

@ -0,0 +1,19 @@
---
next: docs/hello-world.md
permalink: /docs/
---
# Introduction
If you've ever thought, "wouldn't it be cool if GitHub could…"; imma stop you right there. Most features can actually be added via [GitHub Apps](https://developer.github.com/apps/), which extend GitHub and can be installed directly on organizations and user accounts and granted access to specific repositories. They come with granular permissions and built-in webhooks. Apps are first class actors within GitHub.
**Probot is a framework for building [GitHub Apps](http://developer.github.com/apps) in [Node.js](https://nodejs.org/)**. It aims to eliminate all the drudgerylike receiving and validating webhooks, and doing authentication handstandsso you can focus on the features you want to build.
Probot apps are easy to write, deploy, and share. Many of the most popular Probot apps are hosted, so there's nothing for you to deploy and manage. Here are just a few examples of things that have been built with Probot:
- [stale](/apps/stale/) - closes abandoned issues after a period of inactivity.
- [settings](/apps/settings/) - syncs repository settings defined in `.github/config.yml` to GitHub, enabling Pull Requests for repository settings.
- [request-info](/apps/request-info/) - requests more info from newly opened Pull Requests and Issues that contain either default titles or whose description is left blank.
- [Browse more examples](https://github.com/search?q=topic%3Aprobot-plugin&type=Repositories)
Ready to get started?

View File

@ -1,4 +1,4 @@
# Best practices for Probot plugins
# Best Practices
First and foremost, your plugin must obey the [The Three Laws of Robotics](https://en.wikipedia.org/wiki/Three_Laws_of_Robotics):

View File

@ -1,4 +1,8 @@
# Deploy
---
next: docs/best-practices.md
---
# Deployment
Every plugin can either be deployed as a stand-alone bot, or combined with other plugins in one deployment.
@ -72,7 +76,7 @@ Probot runs like [any other Node app](https://devcenter.heroku.com/articles/depl
-----> Launching... done
http://arcane-lowlands-8408.herokuapp.com deployed to Heroku
1. Your plugin should be up and running! To verify that your plugin
1. Your plugin should be up and running! To verify that your plugin
is receiving webhook data, you can tail your app's logs:
$ heroku config:set LOG_LEVEL=trace

View File

@ -1,8 +1,57 @@
# Development
---
next: docs/webhooks.md
---
To run a plugin locally, you'll need to create a GitHub App and configure it to deliver webhooks to your local machine.
# Developing a Plugin
To develop a Probot plugin, you will first need a recent version of [Node.js](https://nodejs.org/) installed. Probot uses the `async/await` keywords, so Node.js 7.6 is the minimum required version.
## Generating a new plugin
[create-probot-plugin](https://github.com/probot/create-probot-plugin) is the best way to start building a new plugin. It will generate a new plugin with everything you need to get started and run your plugin in production.
To get started, install the module from npm:
```
$ npm install -g create-probot-plugin
```
Next, run the app:
```
$ create-probot-plugin my-first-plugin
```
This will ask you a series of questions about your plugin, which should look something like this:
```
Let's create a Probot plugin!
? Plugin's package name: my-first-plugin
? Description of plugin: A "Hello World" GitHub App built with Probot
? Plugin author's full name: Brandon Keepers
? Plugin author's email address: bkeepers@github.com
? Plugin author's homepage:
? Plugin's GitHub user or org name: bkeepers
? Plugin's repo name: my-first-plugin
created file: my-first-plugin/.env.example
created file: my-first-plugin/.gitignore
created file: my-first-plugin/.travis.yml
created file: my-first-plugin/LICENSE
created file: my-first-plugin/README.md
created file: my-first-plugin/app.json
created file: my-first-plugin/index.js
created file: my-first-plugin/package-lock.json
created file: my-first-plugin/package.json
created file: my-first-plugin/docs/deploy.md
Done!
```
The most important files note here are `index.js`, which is where the code for your plugin will go, and `package.json`, which makes this a standard [npm module](https://docs.npmjs.com/files/package.json).
## Configure a GitHub App
To run your plugin in development, you will need to configure a GitHub App to deliver webhooks to your local machine.
1. Make sure you have a recent version of [Node.js](https://nodejs.org/) installed
1. [Create a new GitHub App](https://github.com/settings/apps/new) with:
- **Webhook URL**: Set to `https://example.com/` and we'll update it in a minute.
- **Webhook Secret:** `development`
@ -14,11 +63,22 @@ To run a plugin locally, you'll need to create a GitHub App and configure it to
You'll need to create a test repository and install your app by clicking the "Install" button on the settings page of your app.
Whenever you come back to work on the app after you've already had it running once, you should only need to run `$ npm start`.
## Running the plugin
Once you've set the `APP_ID` of your GitHub app in `.env` and downloaded the private key, you're ready to run your bot.
```
$ npm start
> probot run ./index.js
Yay, the plugin was loaded!
18:11:55.838Z DEBUG PRobot: Loaded plugin: ./index.js
Listening on https://bkeepers.localtunnel.me
```
Optionally, you can also run your plugin through [nodemon](https://github.com/remy/nodemon#nodemon) which will listen on any files changes in your local development environment and automatically restart the server. After installing nodemon, you can run `nodemon --exec "npm start"` and from there the server will automatically restart upon file changes.
## Debugging
1. Always run `$ npm install` and restart the server if package.json has changed.
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`

27
docs/github-api.md Normal file
View File

@ -0,0 +1,27 @@
---
next: docs/http.md
---
# Interacting with GitHub
Probot uses [GitHub Apps](https://developer.github.com/apps/). An app is a first-class actor on GitHub, like a user (e.g. [@defunkt](https://github/defunkt)) or an organization (e.g. [@github](https://github.com/github)). The app 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).
`context.github` is an authenticated GitHub client that can be used to make API calls. It 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.
Here is an example of an autoresponder plugin that comments on opened issues:
```js
module.exports = robot => {
robot.on('issues.opened', async context => {
// `context` extracts information from the event, which can be passed to
// GitHub API calls. This will return:
// {owner: 'yourname', repo: 'yourrepo', number: 123, body: 'Hello World!}
const params = context.issue({body: 'Hello World!'})
// Post a comment on the issue
return context.github.issues.createComment(params);
});
}
```
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 Apps yet, so check [which ones are available](https://developer.github.com/v3/apps/available-endpoints/) first.

15
docs/hello-world.md Normal file
View File

@ -0,0 +1,15 @@
---
next: docs/development.md
---
# Hello World
A Probot plugin is just a [Node.js module](https://nodejs.org/api/modules.html) that exports a function:
```js
module.exports = robot => {
// your code here
};
```
The `robot` parameter is an instance of [`Robot`](https://probot.github.io/probot/latest/Robot.html) and gives you access to all of the bot goodness.

28
docs/http.md Normal file
View File

@ -0,0 +1,28 @@
---
next: docs/simulating-webhooks.md
---
# HTTP Routes
Calling `robot.route('/my-plugin')` will return an [express](http://expressjs.com/) router that you can use to expose HTTP endpoints from your plugin.
```js
module.exports = robot => {
// Get an express router to expose new HTTP endpoints
const app = robot.route('/my-plugin');
// Use any middleware
app.use(require('express').static(__dirname + '/public'));
// Add a new route
app.get('/hello-world', (req, res) => {
res.end('Hello World');
});
};
```
Visit https://localhost:3000/my-plugin/hello-world to access the endpoint.
It is strongly encouraged to use the name of your package as the prefix so none of your routes or middleware conflict with other plugins. For example, if [`probot/owners`](https://github.com/probot/owners) exposed an endpoint, the plugin would call `robot.route('/owners')` to prefix all endpoints with `/owners`.
See the [express documentation](http://expressjs.com/en/guide/routing.html) for more information.

15
docs/pagination.md Normal file
View File

@ -0,0 +1,15 @@
---
next: docs/deployment.md
---
# Pagination
Many GitHub API endpoints are paginated. The `github.paginate` method can be used to get each page of the results.
```js
context.github.paginate(context.github.issues.getAll(context.repo()), res => {
res.data.issues.forEach(issue => {
robot.console.log('Issue: %s', issue.title);
});
});
```

View File

@ -0,0 +1,17 @@
---
next: docs/pagination.md
---
# Simulating Webhooks
As you are developing your plugin, you will likely want to test it by repeatedly trigging the same webhook. You can simulate a webhook being delivered by saving the payload to a file, and then calling `probot simulate` from the command line.
To save a copy of the payload, go to the [settings](https://github.com/settings/apps) page for your App, and go to the **Advanced** tab. Click on one of the **Recent Deliveries** to expand it and see the details of the webhook event. Copy the JSON from the the **Payload** and save it to a new file. (`test/fixtures/issues.labeled.json` in this example).
![](https://user-images.githubusercontent.com/173/28491924-e03e91f2-6ebe-11e7-9570-6d48da68c6ca.png)
Next, simulate this event being delivered by running:
```
$ node_modules/.bin/probot simulate issues test/fixtures/issues.labeled.json ./index.js
```

52
docs/testing.md Normal file
View File

@ -0,0 +1,52 @@
---
next: docs/pagination.md
---
# Testing
We highly recommend working in the style of [test-driven development](http://agiledata.org/essays/tdd.html) when creating probot plugins. It frustrating to constantly create real GitHub events in order to test a plugin. Redelivering webhooks is possible and can be accessed in your app's [settings](https://github.com/settings/apps) page under the **Advanced** tab. We do offer the above documented `simulate` method to help make this easier; however, by writing your tests first, you can avoid repeatedly recreating actual events from GitHub to check if your code is working.
For our testing examples, we use [mocha](https://mochajs.org/) and [expect](https://github.com/mjackson/expect), but there are other options that can perform similar operations. Here's an example of creating a robot instance and mocking out the GitHub API:
```js
// Requiring our testing framework
const expect = require('expect');
// Requiring probot allows us to mock out a robot instance
const {createRobot} = require('probot');
// Create a fixtures folder in your test folder
// Then put any larger testing payloads in there
const payload = require('./fixtures/payload');
describe('your-plugin', () => {
let robot;
let github;
beforeEach(() => {
// Here we create a robot instance
robot = createRobot();
// Here we initialize the plugin on the robot instance
plugin(robot);
// This is an easy way to mock out the GitHub API
github = {
issues: {
createComment: expect.createSpy().andReturn(Promise.resolve({
// Whatever the GitHub API should return
}))
}
}
// Passes the mocked out GitHub API into out robot instance
robot.auth = () => Promise.resolve(github);
});
describe('your functionality', () => {
it('performs an action', async () => {
// Simulates delivery of a payload
await robot.receive(payload);
// This test would pass if in your main code you called `context.github.issues.createComment`
expect(github.issues.createComment).toHaveBeenCalled();
});
});
});
```
A good testing example from [update-docs](github.com/behaviorbot/update-docs) can be found [here](https://github.com/behaviorbot/update-docs/blob/master/test/index.js), and another one from [owners](github.com/probot/owners) can be found [here](https://github.com/probot/owners/blob/master/test/owner-notifier.js).

30
docs/webhooks.md Normal file
View File

@ -0,0 +1,30 @@
---
next: docs/github-api.md
---
# Receiving 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.
Many robots will spend their entire day responding to these actions. `robot.on` will listen for any GitHub webhook events:
```js
module.exports = robot => {
robot.on('push', async context => {
// Code was pushed to the repo, what should we do with it?
robot.log(context);
});
};
```
The robot can listen to any of the [GitHub webhook events](https://developer.github.com/webhooks/#events). The `context` object includes all of the information about the event that was triggered, and `context.payload` has the payload delivered by GitHub.
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', async context => {
// An issue was just opened.
});
};
```