2016-06-26 18:49:35 +02:00
|
|
|
# Writing a new integration
|
2016-04-01 08:23:56 +02:00
|
|
|
|
2016-04-11 20:19:54 +02:00
|
|
|
Integrations are one of the most important parts of a group chat tool
|
|
|
|
like Zulip, and we are committed to making integrating with Zulip and
|
2018-01-26 13:37:54 +01:00
|
|
|
getting your integration merged upstream so that everyone else can benefit
|
|
|
|
from it, as easy as possible while maintaining the high quality of the
|
2016-04-11 20:19:54 +02:00
|
|
|
Zulip integrations library.
|
2016-04-01 08:23:56 +02:00
|
|
|
|
2016-08-05 00:10:56 +02:00
|
|
|
On this page you'll find:
|
|
|
|
|
2017-01-15 05:13:22 +01:00
|
|
|
* An overview of the different [types of integrations](#types-of-integrations)
|
2016-08-05 00:10:56 +02:00
|
|
|
possible with Zulip.
|
|
|
|
* [General advice](#general-advice) for writing integrations.
|
|
|
|
* Details about writing [webhook integrations](#webhook-integrations).
|
|
|
|
* Details about writing [Python script and plugin
|
|
|
|
integrations](#python-script-and-plugin-integrations).
|
2017-10-27 00:08:59 +02:00
|
|
|
* A guide to
|
2017-11-16 17:36:52 +01:00
|
|
|
[documenting your integration](integration-docs-guide) is on a
|
2017-10-27 00:08:59 +02:00
|
|
|
separate page.
|
2017-02-06 22:07:45 +01:00
|
|
|
|
|
|
|
A detailed walkthrough of a simple "Hello World" integration can be
|
2017-11-16 17:36:52 +01:00
|
|
|
found in the [webhook walkthrough](webhook-walkthrough).
|
2016-08-05 00:10:56 +02:00
|
|
|
|
2016-04-01 08:23:56 +02:00
|
|
|
Contributions to this guide are very welcome, so if you run into any
|
2016-04-11 20:19:54 +02:00
|
|
|
issues following these instructions or come up with any tips or tools
|
|
|
|
that help writing integration, please email
|
|
|
|
zulip-devel@googlegroups.com, open an issue, or submit a pull request
|
|
|
|
to share your ideas!
|
2016-04-01 08:23:56 +02:00
|
|
|
|
|
|
|
## Types of integrations
|
|
|
|
|
2016-11-16 01:47:38 +01:00
|
|
|
We have several different ways that we integrate with 3rd party
|
2016-04-01 08:23:56 +02:00
|
|
|
products, ordered here by which types we prefer to write:
|
|
|
|
|
2016-10-04 21:21:06 +02:00
|
|
|
1. **[Webhook integrations](#webhook-integrations)** (examples:
|
|
|
|
Freshdesk, GitHub), where the third-party service supports posting
|
|
|
|
content to a particular URI on our site with data about the event.
|
2017-01-26 16:58:23 +01:00
|
|
|
For these, you usually just need to create a new python package in
|
|
|
|
the `zerver/webhooks/` directory. You can easily find recent
|
2018-01-26 13:37:54 +01:00
|
|
|
commits adding new integrations to crib from via
|
|
|
|
`git log zerver/webhooks/`.
|
2016-04-01 08:23:56 +02:00
|
|
|
|
2016-08-05 00:10:56 +02:00
|
|
|
2. **[Python script integrations](#python-script-and-plugin-integrations)**
|
|
|
|
(examples: SVN, Git), where we can get the service to call our integration
|
|
|
|
(by shelling out or otherwise), passing in the required data. Our preferred
|
2017-08-01 01:25:35 +02:00
|
|
|
model for these is to ship these integrations in the
|
|
|
|
[Zulip Python API distribution](https://github.com/zulip/python-zulip-api/tree/master/zulip),
|
|
|
|
within the `integrations` directory there.
|
2016-04-01 08:23:56 +02:00
|
|
|
|
2016-08-05 00:10:56 +02:00
|
|
|
3. **[Plugin integrations](#python-script-and-plugin-integrations)** (examples:
|
|
|
|
Jenkins, Hubot, Trac) where the user needs to install a plugin into their
|
|
|
|
existing software. These are often more work, but for some products are the
|
|
|
|
only way to integrate with the product at all.
|
2016-04-01 08:23:56 +02:00
|
|
|
|
2016-08-05 00:10:56 +02:00
|
|
|
## General advice
|
2016-04-01 08:23:56 +02:00
|
|
|
|
|
|
|
* Consider using our Zulip markup to make the output from your
|
|
|
|
integration especially attractive or useful (e.g. emoji, markdown
|
|
|
|
emphasis, @-mentions, or `!avatar(email)`).
|
|
|
|
|
|
|
|
* Use topics effectively to ensure sequential messages about the same
|
|
|
|
thing are threaded together; this makes for much better consumption
|
|
|
|
by users. E.g. for a bug tracker integration, put the bug number in
|
|
|
|
the topic for all messages; for an integration like Nagios, put the
|
|
|
|
service in the topic.
|
|
|
|
|
|
|
|
* Integrations that don't match a team's workflow can often be
|
|
|
|
uselessly spammy. Give careful thought to providing options for
|
|
|
|
triggering Zulip messages only for certain message types, certain
|
|
|
|
projects, or sending different messages to different streams/topics,
|
|
|
|
to make it easy for teams to configure the integration to support
|
|
|
|
their workflow.
|
|
|
|
|
2016-05-12 06:12:02 +02:00
|
|
|
* Consistently capitalize the name of the integration in the
|
|
|
|
documentation and the Client name the way the vendor does. It's OK
|
|
|
|
to use all-lower-case in the implementation.
|
|
|
|
|
2016-04-01 08:23:56 +02:00
|
|
|
* Sometimes it can be helpful to contact the vendor if it appears they
|
|
|
|
don't have an API or webhook we can use -- sometimes the right API
|
|
|
|
is just not properly documented.
|
|
|
|
|
2016-05-20 19:38:46 +02:00
|
|
|
* A helpful tool for testing your integration is
|
|
|
|
[UltraHook](http://www.ultrahook.com/), which allows you to receive webhook
|
2016-11-29 23:23:54 +01:00
|
|
|
calls via your local Zulip development environment. This enables you to do end-to-end
|
2016-05-20 19:38:46 +02:00
|
|
|
testing with live data from the service you're integrating and can help you
|
|
|
|
spot why something isn't working or if the service is using custom HTTP
|
|
|
|
headers.
|
|
|
|
|
2016-08-05 00:10:56 +02:00
|
|
|
## Webhook integrations
|
2016-04-01 08:23:56 +02:00
|
|
|
|
2016-11-14 18:12:42 +01:00
|
|
|
A webhook allows a third-party service to push data to you when something
|
|
|
|
happens. It's different from making a REST API call, where you send a request
|
|
|
|
to the service's API and wait for a response. With a webhook, the third-party
|
|
|
|
service sends you an HTTP POST when it has something for you. Your webhook
|
|
|
|
integration defines the URI the service uses to communicate with Zulip, and
|
|
|
|
handles that incoming data.
|
|
|
|
|
2016-04-01 08:23:56 +02:00
|
|
|
New Zulip webhook integrations can take just a few hours to write,
|
|
|
|
including tests and documentation, if you use the right process.
|
2017-08-22 14:47:18 +02:00
|
|
|
|
|
|
|
**For detailed instructions, check out the ["Hello World" webhook walkthrough](
|
2017-11-16 17:36:52 +01:00
|
|
|
webhook-walkthrough)**.
|
2017-08-22 14:47:18 +02:00
|
|
|
|
|
|
|
For a quick guide, read on.
|
2016-04-01 08:23:56 +02:00
|
|
|
|
2017-03-19 13:07:57 +01:00
|
|
|
* First, use <http://requestb.in/> or a similar site to capture an
|
2018-03-01 17:20:02 +01:00
|
|
|
example webhook payload from the service you're integrating. You
|
|
|
|
can use these captured payloads to create a set of test fixtures
|
|
|
|
for your integration under `zerver/webhooks/mywebhook/fixtures/`.
|
|
|
|
|
|
|
|
* Then write a draft webhook handler under `zerver/webhooks/`; there
|
|
|
|
are a lot of examples in that directory. We recommend templating
|
|
|
|
off a short one (like `stash` or `zendesk`), since the longer ones
|
|
|
|
usually just have more complex parsing which can obscure what's
|
|
|
|
common to all webhook integrations. In addition to writing the
|
|
|
|
integration itself, you'll need to create `Integration` object and
|
|
|
|
add it to `WEBHOOK_INTEGRATIONS` in `zerver/lib/integrations.py;`
|
|
|
|
search for `webhook` in that file to find the existing ones (and
|
|
|
|
please add yours in the alphabetically correct place).
|
2016-04-01 08:23:56 +02:00
|
|
|
|
2017-01-26 16:58:23 +01:00
|
|
|
* Then write a test for your fixture in the `tests.py` file in the
|
2018-03-01 17:20:02 +01:00
|
|
|
`zerver/webhooks/mywebhook` directory. You can now iterate on
|
|
|
|
debugging the tests and webhooks handler until they work, all
|
|
|
|
without ever needing to post directly from the service you're
|
|
|
|
integrating with to your Zulip development machine. You can run
|
|
|
|
just the tests for one integration like this:
|
|
|
|
|
|
|
|
```
|
|
|
|
test-backend zerver/webhooks/pagerduty/
|
|
|
|
```
|
|
|
|
|
|
|
|
*Hint: See
|
|
|
|
[this guide](https://zulip.readthedocs.io/en/latest/testing/testing.html)
|
|
|
|
for more details on the Zulip test runner.*
|
2016-04-01 08:23:56 +02:00
|
|
|
|
|
|
|
* Once you've gotten your webhook working and passing a test, capture
|
2018-03-01 17:20:02 +01:00
|
|
|
payloads for the other common types of posts the service's webhook
|
|
|
|
will make, and add tests for them; usually this part of the
|
|
|
|
process is pretty fast. Webhook integration tests should all use
|
|
|
|
fixtures (as opposed to contacting the service), since otherwise
|
|
|
|
the tests can't run without Internet access and some sort of
|
|
|
|
credentials for the service.
|
2016-04-01 08:23:56 +02:00
|
|
|
|
2016-08-04 20:49:17 +02:00
|
|
|
* Finally, write documentation for the integration; there's a
|
2017-11-16 17:36:52 +01:00
|
|
|
[detailed guide](integration-docs-guide).
|
2016-04-01 08:23:56 +02:00
|
|
|
|
2016-05-20 19:38:46 +02:00
|
|
|
### Files that need to be created
|
|
|
|
|
|
|
|
Select a name for your webhook and use it consistently. The examples below are
|
|
|
|
for a webhook named 'MyWebHook'.
|
|
|
|
|
2017-10-27 00:03:52 +02:00
|
|
|
* `static/images/integrations/logos/mywebhook.svg`: An image to represent
|
|
|
|
your integration in the user interface. Generally this should be the logo of the
|
2016-05-20 19:38:46 +02:00
|
|
|
platform/server/product you are integrating. See [Documenting your
|
2017-11-16 17:36:52 +01:00
|
|
|
integration](integration-docs-guide) for details.
|
2017-10-27 00:03:52 +02:00
|
|
|
* `static/images/integrations/mywebbook/001.svg`: A screen capture of your
|
2016-05-20 19:38:46 +02:00
|
|
|
integration for use in the user interface. You can add as many images as needed
|
|
|
|
to effectively document your webhook integration. See [Documenting your
|
2017-11-16 17:36:52 +01:00
|
|
|
integration](integration-docs-guide) for details.
|
2017-05-14 00:52:40 +02:00
|
|
|
* `zerver/webhooks/mywebhook/fixtures/messagetype.json`: Sample json payload data
|
2016-05-20 19:38:46 +02:00
|
|
|
used by tests. Add one fixture file per type of message supported by your
|
2017-11-16 17:36:52 +01:00
|
|
|
integration. See [Testing and writing tests](
|
|
|
|
https://zulip.readthedocs.io/en/latest/testing/testing.html) for details.
|
2017-01-26 16:58:23 +01:00
|
|
|
* `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
|
2016-05-20 19:38:46 +02:00
|
|
|
function including any needed helper functions.
|
2017-01-26 16:58:23 +01:00
|
|
|
* `zerver/webhooks/mywebhook/tests.py`: Add tests for your
|
2017-11-16 17:36:52 +01:00
|
|
|
webbook. See [Testing and writing tests](
|
|
|
|
https://zulip.readthedocs.io/en/latest/testing/testing.html) for details.
|
2017-01-26 16:58:23 +01:00
|
|
|
* `zerver/webhooks/mywebhook/doc.html`: Add end-user documentation. See
|
2017-11-16 17:36:52 +01:00
|
|
|
[Documenting your integration](integration-docs-guide) for details.
|
2016-05-20 19:38:46 +02:00
|
|
|
|
2016-08-04 20:53:05 +02:00
|
|
|
### Files that need to be updated
|
|
|
|
|
|
|
|
* `zerver/lib/integrations.py`: Add your integration to
|
|
|
|
`WEBHOOK_INTEGRATIONS` to register it. This will automatically
|
|
|
|
register a url for the webhook of the form `api/v1/external/mywebhook`
|
|
|
|
and associate with the function called `api_mywebhook_webhook` in
|
2017-01-26 16:58:23 +01:00
|
|
|
`zerver/webhooks/mywebhook/view.py`.
|
2016-08-04 20:53:05 +02:00
|
|
|
|
2016-08-05 00:16:30 +02:00
|
|
|
## Python script and plugin integrations
|
|
|
|
|
|
|
|
For plugin integrations, usually you will need to consult the
|
|
|
|
documentation for the third party software in order to learn how to
|
|
|
|
write the integration. But we have a few notes on how to do these:
|
|
|
|
|
|
|
|
* You should always send messages by POSTing to URLs of the form
|
2016-09-27 21:41:42 +02:00
|
|
|
`https://zulip.example.com/v1/messages/`.
|
2016-08-05 00:16:30 +02:00
|
|
|
|
|
|
|
* We usually build Python script integration with (at least) 2 files:
|
2017-01-04 17:58:29 +01:00
|
|
|
`zulip_foo_config.py` containing the configuration for the
|
2016-08-05 00:16:30 +02:00
|
|
|
integration including the bots' API keys, plus a script that reads
|
|
|
|
from this configuration to actually do the work (that way, it's
|
|
|
|
possible to update the script without breaking users' configurations).
|
|
|
|
|
|
|
|
* Be sure to test your integration carefully and document how to
|
|
|
|
install it (see notes on documentation below).
|
|
|
|
|
|
|
|
* You should specify a clear HTTP User-Agent for your integration. The
|
|
|
|
user agent should at a minimum identify the integration and version
|
|
|
|
number, separated by a slash. If possible, you should collect platform
|
|
|
|
information and include that in `()`s after the version number. Some
|
|
|
|
examples of ideal UAs are:
|
|
|
|
|
|
|
|
```
|
|
|
|
ZulipDesktop/0.7.0 (Ubuntu; 14.04)
|
|
|
|
ZulipJenkins/0.1.0 (Windows; 7.2)
|
|
|
|
ZulipMobile/0.5.4 (Android; 4.2; maguro)
|
|
|
|
```
|