Update integration-guide according to integrations redesign.

With numerous typo and grammar fixed by tabbott.
This commit is contained in:
Tomasz Kolek
2017-01-26 16:58:23 +01:00
committed by Tim Abbott
parent 6e6cbeb89d
commit 71e6eb68c0
2 changed files with 78 additions and 70 deletions

View File

@@ -25,7 +25,7 @@ paths will be familiar to Django developers.
* `zerver/views/*.py` Most [Django views](https://docs.djangoproject.com/en/1.8/topics/http/views/). * `zerver/views/*.py` Most [Django views](https://docs.djangoproject.com/en/1.8/topics/http/views/).
* `zerver/views/webhooks/` Webhook views for [Zulip integrations](integration-guide.html). * `zerver/webhooks/` Webhook views and tests for [Zulip webhook integrations](integration-guide.html).
* `zerver/tornado/views.py` Tornado views. * `zerver/tornado/views.py` Tornado views.

View File

@@ -32,10 +32,10 @@ products, ordered here by which types we prefer to write:
1. **[Webhook integrations](#webhook-integrations)** (examples: 1. **[Webhook integrations](#webhook-integrations)** (examples:
Freshdesk, GitHub), where the third-party service supports posting Freshdesk, GitHub), where the third-party service supports posting
content to a particular URI on our site with data about the event. content to a particular URI on our site with data about the event.
For these, you usually just need to add a new view file in the For these, you usually just need to create a new python package in
`zerver/views/webhooks/` directory (plus test/document/etc.). An the `zerver/webhooks/` directory. You can easily find recent
example commit implementing a new webhook is: commits adding new integrations to crib from via `git log
https://github.com/zulip/zulip/pull/324. zerver/webhooks/`.
2. **[Python script integrations](#python-script-and-plugin-integrations)** 2. **[Python script integrations](#python-script-and-plugin-integrations)**
(examples: SVN, Git), where we can get the service to call our integration (examples: SVN, Git), where we can get the service to call our integration
@@ -100,26 +100,26 @@ Here's how we recommend doing it:
can use these captured payloads to create a set of test fixtures for can use these captured payloads to create a set of test fixtures for
your integration under `zerver/fixtures`. your integration under `zerver/fixtures`.
* Then write a draft webhook handler under `zerver/views/webhooks/`; * Then write a draft webhook handler under `zerver/webhooks/`;
there are a lot of examples in that directory. We recommend there are a lot of examples in that directory. We recommend
templating off a short one (like `stash.py` or `zendesk.py`), since templating off a short one (like `stash` or `zendesk`), since
the longer ones usually just have more complex parsing which can the longer ones usually just have more complex parsing which can
obscure what's common to all webhook integrations. In addition to obscure what's common to all webhook integrations. In addition to
writing the integration itself, you'll need to create `Integration` writing the integration itself, you'll need to create `Integration`
object and add it to `WEBHOOK_INTEGRATIONS` in object and add it to `WEBHOOK_INTEGRATIONS` in
`zerver/lib/integrations.py'; search for `webhook` in that `zerver/lib/integrations.py';` search for `webhook` in that
file to find the existing ones (and please add yours in the file to find the existing ones (and please add yours in the
alphabetically correct place). alphabetically correct place).
* Then write a test for your fixture in a new file in the * Then write a test for your fixture in the `tests.py` file in the
`zerver/tests/webhooks/` directory, and you can iterate on the tests `zerver/webhooks/mywebhook` directory. You can now iterate on
and webhooks handler until they work, all without ever needing to debugging the tests and webhooks handler until they work, all
post directly from the server you're integrating to your Zulip without ever needing to post directly from the service you're
development machine. To run just the tests from the test class you integrating with to your Zulip development machine. To run just the
wrote, you can use e.g. tests from the test class you wrote, you can use e.g.
``` ```
test-backend zerver.tests.webhooks.test_pagerduty.PagerDutyHookTests test-backend zerver/webhooks/pagerduty/
``` ```
See [this guide](testing.html) for more details on the Zulip test See [this guide](testing.html) for more details on the Zulip test
@@ -155,20 +155,22 @@ for a webhook named 'MyWebHook'.
* `zerver/fixtures/mywebhook/mywebhook_messagetype.json`: Sample json payload data * `zerver/fixtures/mywebhook/mywebhook_messagetype.json`: Sample json payload data
used by tests. Add one fixture file per type of message supported by your used by tests. Add one fixture file per type of message supported by your
integration. See [Testing and writing tests](testing.html) for details. integration. See [Testing and writing tests](testing.html) for details.
* `zerver/views/webhooks/mywebhook.py`: Includes the main webhook integration * `zerver/webhooks/mywebhook/__init__.py`: Empty file that is obligatory
part of every python package. Remember to `git add` it.
* `zerver/webhooks/mywebhook/view.py`: Includes the main webhook integration
function including any needed helper functions. function including any needed helper functions.
* `zerver/tests/webhooks/mywebhook.py`: Add tests for your * `zerver/webhooks/mywebhook/tests.py`: Add tests for your
webbook. See [Testing and writing tests](testing.html) for details. webbook. See [Testing and writing tests](testing.html) for details.
* `zerver/webhooks/mywebhook/doc.html`: Add end-user documentation. See
[Documenting your integration](#documenting-your-integration) for details.
### Files that need to be updated ### Files that need to be updated
* `templates/zerver/integrations.html`: Edit to add end-user documentation. See
[Documenting your integration](#documenting-your-integration) for details.
* `zerver/lib/integrations.py`: Add your integration to * `zerver/lib/integrations.py`: Add your integration to
`WEBHOOK_INTEGRATIONS` to register it. This will automatically `WEBHOOK_INTEGRATIONS` to register it. This will automatically
register a url for the webhook of the form `api/v1/external/mywebhook` register a url for the webhook of the form `api/v1/external/mywebhook`
and associate with the function called `api_mywebhook_webhook` in and associate with the function called `api_mywebhook_webhook` in
`zerver/views/webhooks/mywebhook.py`. `zerver/webhooks/mywebhook/view.py`.
## Python script and plugin integrations ## Python script and plugin integrations
@@ -203,17 +205,17 @@ ZulipMobile/0.5.4 (Android; 4.2; maguro)
## Documenting your integration ## Documenting your integration
Every Zulip integration must be documented in Every Zulip integration must be documented in
`templates/zerver/integrations.html`. Usually, this involves a few `zerver/webhooks/mywebhook/doc.html`. Usually, this involves a few
steps: steps:
* Add an `integration-instructions` class block in the * Add text explaining all of the steps required to setup the
alphabetically correct place, explaining all the steps required to integration, including what URLs to use, etc. If there are any
setup the integration, including what URLs to use, etc. If there screens in the product involved, take a few screenshots with the
are any screens in the product involved, take a few screenshots with input fields filled out with sample values in order to make the
the input fields filled out with sample values in order to make the instructions really easy to follow. For the screenshots, use a bot
instructions really easy to follow. For the screenshots, use with a name like "GitHub Bot", an email address for the bot like
something like `github-bot@example.com` for the email addresses and `github-bot@zulip.example.com`, and an obviously fake API key like
an obviously fake API key like `abcdef123456790`. `abcdef123456790`.
* Make sure you've added your integration to * Make sure you've added your integration to
`zerver/lib/integrations.py`; this results in your integration `zerver/lib/integrations.py`; this results in your integration
@@ -286,16 +288,22 @@ only one fixture, `zerver/fixtures/helloworld/helloworld_hello.json`:
When writing your own webhook integration, you'll want to write a test function When writing your own webhook integration, you'll want to write a test function
for each distinct message condition your webhook supports. You'll also need a for each distinct message condition your webhook supports. You'll also need a
corresponding fixture for each of these tests. See [Step 3: Create corresponding fixture for each of these tests. See [Step 3: Create
tests](#step-3-create-tests) or [Testing](testing.html) for further details. tests](#step-4-create-tests) or [Testing](testing.html) for further details.
### Step 1: Create main webhook code ### Step 1: Initialize your webhook python package
In the `zerver/webhooks/` directory, create new subdirectory that will
contain all of corresponding code. In our example it will be
`helloworld`. The new directory will be a python package, so you have
to create an empty `__init__.py` file in that directory via e.g. `touch
zerver/webhooks/helloworld/__init__.py`.
### Step 2: Create main webhook code
The majority of the code for your webhook integration will be in a single The majority of the code for your webhook integration will be in a single
python file in `zerver/views/webhooks/`. The name of this file should be the python file, `zerver/webhooks/mywebhook/view.py`.
name of your webhook, all lower-case, with file extension `.py`:
`mywebhook.py`.
The Hello World integration is in `zerver/views/webhooks/helloworld.py`: The Hello World integration is in `zerver/webhooks/helloworld/view.py`:
``` ```
from __future__ import absolute_import from __future__ import absolute_import
@@ -377,7 +385,7 @@ validate the message and then send it.
Finally, we return a 200 http status with a JSON format success message via Finally, we return a 200 http status with a JSON format success message via
`json_success()`. `json_success()`.
### Step 2: Create an api endpoint for the webhook ### Step 3: Create an api endpoint for the webhook
In order for a webhook to be externally available, it must be mapped to a url. In order for a webhook to be externally available, it must be mapped to a url.
This is done in `zerver/lib/integrations.py`. This is done in `zerver/lib/integrations.py`.
@@ -395,7 +403,7 @@ And you'll find the entry for Hello World:
``` ```
This tells the Zulip api to call the `api_helloworld_webhook` function in This tells the Zulip api to call the `api_helloworld_webhook` function in
`zerver/views/webhooks/helloworld.py` when it receives a request at `zerver/webhooks/helloworld/view.py` when it receives a request at
`/api/v1/external/helloworld`. `/api/v1/external/helloworld`.
This line also tells Zulip to generate an entry for Hello World on the Zulip This line also tells Zulip to generate an entry for Hello World on the Zulip
@@ -441,10 +449,10 @@ Using either method will create a message in Zulip:
![Image of Hello World webhook message](images/helloworld-webhook.png) ![Image of Hello World webhook message](images/helloworld-webhook.png)
### Step 3: Create tests ### Step 4: Create tests
Every webhook integration should have a corresponding test file in Every webhook integration should have a corresponding test file:
`zerver/tests/webhooks/`. `zerver/webhooks/mywebhook/tests.py`.
You should name the class `<WebhookName>HookTests` and have it inherit from You should name the class `<WebhookName>HookTests` and have it inherit from
the base class `WebhookTestCase`. For our HelloWorld webhook, we name the test the base class `WebhookTestCase`. For our HelloWorld webhook, we name the test
@@ -510,7 +518,7 @@ the Zulip development environment with this command:
``` ```
(zulip-venv)vagrant@vagrant-ubuntu-trusty-64:/srv/zulip$ (zulip-venv)vagrant@vagrant-ubuntu-trusty-64:/srv/zulip$
./tools/test-backend zerver.tests.webhooks.test_hello_world.HelloWorldHookTests ./tools/test-backend zerver/webhooks/helloworld
``` ```
(Note: You must run the tests from the top level of your development directory. (Note: You must run the tests from the top level of your development directory.
@@ -520,15 +528,15 @@ using Vagrant, use the directory where you have your development environment.)
You will see some script output and if all the tests have passed, you will see: You will see some script output and if all the tests have passed, you will see:
``` ```
Running zerver.tests.webhooks.test_hello_world.HelloWorldHookTests.test_goodbye_message Running zerver.webhooks.helloworld.tests.HelloWorldHookTests.test_goodbye_message
Running zerver.tests.webhooks.test_hello_world.HelloWorldHookTests.test_hello_message Running zerver.webhooks.helloworld.tests.HelloWorldHookTests.test_hello_message
DONE! DONE!
``` ```
### Step 4: Create documentation ### Step 5: Create documentation
Next, we add end-user documentation for our webhook integration to Next, we add end-user documentation for our webhook integration to
`templates/zerver/integrations.html`. This is what generates the page `zever/webhooks/mywebhook/doc.html`. This is what generates the page
displayed for your webhook from the Integrations page (in the gear menu.) displayed for your webhook from the Integrations page (in the gear menu.)
You can see an example at [https://zulipchat.com/integrations](https://zulipchat.com/integrations). You can see an example at [https://zulipchat.com/integrations](https://zulipchat.com/integrations).
@@ -541,40 +549,40 @@ installation and usage instructions.
Because there is an entry for the Hello World webhook in WEBHOOK_INTEGRATIONS Because there is an entry for the Hello World webhook in WEBHOOK_INTEGRATIONS
in `zerver/lib/integrations.py`, this div will be generated automatically. in `zerver/lib/integrations.py`, this div will be generated automatically.
The second part is a `div` with the webhook's usage instructions: The second part is a content of a `div` with the webhook's usage instructions.
Because there is an entry for the Hello World webhook in WEBHOOK_INTEGRATIONS
in `zerver/lib/integrations.py`, this div will also be generated automatically.
``` ```
<div id="helloworld" class="integration-instructions"> <p>Learn how Zulip integrations work with this simple Hello World example!</p>
<p>Learn how Zulip integrations work with this simple Hello World example!</p> <p>The Hello World webhook will use the <code>test<code> stream, which is
created by default in the Zulip development environment. If you are running
Zulip in production, you should make sure this stream exists.</p>
<p>The Hello World webhook will use the <code>test<code> stream, which is <p>Next, on your <a href="/#settings" target="_blank">Zulip
created by default in the Zulip development environment. If you are running settings page</a>, create a Hello World bot. Construct the URL for
Zulip in production, you should make sure this stream exists.</p> the Hello World bot using the API key and stream name:
<code>{{ external_api_uri }}/v1/external/helloworld?api_key=abcdefgh&amp;stream=test</code>
</p>
<p>Next, on your <a href="/#settings" target="_blank">Zulip <p>To trigger a notication using this webhook, use `send_webhook_fixture_message` from the Zulip command line:</p>
settings page</a>, create a Hello World bot. Construct the URL for <div class="codehilite">
the Hello World bot using the API key and stream name: <pre>(zulip-venv)vagrant@vagrant-ubuntu-trusty-64:/srv/zulip$
<code>{{ external_api_uri }}/v1/external/helloworld?api_key=abcdefgh&amp;stream=test</code>
</p>
<p>To trigger a notication using this webhook, use `send_webhook_fixture_message` from the Zulip command line:</p>
<div class="codehilite">
<pre>(zulip-venv)vagrant@vagrant-ubuntu-trusty-64:/srv/zulip$
./manage.py send_webhook_fixture_message \ ./manage.py send_webhook_fixture_message \
> --fixture=zerver/fixtures/helloworld/helloworld_hello.json \ > --fixture=zerver/fixtures/helloworld/helloworld_hello.json \
> '--url=http://localhost:9991/api/v1/external/helloworld?api_key=<api_key>'</pre> > '--url=http://localhost:9991/api/v1/external/helloworld?api_key=<api_key>'</pre>
</div>
<p>Or, use curl:</p>
<div class="codehilite">
<pre>curl -X POST -H "Content-Type: application/json" -d '{ "featured_title":"Marilyn Monroe", "featured_url":"https://en.wikipedia.org/wiki/Marilyn_Monroe" }' http://localhost:9991/api/v1/external/helloworld\?api_key\=<api_key></pre>
</div>
<p><b>Congratulations! You're done!</b><br /> Your messages may look like:</p>
<img class="screenshot" src="/static/images/integrations/helloworld/001.png" />
</div> </div>
<p>Or, use curl:</p>
<div class="codehilite">
<pre>curl -X POST -H "Content-Type: application/json" -d '{ "featured_title":"Marilyn Monroe", "featured_url":"https://en.wikipedia.org/wiki/Marilyn_Monroe" }' http://localhost:9991/api/v1/external/helloworld\?api_key\=<api_key></pre>
</div>
<p><b>Congratulations! You're done!</b><br /> Your messages may look like:</p>
<img class="screenshot" src="/static/images/integrations/helloworld/001.png" />
``` ```
These documentation blocks should fall alphabetically. For the These documentation blocks should fall alphabetically. For the