zulip/templates/zerver/integrations.html

1236 lines
58 KiB
HTML

{% extends "zerver/portico.html" %}
{% block customhead %}
{{ super() }}
<meta name="viewport" content="width=device-width, initial-scale=1.0">
{% stylesheet 'portico' %}
{% stylesheet 'landing-page' %}
{{ minified_js('landing-page')|safe }}
{% endblock %}
{% block hello_page_container %} hello-main{% endblock %}
{% block hello_page_footer %} hello-footer{% endblock %}
{% block os_announcement %}
{% if show_oss_announcement %}
<div class="os-headline-container">
<img src="/static/images/logo/zballoon.png" class="os-illustration" alt="Zulip balloon" />
<div class="main-headline-text">
<span class="tagline os-tagline">
{{ _('Zulip has been released as open source software!') }}
</span>
<span class="footnote os-footnote">
{% trans %}Read the <a href="https://blogs.dropbox.com/tech/2015/09/open-sourcing-zulip-a-dropbox-hack-week-project" target="_blank">announcement</a> or go to <a href="https://www.zulip.org" target="_blank">the Zulip open source project website</a>.{% endtrans %}
</span>
</div>
</div>
{% endif %}
{% endblock %}
{% block portico_content %}
{% include 'zerver/landing_nav.html' %}
<div class="portico-landing integrations">
<div class="main">
<div class="padded-content">
<div class="inner-content">
<div class="portico-page-header"><a href="#" class="no-style"><i class="icon-vector-gears portico-page-header-icon"></i>Integrations</a></div>
<div id="integration-main-text">
<p>With Zulip integrations, your team
can stay up-to-date on code changes, issue tickets, build system
results, tweets about your project, and much more.</p>
<p>Many of these integrations require creating a Zulip bot. You
can do so on your {{ settings_html|safe }}. Be
sure to note its username and API key.</p>
<p>If an integration you want isn't available yet, you
can <a href="http://zulip.readthedocs.io/en/latest/integration-guide.html">contribute
an integration</a>
or <a href="https://github.com/zulip/zulip/issues/new">open an
issue on GitHub</a> and tag it with the "integrations" label
(so you can get notified when that integration becomes
available).</p>
</div>
<div id="integration-instruction-block" class="integration-instruction-block">
<a href="#" id="integration-list-link"><i class="icon-vector-circle-arrow-left"></i><span>Back to list</span></a>
</div>
<div class="integration-lozenges">
{% for integration in integrations_dict.values() %}
{% if integration.is_enabled() %}
<div class="integration-lozenge integration-{{ integration.name }}">
<a class="integration-link integration-{{ integration.name }}" href="#{{ integration.name }}">
<img class="integration-logo" src="/{{ integration.logo }}" alt="{{ integration.display_name }} logo" />
{% if integration.secondary_line_text %}
<span class="integration-label" style="padding-top: 0px; padding-bottom: 0px;">{{ integration.display_name }}</span>
<span class="integration-label-secondary">{{ integration.secondary_line_text }}</span>
{% else %}
<span class="integration-label">{{ integration.display_name}}</span>
{% endif %}
</a>
</div>
{% endif %}
{% endfor %}
</div>
<div class="portico-page-header extra" id="hubot-integrations"><a href="#" class="no-style"><i class="icon-vector-gears portico-page-header-icon"></i>Integrations available via Hubot</a></div>
<p class="extra">The official <a class="integration-link integration-hubot" href="#hubot"><span class="integration-label">Hubot</span></a>
integration provides an extension point for additional Zulip integrations. </p><p class="extra"> A non-comprehensive list of integrations available through
<a class="integration-link integration-hubot" href="#hubot"><span class="integration-label">Hubot</span></a> follows below:</p>
<div class="integration-lozenges">
{% for integration in hubot_lozenges_dict.values() %}
<div class="integration-lozenge integration-{{ integration.name }}">
<a class="integration-link integration-{{ integration.name }}" href="{{ integration.git_url }}">
<img class="integration-logo" src="/{{ integration.logo }}" alt="{{ integration.logo_alt }} logo" />
<span class="integration-label">{{ integration.display_name}}</span>
</a>
</div>
{% endfor %}
</div>
<div id="integration-instructions-group">
{% for integration in integrations_dict.values() %}
{% if integration.is_enabled() %}
{% if integration.doc %}
<div id={{ integration.name }} class="integration-instructions">
{% include integration.doc %}
</div>
{% endif %}
{% endif %}
{% endfor %}
<div id="asana" class="integration-instructions">
<p>Get Zulip notifications for your Asana tasks!</p>
<p>First, create the stream you'd like to use for Asana notifications, and
subscribe all interested parties to this stream. We recommend the
name <code>asana</code>.</p>
<p>Next, on your {{ settings_html|safe }}, create an Asana bot. Please note the bot name and API key.</p>
<p>Then:</p>
<ol>
<li>
<p>Download and install our <a href="/api">Python bindings</a> on the
server where the Asana mirroring script will live. The Asana
integration will be installed to a location
like <code>/usr/local/share/zulip/integrations/asana/</code>.</p>
</li>
<li>
<p>Visit your <a href="https://app.asana.com/-/account_api">Asana
account settings page</a> and retrieve your API key.</p>
<p>Edit <code>asana/zulip_asana_config.py</code> and
change the following lines to configure the integration:</p>
<div class="codehilite">
<pre>
<span class="n">ASANA_API_KEY</span> <span class="o">=</span> <span class="s">0123456789abcdef0123456789abcdef</span>
<span class="n">ZULIP_USER</span> <span class="o">=</span> <span class="s">"asana-bot@example.com"</span>
<span class="n">ZULIP_API_KEY</span> <span class="o">=</span> <span class="s">"0123456789abcdef0123456789abcdef"</span>
{% if api_site_required %}<span class="n">ZULIP_SITE</span> <span class="o">=</span> <span class="s">"{{ external_api_uri_subdomain }}"</span>{% endif %}</pre>
</div>
<p>If you are using a stream other than <code>asana</code>,
set <code>ZULIP_STREAM_NAME</code> to the chosen stream name.</p>
</li>
<li>
<p>Test your configuration by running the mirror with
<code>asana/zulip_asana_mirror</code>. It will print
some informational messages and process any recently created
or completed tasks.</p>
</li>
<li>
<p>This mirror is intended to be a long-running processing and should be
hooked into your infrastructure for keeping services running (for
example, auto-restarting through <code>supervisord</code>).</p>
<p>Please
contact <a href="mailto:zulip-devel@googlegroups.com?subject=Asana%20integration%20question">zulip-devel@googlegroups.com</a>
if you'd like assistance with maintaining this integration.
</p>
</li>
</ol>
<p><b>Congratulations! You're done!</b><br /> When team members create and
complete tasks in Asana, you'll get a Zulip notification that looks like
this:</p>
<img class="screenshot" src="/static/images/integrations/asana/001.png" />
</div>
<div id="basecamp" class="integration-instructions">
<p>First, create the stream you'd like to use for Basecamp notifications,
and subscribe all interested parties to this stream. We recommend the
name <code>basecamp</code>.</p>
<p>Next, download and install our <a href="/api">Python
bindings and example scripts</a> on the computer you'd like to run this mirroring script from.</p>
<p>You will need your Basecamp account ID. You can find it as a sequence of numbers in the URL when you log in:</p>
<img class="screenshot" src="/static/images/integrations/basecamp/001.png" />
<p>Edit the Basecamp and Zulip credentials in <code>integrations/basecamp/zulip_basecamp_config.py</code> using
your favorite editor:</p>
<div class="codehilite">
<pre><span class="n">BASECAMP_ACCOUNT_ID</span> <span class="o">=</span> <span class="s">"1234567"</span>
<span class="n">BASECAMP_USERNAME</span> <span class="o">=</span> <span class="s">"foo@example.com"</span>
<span class="n">BASECAMP_PASSWORD</span> <span class="o">=</span> <span class="s">"p455w0rd"</span>
<span class="n">ZULIP_USER</span> <span class="o">=</span> <span class="s">"basecamp-bot@example.com"</span>
<span class="n">ZULIP_API_KEY</span> <span class="o">=</span> <span class="s">"0123456789abcdef0123456789abcdef"</span>
{% if api_site_required %}<span class="n">ZULIP_SITE</span> <span class="o">=</span> <span class="s">"{{ external_api_uri_subdomain }}"</span>{% endif %}</pre>
</div>
<p>Before your first run of the script, you may optionally choose to
configure it to mirror some number of hours of Basecamp activity:</p>
<div class="codehilite">
<pre><span class="n">BASECAMP_INITIAL_HISTORY_HOURS</span> <span class="o">=</span> <span class="s">10</span></pre>
</div>
<p>Now, simply run the <code>api/integrations/basecamp/zulip_basecamp_mirror</code> script.
If needed, this script may be restarted, and it will automatically resume from when
it was last running.</p>
<p><b>Congratulations! You're done!</b><br /> Whenever you create a new project,
calendar event, comment, message, or more, you'll get a notification in your selected stream
with the project or calendar as the topic.</p>
<img class="screenshot" src="/static/images/integrations/basecamp/002.png" />
</div>
<div id="capistrano" class="integration-instructions">
<p>First, download and install our <a href="/api">Python
bindings and example scripts</a> on your Capistrano server.
Once you've done that, you'll use the <code>zulip-send</code>
utility to notify you when certain events happen.</p>
<p>Here's some example code for sending a Zulip notification
after a deployment has completed:</p>
<div class="codehilite"><pre><span class="n">after</span> <span class="s1">'deploy'</span><span class="p">,</span> <span class="s1">'notify:humbug'</span>
<span class="n">namespace</span> <span class="ss">:notify</span> <span class="k">do</span>
<span class="n">desc</span> <span class="s2">"Post a message to Zulip that we've deployed"</span>
<span class="n">task</span> <span class="ss">:humbug</span> <span class="k">do</span>
<span class="c1"># this will post to Zulip as the user defined in
# ~/.zuliprc if you omit --user and --api-key</span>
<span class="n">run_locally</span> <span class="s2">"echo ':beers: I just deployed to </span><span class="si">#{</span><span class="n">stage</span><span class="si">}</span><span class="s2">! :beers:' | zulip-send \
--user capistrano-bot@example.com --api-key a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5 \
{% if api_site_required %} --site={{ external_api_uri_subdomain }} \
{% endif %} --stream commits --subject deployments || true"</span>
<span class="k">end</span>
<span class="k">end</span>
</pre></div>
<p>Some notes:</p>
<ul>
<li>If you prefer not to use <code>--user</code> and <code>--api-key</code> above, you can fill out <code>~/.zuliprc</code> on your Capistrano
machine. For instructions on how to write that file, see <a href="/api">the API page</a>.</li>
<li>You may need to change the <code>deploy</code> above to
another step of your deployment process, if you'd like the
notification to fire at a different time.</li>
</ul>
<em></em>
<p><b>Congratulations! You're done!</b><br /> Whenever you do a
deployment, you'll get an automated notification that looks like
this:</p>
<img class="screenshot" src="/static/images/integrations/capistrano/001.png" />
<p><small>Thanks to Wes of TurboVote for <a href="https://gist.github.com/cap10morgan/5100822">submitting this integration</a>!</small></p>
</div>
<div id="codebase" class="integration-instructions">
<p>First, create the streams you'd like to use for Codebase notifications. There will be two types of
messages: commit-related updates and issue-related updates. After creating these streams (we suggest naming
them <code>codebase commits</code> and <code>codebase issues</code>), make sure to subscribe all interested parties.</p>
<p>Next, download and install our <a href="/api">Python
bindings and example scripts</a> on the computer you'd like to run this mirroring script from.</p>
<p>You will need your Codebase API Username. You can find it in the settings page of your account, under
<code>API Credentials</code>.</p>
<p>Edit the Codebase and Zulip credentials in <code>integrations/codebase/zulip_codebase_config.py</code> using
your favorite editor:</p>
<div class="codehilite">
<pre><span class="n">CODEBASE_API_USERNAME</span> <span class="o">=</span> <span class="s">"zulip-inc/leo-franchi-15"</span>
<span class="n">CODEBASE_API_KEY</span> <span class="o">=</span> <span class="s">0123456789abcdef0123456789abcdef</span>
<span class="n">ZULIP_USER</span> <span class="o">=</span> <span class="s">"codebase-bot@example.com"</span>
<span class="n">ZULIP_API_KEY</span> <span class="o">=</span> <span class="s">"0123456789abcdef0123456789abcdef"</span>
{% if api_site_required %}<span class="n">ZULIP_SITE</span> <span class="o">=</span> <span class="s">"{{ external_api_uri_subdomain }}"</span>{% endif %}</pre>
</div>
<p>Before your first run of the script, you may optionally choose to
configure it to mirror some number of hours of prior Codebase activity:</p>
<div class="codehilite">
<pre><span class="n">CODEBASE_INITIAL_HISTORY_HOURS</span> <span class="o">=</span> <span class="s">10</span></pre>
</div>
<p>Now, simply run the <code>api/integrations/codebase/zulip_codebase_mirror</code> script.
If needed, this script may be restarted, and it will automatically resume from when
it was last running.</p>
<p><b>Congratulations! You're done!</b><br /> Whenever you create a new project,
commit, issue, deployment, or more, you'll get notifications in your selected streams
with the associated information.</p>
<img class="screenshot" src="/static/images/integrations/codebase/001.png" />
</div>
{% if email_integration_enabled %}
<div id="email" class="integration-instructions">
<p>You can send emails to Zulip! This is useful:</p>
<ul>
<li>If you use a service that can send emails but does not easily lend
itself to more direct integration</li>
<li>If you have an email that you want to discuss on Zulip</li>
<li>As a structured, searchable, commentable archive for mailing list
traffic</li>
</ul>
<p>To send an email to a Zulip stream:</p>
<ol>
<li>Visit your {{ subscriptions_html|safe }} and click on the stream row to expand it.</li>
<li>Copy the stream email address
(e.g. <code>{{ email_gateway_example }}</code>). If the stream
name contains special characters, we've transformed the name so it is a
safe email recipient.</li>
<li>Send an email (To, CC, and BCC all work) to the stream email
address. The email subject will become the stream topic, and the email
body will become the Zulip message content.</li>
</ol>
<p>Please note that it may take up to one minute for the message to show up
in Zulip.</p>
</div>
{% endif %}
<div id="git" class="integration-instructions">
<p>First, download and install our <a href="/api">Python
bindings and example scripts</a> on your Git server.</p>
<p>Next, create the stream you'd like to use for Git notifications, and
subscribe all interested parties to this stream. The integration will use
the default stream <code>commits</code> if no stream is supplied in the
hook; you still need to create the stream even if you are using this
default.</p>
<p>Next, open <code>integrations/git/zulip_git_config.py</code>
in your favorite editor, and change the following lines to
specify the email address and API key for your Git bot:</p>
<div class="codehilite"><pre><span class="n">ZULIP_USER</span> <span class="o">=</span> <span class="s">"git-bot@example.com"</span>
<span class="n">ZULIP_API_KEY</span> <span class="o">=</span> <span class="s">"0123456789abcdef0123456789abcdef"</span>
{% if api_site_required %}<span class="n">ZULIP_SITE</span> <span class="o">=</span> <span class="s">"{{ external_api_uri_subdomain }}"</span>{% endif %}</pre></div>
<p>You can also specify which pushes will result in
notifications and to what stream the notifications will be sent
by modifying the <code>commit_notice_destination</code> function
in <code>zulip_git_config.py</code>. By default, pushes to
the <code>master</code> and <code>test-post-receive</code>
branches will result in a notification to
stream <code>commits</code>.</p>
<p>Save <code>integrations/git/zulip_git_config.py</code> to
the <code>.git/hooks</code> directory of your git
repository.</p>
<p>Symlink
<code>/usr/local/share/zulip/integrations/git/post-receive</code>
into the <code>.git/hooks</code> directory of your git repository.</p>
<p><b>Congratulations! You're done!</b><br /> Whenever you make
a push to the <code>master</code> branch of your git repository
(or whatever you configured above), the Zulip git plugin will
send an automated notification that looks like this:</p>
<img class="screenshot" src="/static/images/integrations/git/001.png" />
<p><b>Testing</b><br />You can test the plugin without changing
your <code>master</code> branch by pushing to
the <code>test-post-receive</code> branch.</p>
</div>
<div id="google-calendar" class="integration-instructions">
<p>
Get Google Calendar reminders in Zulip! This is a great way to see your reminders directly in
your Zulip feed.
</p>
<p>
First download and install our <a href="/api">Python Bindings and example scripts</a>.
This bot should be set up on a trusted machine, because your API key is visible to local users
through the command line or config file.
</p>
<p>
Next, follow the instructions for <b>Step 1</b> at
<a href="https://developers.google.com/google-apps/calendar/quickstart/python">this link</a>
to get a <code>client_secret</code> file. Save this file as <code>client_secret.json</code>
to your <code>~/</code> directory.
</p>
<p>
Next, install the latest Google API Client for Python by following the instructions on
the <a href="https://developers.google.com/api-client-library/python/start/installation">
Google Website</a>.
</p>
<p>
Then go to your <b>Zulip Settings</b> by clicking on the cog in the top right corner,
and then clicking on <b>Settings</b>.
</p>
<p>
Click on the tab that's labeled <b>Your bots</b> and click on <b>Show/change your API
key</b>. Enter your password if prompted, and download the <code>zuliprc</code> file. Save
this file as <code>.zuliprc</code> to your <code>~/</code> directory.
</p>
<p><img class="screenshot" src="/static/images/integrations/google/calendar/001.png" /></p>
<p>
Run the <code>get-google-credentials</code> with this command:
<pre>python /usr/local/share/zulip/integrations/google/get-google-credentials</pre>
It should open up a browser and ask you for certain permissions. Give Zulip access, and move
on to the next step. If it doesn't open a browser, follow the instructions in the terminal
window.
</p>
<p>
Now, all that's left to do is to run the <code>gcal-bot</code> script, in the same
directory as the <code>get-google-credentials</code> script, with the necessary paramaters:
<pre>python /usr/local/share/zulip/integrations/google/gcal-bot --user foo@zulip.com</pre>
</p>
<p>
The <code>--user</code> flag specifies the user to send the reminder to. <br />There are
two optional flags that you can specify when running this script:
</p>
<ol>
<li>
<code>--calendar</code>: This flag specifies the calendar to watch from the user's
Google Account. By default, this flag is set to a user's primary or default calendar.
To specify a calendar, you need the calendar ID which can be obtained by going to Google
Calendar and clicking on the wedge next to the calendar's name. Click on settings in
<b>Calendar settings</b> in the drop down, and look for the <b>Calendar Address</b>
section. Copy the <b>Calendar ID</b> from the right side of the page and use that as the
value for this flag.
<p><img class="screenshot" src="/static/images/integrations/google/calendar/002.png"/></p>
</li>
<li>
<code>--interval</code>: This flag specifies the interval of time - in minutes - between
receiving the reminder, and the actual event. For example, an interval of 30 minutes
would mean that you would receive a reminder for an event 30 minutes before it is
scheduled to occur.
</li>
</ol>
<p>
Don't close the terminal window with the bot running. You will only get reminders if the
bot is still running.</p>
<p>
<b>Congratulations! You're done!</b><br />You will get a Zulip private message, whenever you
have a calendar event scheduled, that looks like this:
<img class="screenshot" src="/static/images/integrations/google/calendar/003.png" />
</p>
</div>
<div id="hubot" class="integration-instructions">
<ol>
<li><p>Follow the "Getting Started with Hubot" section of the <a href="https://hubot.github.com/docs/#getting-started-with-hubot">Hubot README</a> to create your Hubot. You'll have a new directory from which <code>bin/hubot</code> starts a vanilla Hubot instance with the shell backend.</p></li>
<li>In your Hubot's directory, install the Zulip adapter. Run:
<pre><code>npm install --save hubot-zulip</code></pre>
</li>
<li><p>On your {{ settings_html|safe }}, create a bot account. Note its username, API key and full name; you will use them on the next step.</p></li>
<li>To run Hubot locally, use:
<pre><code>HUBOT_ZULIP_SITE={{ external_api_path_subdomain }} HUBOT_ZULIP_BOT=hubot-bot@example.com HUBOT_ZULIP_API_KEY=your_key bin/hubot --adapter zulip --name "myhubot"</code></pre>
</li>
</ol>
<p>The bot account email address and API key are passed to Hubot via environment variables <code>HUBOT_ZULIP_BOT</code> and <code>HUBOT_ZULIP_API_KEY</code>. The <code>--name</code> parameter must match the name you gave the bot on the settings page.</p>
<p>
Hubot will automatically listen for commands on all public streams. You can also invite Hubot to invite-only streams.
</p>
<p>
To test your Hubot installation, send it an @-notification with a basic command, for example <code>@Hubot pug me</code>, which should produce a result like this:
</p>
<img class="screenshot" src="/static/images/integrations/hubot/001.png" />
<p><a href='https://github.com/zulip/hubot-zulip'>Source code for the hubot-zulip adapter is available on GitHub</a>.</p>
<p><a href="#hubot-integrations">Check out additional Zulip integrations available via Hubot</a></p>
</div>
<div id="jenkins" class="integration-instructions">
<p>First, create the stream you'd like to use for Jenkins or Hudson
notifications, and subscribe all interested parties to this stream. We
recommend the name <code>jenkins</code> or <code>hudson</code>.</p>
<p><strong>Install the plugin</strong><br /> Install the "Zulip"
plugin by going to
<code>Manage Jenkins > Manage Plugins > Available</code>,
typing in "Zulip", and clicking "Install without
restart". (For historical reasons, the plugin might be named
"Humbug Plugin" in some places)</p>
<img class="screenshot" src="/static/images/integrations/jenkins/001.png" />
<p><strong>Configure the plugin</strong><br /> Once the plugin
is installed, configure it by going to
<code>Manage Jenkins > Configure System</code>. Scroll to the
section labeled "Zulip Notification Settings", and specify your
bot's email address, API key, the stream receiving the
notifications, and whether you'd like a notification on every
build, or only when the build fails (Smart Notification).</p>
<p>(If you don't see this option, you may first need to restart
Jenkins.)</p>
<img src="/static/images/integrations/jenkins/002.png" />
<p><strong>Configure a post-build action for your project</strong><br />
Once you've done that, it's time to configure one of your
projects to use the Zulip notification plugin. From your
project page, click "Configure" on the left sidebar. Scroll to
the bottom until you find the section labeled "Post-build
Actions". Click the dropdown and select "Zulip
Notification". It should look as below. Then click "Save".</p>
<img src="/static/images/integrations/jenkins/003.png" />
<p><b>Congratulations! You're done!</b><br /> When your builds
fail or succeed, you'll see a commit message like the following
with a topic that matches the project name (in this case
"SecretProject"):</p>
<img class="screenshot" src="/static/images/integrations/jenkins/004.png" />
<p><b>Troubleshooting</b><br />
<ul>
<li>Did you set up a post-build action for your project?</li>
<li>Does the stream you picked (e.g. <code>jenkins</code>) already exist? If not, add yourself to it and try again.</li>
<li>Are your access key and email address correct? Test them using <a href="/api">our curl API</a>.</li>
<li>Still stuck? Email <a href="mailto:zulip-devel@googlegroups.com?subject=Jenkins">zulip-devel@googlegroups.com</a>.</li>
</ul>
</p>
</div>
<div id="jira-plugin" class="integration-instructions">
<p><em>If you are running JIRA version 5.2 or greater, or using the
hosted JIRA provided by Atlassian, we recommend using the <a
href="#jira">web-hook method</a> above instead. This plugin
supports older versions of JIRA.</em></p>
<p>First, create the stream you'd like to use for JIRA notifications, and
subscribe all interested parties to this stream. We recommend the
name <code>jira</code>.</p>
<h5>Plugin mechanism</h5>
Next, download and install our <a href="/api">Python bindings and example scripts</a>.
<p><b>Plugin Installation</b></p>
The JIRA integration plugin requires two JIRA plugins. Please install
the following plugins using the Universal Plugin Manager in your JIRA
installation:
<ul>
<li><a href="https://marketplace.atlassian.com/plugins/com.onresolve.jira.groovy.groovyrunner">Script Runner Plugin</a></li>
<li><a href="https://marketplace.atlassian.com/plugins/com.atlassian.jira.plugin.jirasslplugin">SSL Plugin</a></li>
</ul>
<p><b>SSL Setup</b></p>
As Zulip is using a StartCOM SSL certificate that is not recognized by default in the Java installation shipped with JIRA,
you will need to tell JIRA about the certificate. Navigate to <code>Administration > System > Configure SSL</code> and in
the <code>Import SSL Certificates</code> field, enter <code>{{ external_api_uri_subdomain }}</code>. After clicking <code>Save Certificates</code>,
follow the on-screen instructions and restart JIRA for it to recognize the proper certificates.
<p><b>Zulip Integration</b></p>
Copy the folder <code>integrations/jira/org/</code> (from the tarball you downloaded above) to your JIRA <code>classes</code> folder.
For self-contained JIRA installations, this will be <code>atlassian-jira/WEB-INF/classes/</code>, but this may be different in your deployment.
Edit the constants at the top of <code>org/zulip/jira/ZulipListener.groovy</code>
and fill them with the appropriate values:
<div class="codehilite"><pre><span class="n">String</span> <span class="n">zulipEmail</span> <span class="o">=</span> <span class="s2">"jira-notifications-bot@example.com"</span>
<span class="n">String</span> <span class="n">zulipAPIKey</span> <span class="o">=</span> <span class="s2">"0123456789abcdef0123456789abcdef"</span>
<span class="n">String</span> <span class="n">zulipStream</span> <span class="o">=</span> <span class="s2">"JIRA"</span>
<span class="n">String</span> <span class="n">issueBaseUrl</span> <span class="o">=</span> <span class="s2">"https://jira.COMPANY.com/browse/"</span>
</pre></div>
<p>In the Administrators page, navigate to <code>Plugins > Other > Script Listeners</code>. In the <code>Add Listener</code> section, click on
the <code>Custom Listener</code> option. Select the events you wish the Zulip integration to fire for, and the projects you wish Zulip to be notified for.
In the <code>Name of groovy class</code> field, enter <code>org.zulip.jira.ZulipListener</code>.
</p>
<p>Click <code>Add Listener</code>, and JIRA will now notify your Zulip of changes to your issues!</p>
<p><b>Congratulations! You're done!</b><br />
Updates from JIRA will be sent to the stream you've configured, as below.</p>
<img class="screenshot" src="/static/images/integrations/jira/001.png" />
</div>
<div id="mercurial" class="integration-instructions">
<p>Get Zulip notifications when you <code>hg push</code>!</p>
<p>First, create the stream you'd like to use for Mercurial notifications,
and subscribe all interested parties to this stream. We recommend the
name <code>commits</code>.</p>
<p>Next, on your {{ settings_html|safe }}, create a Mercurial bot.</p>
<p>Then:</p>
<ol>
<li>
<p>Download and install our <a href="/api">Python bindings</a> on the
server where the master Mercurial repository lives.</p>
</li>
<li>
<p>Edit the <code>hg/.hgrc</code> configuration file for this master
Mercurial repository and add the following sections, using the
credentials for your Mercurial bot and setting the appropriate path to
the integration hook if it installs in a different location on this
system:</p>
<pre>[hooks]
changegroup = python:/usr/local/share/zulip/integrations/hg/zulip-changegroup.py:hook
[zulip]
email = "hg-bot@example.com"
api_key = "0123456789abcdefg"
stream = "commits"
{% if api_site_required %}site = {{ external_api_uri_subdomain }}{% endif %}</pre>
</li>
</ol>
<p>That's all it takes for the basic setup! On the next
<code>hg push</code>, you'll get a Zulip update for the changeset.</p>
<h3>More configuration options</h3>
<p>The Mercurial integration also supports:</p>
<ul>
<li>linking to changelog and revision URLs for your repository's web
UI</li>
<li>branch whitelists and blacklists</li>
</ul>
<h4>Web repository links</h4>
<p>If you've set up your repository to
be <a href="http://mercurial.selenic.com/wiki/QuickStart#Network_support">browsable
via the web</a>, add a <code>web_url</code> configuration option to
the <code>zulip</code> section of your master <code>.hg/hgrc</code> to get
changelog and revision links in your Zulip notifications:</p>
<pre><font color="#B6B6B4">[zulip]
email = "hg-bot@example.com"
api_key = "0123456789abcdefg"
stream = "commits"</font>
web_url = "http://hg.example.com:8000/"
{% if api_site_required %}site = {{ external_api_uri_subdomain }}{% endif %}</pre>
<h4>Branch whitelists and blacklists</h4>
<p>By default, this integration will send Zulip notifications for
changegroup events for all branches. If you'd prefer to only receive Zulip
notifications for specified branches, add a <code>branches</code>
configuration option to the <code>zulip</code> section of your
master <code>.hg/hgrc</code>, containing a comma-separated list of the
branches that should produce notifications:</p>
<pre><font color="#B6B6B4">[zulip]
email = "hg-bot@example.com"
api_key = "0123456789abcdefg"
stream = "commits"</font>
branches = "prod,master"</pre>
<p>You can also exclude branches that you don't want to cause
notifications. To do so, add an <code>ignore_branches</code> configuration
option to the <code>zulip</code> section of your
master <code>.hg/hgrc</code>, containing a comma-separated list of the
branches that should be ignored:</p>
<pre><font color="#B6B6B4">[zulip]
email = "hg-bot@example.com"
api_key = "0123456789abcdefg"
stream = "commits"</font>
ignore_branches = "noisy,even-more-noisy"</pre>
<p><b>Congratulations! You're done!</b><br /> When team members push new
changesets with <code>hg push</code>, you'll get a Zulip notification that
looks like this:</p>
<img class="screenshot" src="/static/images/integrations/hg/001.png" />
</div>
<div id="nagios" class="integration-instructions">
<p>First, create the stream you'd like to use for Nagios notifications,
and subscribe all interested parties to this stream. The integration will
use the default stream <code>nagios</code> if no stream is supplied in the
configuration; you still need to create the stream even if you are using
this default.</p>
<p>Next, download and install our <a href="/api">Python
bindings and example scripts</a> on your Nagios server.</p>
<p>Next, open <code>integrations/nagios/zuliprc.example</code>
in your favorite editor, and change the following lines to
specify the email address and API key for your Nagios bot,
saving it to <code>/etc/nagios3/zuliprc</code> on your Nagios
server:</p>
<div class="codehilite"><pre>[api]
email = NAGIOS_BOT_EMAIL_ADDRESS
key = NAGIOS_BOT_API_KEY
{% if api_site_required %}site = {{ external_api_uri_subdomain }}{% endif %}</pre></div>
<p>Copy <code>integrations/nagios/zulip_nagios.cfg</code>
to <code>/etc/nagios3/conf.d</code> on your Nagios server.</p>
<p>Finally, add <code>zulip</code> to the <code>members</code>
list for one or more of the contact groups in the
<code>CONTACT GROUPS</code> section
of <code>/etc/nagios3/conf.d/contacts.cfg</code>, doing
something like:
</p>
<div class="codehilite"><pre>define contactgroup{
contactgroup_name admins
alias Nagios Administrators
members monitoring<span class="na">, zulip</span>
}
</pre></div>
Once you've done that, reload your Nagios configuration
using <code>/etc/init.d/nagios3 reload</code>.
<p><b>Congratulations! You're done!</b><br /> When your Nagios
system makes an alert, you'll see a message like the following,
to the stream <code>nagios</code> (to change this, edit the
arguments to <code>nagios-notify-zulip</code>
in <code>/etc/nagios3/conf.d/zulip_nagios.cfg</code>) with a
topic indicating the service with an issue:</p>
<img class="screenshot" src="/static/images/integrations/nagios/001.png" />
<p><b>Testing</b><br />If you
have <a href="http://nagios.sourceforge.net/docs/3_0/extcommands.html">external
commands enabled in Nagios</a>, you can generate a test notice
from your Nagios instance by visiting using the
<code>Send custom service notification</code> command in
the <code>Service Commands</code> section of any individual
service's page on your Nagios instance.</p>
<p><b>Troubleshooting</b><br />You can confirm whether you've
correctly configured Nagios to run the Zulip plugin by looking
for <code>SERVICE NOTIFICATION</code> lines mentioning zulip
in <code>/var/log/nagios3/nagios.log</code>. You can confirm
whether you've configured the Zulip plugin code correctly by
running <code>/usr/local/share/zulip/integrations/nagios/nagios-notify-zulip</code>
directly.</p>
</div>
<div id="openshift" class="integration-instructions">
<p>Ths integration sends a notification every time a deployment is
made in an OpenShift instance.</p>
<p>First, download our <a href="/api">Python
bindings and example scripts</a>, and move it to your local copy of
the application's repository.</p>
<p>Then, create a new commit including all the changes made to the
repository, and push it to your app.</p>
<p>After that, connect to the application through SSH. If you don't know
how to do this, log in to your OpenShift Online account, go to your
application's dashboard, and click "Want to log in to your application?".
<br />There you'll find the app's SSH user, address, and further
information on SSH, in case you need it.</p>
<img class="screenshot" src="/static/images/integrations/openshift/002.png" />
<p>Once you have connected, install the Python bindings by running:</p>
<div class="codehilite"><pre>
<span class="s">$</span> cd ~/app-root/repo/&lt;python_bindings_path&gt;
<span class="s">$</span> python setup.py install</pre>
</div>
<p>Where <code>&lt;python_bindings_path&gt;</code> is the path where you
saved the bindings in the first step.</p>
<p>Next, open <code>integrations/openshift/zulip_openshift_config.py</code>
inside the SSH terminal with your favorite editor, and change the
following lines to specify the email address and API key for your
OpenShift integration:</p>
<div class="codehilite">
<pre><span class="n">ZULIP_USER</span> <span class="o">=</span> <span class="s">"openshift-bot@example.com"</span>
<span class="n">ZULIP_API_KEY</span> <span class="o">=</span> <span class="s">"0123456789abcdef0123456789abcdef"</span>
{% if api_site_required %}<span class="n">ZULIP_SITE</span> <span class="o">=</span> <span class="s">"{{ external_api_uri_subdomain }}"</span>{% endif %}</pre>
</div>
<p>You can also specify which pushes will result in
notifications and to what stream the notifications will be sent
by modifying the <code>deployment_notice_destination</code> function
in <code>zulip_openshift_config.py</code>. By default, deployments
triggered by commits pushed to the <code>master</code> and
<code>test-post-receive</code> branches will result in a notification
to stream <code>deployments</code>.</p>
<p>Save the file, and symlink
<code>$OPENSHIFT_PYTHON_DIR/virtenv/share/zulip/integrations/openshift/post-receive</code>
into the <code>~/app-root/repo/.openshift/action_hooks</code>
directory.</p>
<p>Next, create the stream you'd like to use for OpenShift notifications,
and subscribe all interested parties to this stream. The integration will
use the default stream <code>deployments</code> if no stream is supplied
in the hook; you still need to create the stream even if you are using
this default.</p>
<p><b>Congratulations! You're done!</b><br /> Whenever you make
a push to the <code>master</code> branch of your application's repository
(or whichever branch you configured above), or if you force a deployment,
the Zulip OpenShift plugin will send an automated notification that
looks like this:</p>
<img class="screenshot" src="/static/images/integrations/openshift/001.png" />
<p><b>Testing</b><br />You can test the plugin without changing
your <code>master</code> branch by pushing to
the <code>test-post-receive</code> branch.</p>
</div>
<div id="perforce" class="integration-instructions">
<p>Zulip supports integration with Perforce as a
<a href="http://www.perforce.com/perforce/doc.current/manuals/p4sag/chapter.scripting.html">trigger</a>
that fires once a changelist is submitted and committed. To do this:</p>
<ol>
<li>Download and install our <a href="/api">Python bindings</a> on the
server that hosts your Perforce depot. The Perforce trigger will be
installed to a location like
<code>/usr/local/share/zulip/integrations/perforce</code></li>
<li>Open <code>integrations/perforce/zulip_perforce_config.py</code> in
your favorite editor, change the <code>ZULIP_USER</code> and
<code>ZULIP_API_KEY</code> variables at the top of the file to the
credentials for the bot you'd like to use for this integration.</li>
<li>You should also change <code>ZULIP_SITE</code> to {{ external_api_path_subdomain }}</li>
<li>Edit your
<a href="http://www.perforce.com/perforce/doc.current/manuals/p4sag/chapter.scripting.html#d0e14583">trigger table</a>
with <code>p4 triggers</code> and add an entry something like the
following:
<pre>notify_zulip change-commit //depot/... "/usr/local/share/zulip/integrations/perforce/zulip_change-commit.py %change% %changeroot%"</pre>
</li>
<li>By default, this hook will send to streams of the form
<code>depot_subdirectory-commits</code>. So, a changelist that modifies
files in <code>//depot/foo/bar/baz</code> will result in a message to
stream <code>foo-commits</code>. Messages about changelists that modify
files in the depot root or files in multiple direct subdirectories of
the depot root will be sent to <code>depot-commits</code>. If you'd
prefer different behavior, such as all commits across your depot going
to one stream, change it now in <code>zulip_perforce_config.py</code>.
Make sure that everyone interested in getting these post-commit Zulips
is subscribed to the relevant streams!</li>
</ol>
<p><b>Congratulations! You're done!</b><br /> When you commit to your
Perforce depot the team can see updates in real time in
Zulip:</p>
<img class="screenshot" src="/static/images/integrations/perforce/001.png" />
</div>
<div id="phabricator" class="integration-instructions">
<p>Zulip supports integration with Phabricator and can notify you of the
latest items in your Phabricator feed.</p>
<p>You can follow the instructions at
<a href="https://github.com/zulip/phabricator-to-zulip">
https://github.com/zulip/phabricator-to-zulip
</a>
to get it set up.
</p>
</div>
<div id="puppet" class="integration-instructions">
<p>Zulip supports Puppet integration and can notify you when Puppet runs fail (or when they happen at all).</p>
<p>You can follow the instructions at
<a href="https://forge.puppetlabs.com/mbarr/puppet_zulip">
https://forge.puppetlabs.com/mbarr/puppet_zulip
</a>
to get it set up.
</p>
<p><small>Thanks to Matt from Kensho for submitting this integration!</small></p>
</div>
<div id="redmine" class="integration-instructions">
<p>Get information on new or updated Redmine issues right in
Zulip with our Zulip Redmine plugin! Note: this setup must be
done by a Redmine Administrator.</p>
<p>First, create the stream you'd like to use for Redmine notifications,
and subscribe all interested parties to this stream. We recommend the
name <code>redmine</code>.</p>
<p>Then:</p>
<ol>
<li>
<p>Clone
the <a href="https://github.com/zulip/zulip-redmine-plugin">Zulip
Redmine plugin repository</a> by running:</p>
<pre>git clone https://github.com/zulip/zulip-redmine-plugin</pre>
</li>
<li>
<p>Follow
the <a href="http://www.redmine.org/projects/redmine/wiki/Plugins">Redmine
plugin installation guide</a> to install
the <code>zulip_redmine</code> plugin directory, which is a
subdirectory of the <code>zulip-redmine-plugin</code> repository
directory. In a nutshell, the steps are:</p>
<ol type="A">
<li>
<p>Copy the <code>zulip_redmine</code> directory to
the <code>plugins</code> directory of your Redmine
instance.</p></li>
<li>
<p>Update the Redmine database by running (for Rake 2.X, see the
guide for instructions for older versions):</p>
<pre>rake redmine:plugins:migrate RAILS_ENV=production</pre>
</li>
<li>
<p>Restart your Redmine instance.</p>
</li>
</ol>
<p>The Zulip plugin is now registered with Redmine!</p>
</li>
<li>
<p>On your {{ settings_html|safe }}, create a new Redmine bot.</p>
</li>
<li>
<p>To configure Zulip notification settings that apply to many
projects in one go, in Redmine click the "Administration" link in
the top left. Click the "Plugins" link on the Administration page,
and click the "Configure" link to the right of the Zulip plugin
description. In the "Projects" section, select all projects to which
you want these settings to apply.</p>
<p>To configure Zulip notifications for a particular Redmine project,
visit the project's Settings page.</p>
<p>
In either case, fill out zulip server by <code>{{ external_api_path_subdomain }}</code>,
the bot email address, and API key, and the
Zulip stream that should receive notifications. Apply your changes.
</p>
</li>
<li>
<p>To test the plugin, create an issue or update an existing issue in
a Redmine project that has Zulip notifications configured (any
project, if you've configured global settings).</p>
</li>
</ol>
<p><b>Congratulations! You're done!</b><br /> When you update issues in
Redmine, the team can see these updates in real time in Zulip:</p>
<img class="screenshot" src="/static/images/integrations/redmine/001.png" />
</div>
<div id="rss" class="integration-instructions">
<h4>RSS</h4>
<p>Get service alerts, news, and new blog posts right in Zulip with our
RSS integration!</p>
<p>First, create the stream you'd like to use for RSS notifications, and
subscribe all interested parties to this stream. We recommend the
name <code>rss</code>.</p>
<p>Next, on your {{ settings_html|safe }}, create an RSS bot.</p>
<p>Then, download and install our <a href="/api">Python bindings</a> on
the server where the RSS bot will live. The RSS integration will be
installed to a location
like <code>/usr/local/share/zulip/integrations/rss/rss-bot</code>.</p>
<p>Follow the instructions in the <code>rss-bot</code> script for
configuring the bot, adding your subscriptions, and setting up a cron job
to run the bot.</p>
<p><b>Congratulations! You're done!</b><br /> When new items appear in
your feeds, the team can see these updates in real time in Zulip:</p>
<img class="screenshot" src="/static/images/integrations/rss/001.png" />
</div>
<div id="subversion" class="integration-instructions">
<p>It is easy to send Zulips on SVN commits, by configuring a post-commit
hook. To do this:</p>
<p>First, create the stream you'd like to use for SVN commit
notifications, and subscribe all interested parties to this stream. The
integration will use the default stream <code>commits</code> if no stream
is supplied in the hook; you still need to create the stream even if you
are using this default.</p>
<p>Then:</p>
<ol>
<li>Download and install our <a href="/api">Python bindings</a> on the
server where the SVN repository lives.</li>
<li>Install <code>pysvn</code>. On Linux, you can install
the <code>python-svn</code> package. On other platforms, you can install
a binary or from source following
the <a href="http://pysvn.tigris.org/project_downloads.html">instructions
on the pysvn website</a>.</li>
<li>Copy <code>integrations/svn/zulip_svn_config.py</code>
and <code>integrations/svn/post-commit</code> from the API bindings
directory to the <code>hooks</code> subdirectory of your SVN
repository.</li>
<li><p>Next, open <code>integrations/git/zulip_svn_config.py</code>
in your favorite editor, and change the following lines to
configure your SVN integration:</p>
<div class="codehilite"><pre><span class="n">ZULIP_USER</span> <span class="o">=</span> <span class="s">"svn-bot@example.com"</span>
<span class="n">ZULIP_API_KEY</span> <span class="o">=</span> <span class="s">"0123456789abcdef0123456789abcdef"</span>
{% if api_site_required %}<span class="n">ZULIP_SITE</span> <span class="o">=</span> <span class="s">"{{ external_api_uri_subdomain }}"</span>{% endif %}</pre></div>
</li>
<li>The default stream used by this post-commit hook
is <code>commits</code>; if you'd prefer a different stream, change it
now in <code>zulip_svn_config.py</code>. Make sure that everyone
interested in getting these post-commit Zulips is subscribed to that
stream!</li>
</ol>
<p><b>Congratulations! You're done!</b><br /> When you commit to this SVN
repository, the team can see these updates in real time in Zulip:</p>
<img class="screenshot" src="/static/images/integrations/svn/001.png" />
</div>
<div id="trac" class="integration-instructions">
<p>First, create the stream you'd like to use for Trac notifications, and
subscribe all interested parties to this stream. The integration will use
the default stream <code>trac</code> if no stream is supplied in the
hook; you still need to create the stream even if you are using this
default.</p>
<p>Next, download and install our <a href="/api">Python
bindings and example scripts</a> on your Trac server.</p>
<p>Next, open <code>integrations/trac/zulip_trac_config.py</code> in
your favorite editor, and change the following lines to specify
your bot's email address, API key, and where you'd like your
notification messages to go (by default,
stream <code>trac</code>):</p>
<div class="codehilite"><pre><span class="n">ZULIP_USER</span> <span class="o">=</span> <span class="s">"trac-notifications-bot@example.com"</span>
<span class="n">ZULIP_API_KEY</span> <span class="o">=</span> <span class="s">"0123456789abcdef0123456789abcdef"</span>
<span class="n">STREAM_FOR_NOTIFICATIONS</span> <span class="o">=</span> <span class="s">"trac"</span>
<span class="n">TRAC_BASE_TICKET_URL</span> <span class="o">=</span> <span class="s">"https://trac.example.com/ticket"</span>
{% if api_site_required %}<span class="n">ZULIP_SITE</span> <span class="o">=</span> <span class="s">"{{ external_api_uri_subdomain }}"</span>{% endif %}</pre></div>
<p>Copy <code>integrations/trac/zulip_trac.py</code>
and <code>integrations/trac/zulip_trac_config.py</code> into
your Trac installation's <code>plugins/</code>
subdirectory. Once you've done that, edit your Trac
installation's <code>conf/trac.ini</code> to
add <code>zulip_trac</code> to the <code>[components]</code>
section, as follows:</p>
<div class="codehilite"><pre><span class="k">[components]</span>
<span class="na">zulip_trac</span> <span class="o">=</span> <span class="s">enabled</span></pre></div>
<p>You may then need to restart Trac (or Apache) so that Trac will load our plugin.</p>
<p><b>Congratulations! You're done!</b><br /> When people open
new tickets (or edit existing tickets), you'll see a message
like the following, to the stream <code>trac</code> (or whatever
you configured above) with a topic that matches the ticket
name:</p>
<img class="screenshot" src="/static/images/integrations/trac/001.png" />
<p><b>Additional trac configuration</b><br /> After using the plugin
for a while, you may want to customize which changes to tickets
result in a Zulip notification using
the <code>TRAC_NOTIFY_FIELDS</code> setting
in <code>zulip_trac_config.py</code>.</p>
</div>
<div id="trello-plugin" class="integration-instructions">
<p>
This legacy integration for Trello works by running a script
that communicates with the Trello API in a cron job. We
recommend <a href="#trello">the new Trello webhook
integration</a> (which will eventually replace this entirely).
Please <a href="https://github.com/zulip/zulip/issues/new">report
any issues</a> which cause you to prefer this integration over
the webhook integration.
</p>
<p>First, create the stream you'd like to use for Trello notifications,
and subscribe all interested parties to this stream. We recommend the
name <code>trello</code>.</p>
<p>Next, download a copy
of <a href="https://github.com/zulip/trello-to-zulip">trello-to-zulip</a>
and follow the instructions in <code>README.md</code>. When you
make changes in Trello, they will be reflected in Zulip:
</p>
<img class="screenshot" src="/static/images/integrations/trello/002.png" />
<p><small>Thanks to Nathan from FoundationDB for submitting this integration!</small></p>
</div>
<div id="twitter" class="integration-instructions">
<p>See Twitter search results in Zulip! This is great for seeing and
discussing who is talking about you, friends, competitors, or important
topics in real time.</p>
<p>First, create the stream you'd like to use for tweets, and subscribe
all interested parties to this stream. We recommend the
name <code>twitter</code>.</p>
<p>Next, download and install our <a href="/api">Python bindings and
example scripts</a>. This bot should be set up on a trusted machine,
because your API key is visible to local users through the command line or
config file.</p>
<p>Next, install <b>version 1.0 or later</b> of
the <code>twitter-python</code> library. If your operating system
distribution doesn't package a new enough version, you can install the
library from source
from <a href="https://github.com/bear/python-twitter">the GitHub
repository</a>.</p>
<p>Next, set up Twitter authentication. This bot uses OAuth to
authenticate with Twitter, and in order to obtain a consumer key & secret,
you must register a new application under your Twitter account:</p>
<ol>
<li>
Log in to <a href="http://dev.twitter.com">http://dev.twitter.com</a>.
</li>
<li>
In the menu under your username,
click <a href="https://dev.twitter.com/apps">My Applications</a>. From
this page, create a new application.
</li>
<li>
Click on the application you created and click "create my access
token". Fill in the requested values.
</li>
</ol>
<p>To configure and deploy this bot:</p>
<ol>
<li>
Create a <code>~/.zulip_twitterrc</code> with the following
contents:
<pre>[twitter]
consumer_key =
consumer_secret =
access_token_key =
access_token_secret =</pre>
</li>
<li>
Test the script by running it manually:
<pre>
/usr/local/share/zulip/integrations/twitter/twitter-search-bot --search="@nprnews,quantum physics" --site={{ external_api_uri_subdomain }}
</pre>
Note: <code>twitter-search-bot</code> may install to a different
location on your operating system distribution.
</li>
<li>
Configure a crontab entry for this script. A sample crontab entry that
will process tweets every minute is:
<pre>
* * * * * /usr/local/share/zulip/integrations/twitter/twitter-search-bot --search="@nprnews,quantum physics" --site={{ external_api_uri_subdomain }}
</pre>
</li>
</ol>
<p><b>Congratulations! You're done!</b><br /> When someone tweets a
message containing one of your search terms, you'll get a Zulip on your
specified stream, with the search term as the topic.</p>
<img class="screenshot" src="/static/images/integrations/twitter/001.png" />
<p>Note that the twitter search bot integration <b>just sends
links to tweets</b>; the pretty inline previews of tweets are
generated by the Twitter card rendering integration configured
in <code>/etc/zulip/settings.py</code> on the Zulip server.</p>
</div>
</div>
</div> <!-- .inner-content -->
</div> <!-- .padded-content -->
</div> <!-- .main -->
</div> <!-- .portico-landing -->
{% endblock %}