mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-03 21:43:21 +00:00 
			
		
		
		
	Currently (https://github.com/rtfd/recommonmark/issues/3) the recommonmark bridge (which allows Sphinx to read Markdown) does not support tables, so the directory structure doc is now a bulleted list instead of a set of tables.
		
			
				
	
	
		
			183 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			183 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
# How to write a new integration
 | 
						|
 | 
						|
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
 | 
						|
getting you integration merged upstream so everyone else can benefit
 | 
						|
from it as easy as possible while maintaining the high quality of the
 | 
						|
Zulip integrations library.
 | 
						|
 | 
						|
Contributions to this guide are very welcome, so if you run into any
 | 
						|
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!
 | 
						|
 | 
						|
## Types of integrations
 | 
						|
 | 
						|
We have several different ways that we integrate with 3rd part
 | 
						|
products, ordered here by which types we prefer to write:
 | 
						|
 | 
						|
1. 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.  For these, you usually just need
 | 
						|
to add a new handler in `zerver/views/webhooks.py` (plus
 | 
						|
test/document/etc.).  An example commit implementing a new webhook is:
 | 
						|
https://github.com/zulip/zulip/pull/324.
 | 
						|
 | 
						|
2. Python script 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 model for these is to
 | 
						|
ship these integrations in our API release tarballs (by writing the
 | 
						|
integration in `api/integrations`).
 | 
						|
 | 
						|
3. 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.
 | 
						|
 | 
						|
## General advice for writing integrations
 | 
						|
 | 
						|
* 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.
 | 
						|
 | 
						|
* 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.
 | 
						|
 | 
						|
* 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.
 | 
						|
 | 
						|
## Writing Webhook integrations
 | 
						|
 | 
						|
New Zulip webhook integrations can take just a few hours to write,
 | 
						|
including tests and documentation, if you use the right process.
 | 
						|
Here's how we recommend doing it:
 | 
						|
 | 
						|
* First, use http://requestb.in/ or a similar site to capture an
 | 
						|
  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/fixtures`.
 | 
						|
 | 
						|
* Then write a draft webhook handler under `zerver/views/webhooks/`;
 | 
						|
  there are a lot of examples in that directory.  We recommend
 | 
						|
  templating off a short one (like `stash.py` or `zendesk.py`), 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 add an entry in
 | 
						|
  `zproject/urls.py` for your webhook; search for `webhook` in that
 | 
						|
  file to find the existing ones (and please add yours in the
 | 
						|
  alphabetically correct place).
 | 
						|
 | 
						|
* Then write a test for your fixture in `zerver/tests/test_hooks.py`, and
 | 
						|
  you can iterate on the tests and webhooks handler until they work,
 | 
						|
  all without ever needing to post directly from the server you're
 | 
						|
  integrating to your Zulip development machine.  To run just the
 | 
						|
  tests from the test class you wrote, you can use e.g.
 | 
						|
 | 
						|
  ```
 | 
						|
  test-backend zerver.tests.test_hooks.PagerDutyHookTests
 | 
						|
  ```
 | 
						|
 | 
						|
  See
 | 
						|
  https://github.com/zulip/zulip/blob/master/README.dev.md#running-the-test-suite
 | 
						|
  for more details on the Zulip test runner.
 | 
						|
 | 
						|
* Once you've gotten your webhook working and passing a test, capture
 | 
						|
  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.
 | 
						|
 | 
						|
* Finally, write documentation for the integration (see below)!
 | 
						|
 | 
						|
## Writing Python script and plugin integrations 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
 | 
						|
`https://zulip.example.com/v1/messages/`, not the legacy
 | 
						|
`/api/v1/send_message` message sending API.
 | 
						|
 | 
						|
* We usually build Python script integration with (at least) 2 files:
 | 
						|
`zulip_foo_config.py`` containing the configuration for the
 | 
						|
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)
 | 
						|
```
 | 
						|
 | 
						|
## Documenting your integration
 | 
						|
 | 
						|
Every Zulip integration must be documented in
 | 
						|
`templates/zerver/integrations.html`.  Usually, this involves a few
 | 
						|
steps:
 | 
						|
 | 
						|
* Add an `integration-lozenge` class block in the alphabetically
 | 
						|
  correct place in the main integration list, using the logo for the
 | 
						|
  integrated software.
 | 
						|
 | 
						|
* Add an `integration-instructions` class block also in the
 | 
						|
  alphabetically correct place, explaining all the steps required to
 | 
						|
  setup the integration, including what URLs to use, etc.  If there
 | 
						|
  are any screens in the product involved, take a few screenshots with
 | 
						|
  the input fields filled out with sample values in order to make the
 | 
						|
  instructions really easy to follow.  For the screenshots, use
 | 
						|
  something like `github-bot@example.com` for the email addresses and
 | 
						|
  an obviously fake API key like `abcdef123456790`.
 | 
						|
 | 
						|
* Finally, generate a message sent by the integration and take a
 | 
						|
  screenshot of the message to provide an example message in the
 | 
						|
  documentation. If your new integration is a webhook integration,
 | 
						|
  you can generate such a message from your test fixtures
 | 
						|
  using `send_webhook_fixture_message`:
 | 
						|
 | 
						|
  ```
 | 
						|
  ./manage.py send_webhook_fixture_message \
 | 
						|
       --fixture=zerver/fixtures/pingdom/pingdom_imap_down_to_up.json \
 | 
						|
       '--url=/api/v1/external/pingdom?stream=stream_name&api_key=api_key'
 | 
						|
  ```
 | 
						|
 | 
						|
  When generating the screenshot of a sample message, give your test
 | 
						|
  bot a nice name like "GitHub Bot", use the project's logo as the
 | 
						|
  bot's avatar, and take the screenshots showing the stream/topic bar
 | 
						|
  for the message, not just the message body.
 | 
						|
 | 
						|
When writing documentation for your integration, be sure to use the
 | 
						|
`{{ external_api_uri }}` template variable, so that your integration
 | 
						|
documentation will provide the correct URL for whatever server it is
 | 
						|
deployed on.  If special configuration is required to set the SITE
 | 
						|
variable, you should document that too, inside an `{% if
 | 
						|
api_site_required %}` check.
 |