Welcome to Jirafs’s documentation!

https://travis-ci.org/coddingtonbear/jirafs.svg?branch=master https://badge.fury.io/py/jirafs.png https://badges.gitter.im/Join%20Chat.svg

Pronounced like ‘giraffes’, but totally unrelated to wildlife, this library lets you stay out of Jira as much as possible by letting you edit your Jira issues as a collection of text files using an interface inspired by git and hg.

http://coddingtonbear-public.s3.amazonaws.com/github/jirafs/readme_demo_2.1_v7.gif

Getting Started

Installation

It is recommended that you install the program using pip while in a Python 3 virtualenv; you can install using pip by running:

pip install jirafs

After Jirafs successfully installs, you’ll have access to the jirafs command that you can use for interacting with Jira.

Working with a Jira issue

First, you’ll need to “clone” the issue you want to work with using Jirafs by running the following (replacing http://my.jira.server/browse/MYISSUE-1024 with the issue url you are concerned about):

jirafs clone http://my.jira.server/browse/MYISSUE-1024

The first time you run this command, Jirafs will ask you for a series of details that it will use for communicating with Jira; don’t worry: although all of this information will be stored in a plaintext file at ~/.jirafs_config, Jirafs will not store your password unless you give it permission to do so.

Once the command runs successfully, it will have created a new folder named after the issue you’ve cloned, and inside that folder it will place a series of text files representing the issue’s contents in Jira as well as copies of all attachments currently attached to the issue in Jira.

The following text files are created:

  • fields.jira: This file will show all currently-set field values for this Jira issue (except fields written to their own files; see description.jira below). You can change field values here by editing the field values in the file. See Editing Issue Fields for more information.
  • description.jira: This file will show the issue’s current description. You can change the issue’s description by editing the contents of this file.
  • links.jira: This file lists all of the links associated with this Jira issue. You can add new links (or remove links) by adding or removing bulleted items from this list; see Adding, Removing or Changing Links for more information.
  • comments.read_only.jira: This file shows all comments currently posted to this issue. Note that you cannot edit the comments in this file.
  • new_comment.jira: This file starts out empty, but if you would like to add a new comment, you can create one by entering text into this file.

In order to update any of the above data or upload an asset, either make the change to a field in fields.jira, edit the issue’s description in description.jira, write a comment into new_comment.jira, or copy a new asset into this folder, then run:

jirafs status

to see both what changes you’ve marked as ready for being submitted to Jira as well as which changes you have made, but not yet committed.

Note

Unlike when working with a git repository, you do not need to ‘stage’ files using a command analogous to git’s “add” command when working with a Jira issue using Jirafs. All uncommitted files will automatically be included in any commit made.

Once you’re satisfied with the changes that are about to be submitted to Jira, run:

jirafs submit

Note

jirafs submit really just runs jirafs commit followed by jirafs push (which itself runs jirafs pull to get your local copy up-to-date with what it saw in Jira), so although jirafs submit is probably the path you want to take, feel free to use the lower-level more-git-like commands if you want.

Please consider this to be just a simple overview – there are a variety of other commands you can run to have finer-grained control over how the issue folder is synchronized with Jira; see Common Commands for more details.

Note

If you are a VIM user, there is a VIM Plugin available that provides syntax highlighting for Jira/Confluence’s wikimarkup.

Editing Issue Fields

In most cases, you can simply edit the field’s contents directly – just make sure to indent the field contents by four spaces.

For text fields, editing field contents is as simple as typing-in a new value, but many issue fields are are JSON dictionaries or lists that require you to edit the data in a more-structured way. If the data you enter is not valid JSON, when push-ing up changes, you will receive an error, but don’t worry – if you encounter such an error, edit the contents to be valid JSON, commit, and push again. You may need to consult with Jira’s documentation to develop an understanding of how to change these values.

Note

You don’t always need to enter values for every field in a JSON dictionary; in some cases, Jira will infer the missing information for you.

Macros

One of the most powerful features of Jirafs is how it can make your workflow easier if you ever need to do common things like insert tables, graphs, or charts in your issues. There are a handful of macros available, and writing your own macro plugin is easy. See Using Macros for more information.

Migrating from 1.0

There were a lot of changes between Jirafs v1 and Jirafs v2; so you might be under the impression that you may need to take special care with how you migrate forward to v2. Fortunately, though, ticket folders created with Jirafs v1 are fully-compatible with those created by Jirafs v2. You do, though, need to make one change to how you work with jirafs: the syntax used for macros has changed, and the macro API has been updated and will require you to upgrade the macros you currently use to their latest versions.

If you had a macro named list-table installed, you previously would have used that macro by using Jira-style curly-brace syntax:

{list-table}
*
** One
** Two
* A
** B
** C
{list-table}

As of Jirafs v2, we use an xml-inspired syntax for a variety of reasons, most importantly that it makes it easier for Jirafs to tell the difference between when you’re intending to use Jira markup and when you’re intending that Jirafs run a macro for you:

<jirafs:list-table>
*
** One
** Two
* A
** B
** C
</jirafs:list-table>

Otherwise, behaviors will generally be the same.

Common Commands

The following commands are sure to be commonly used. Be sure to check out Advanced Commands if you are curious about less-commonly-used functionality.

Note

Commands marked with an asterisk can be ran from either an issue folder, or from within a folder containing many issue folders.

In the latter case, the command will be ran for every subordinate issue folder.

clone <source>

Requires a single parameter (source) indicating what to clone.

Possible forms include:

  • clone http://my.jira.server/browse/MYISSUE-1024 [PATH]
  • clone MYISSUE-1024 [PATH] (will use default Jira instance)

Create a new issue folder for MYISSUE-1024 (replace MYISSUE-1024 with an actual Jira issue number), and clone the relevant issue into this folder.

Note that you may specify a full URL pointing to an issue, but if you do not specify a full URL, your default Jira instance will be used; if you have not yet set one, you will be asked to specify one.

Although by default, the issue will be cloned into a folder matching the name of the issue, you may specify a path into which the issue should be cloned by specifying an additional parameter (PATH in the example forms above).

preview [<field name>]

Render the content of the field named field_name via your Jira instance’s Wiki Markup renderer. This is useful for helping you ensure that your wiki markup is correct and previewing content generated by any macro plugins you might be using. If no field name is specified, a message overview will be displayed showing you a preview of the message description, summary, new comment, and historical comments.

Note that you can also access subkeys in fields containing JSON by using a dotpath, and can render the following special fields:

  • new_comment: The formatted contents of your unsubmitted comment.
  • comments: The comments for this issue.

submit

Commit outstanding changes, push them to the remote server, and pull outstanding changes.

This is exactly equivalent to running a commit followed by a push.

commit

From within an issue folder, commits local changes and marks them for submission to Jira next time push is run.

Note

Unlike git (but like mercurial), you do not need to stage files by running a command analogous to git’s ‘add’ before committing. The commit operation will automatically commit changes to all un-committed files.

pull *

From within an issue folder, fetches remote changes from Jira and merges the changes into your local copy. This command is identical to running fetch followed by merge.

push *

From within an issue folder, discovers any local changes, and pushes your local changes to Jira.

status *

From within an issue folder, will report both any changes you have not yet committed, as well as any changes that would take place were you to run jirafs push.

open *

From within an issue folder, opens the current Jira issue in your default web browser.

subtask <summary>

From within an issue folder, creates a new subtask of the current Jira issue.

assign [<username>]

Change the assignee of the Jira issue to the username specified. If one does not specify a username, the assignee will be set to the currently authenticated user.

transition

From within an issue folder, allows you to transition an issue into any state available in your workflow.

Possible forms include:

  • transition: The user will be presented with state options for selection at runtime.
  • transition 10: Transition into the state with the ID of ‘10’.
  • transition "closed": Transition into the state with the name “closed”. Note that state names are case-insensitive.

Note

Note that the options available are dependent upon the user account used for authentication.

Advanced Commands

You will probably not have a need to use the below commands, but they are available for adventurous users.

fetch

Fetch upstream changes from Jira, but do not apply them to your local copy. To apply the fetched changes to your local copy, run merge.

merge

From within an issue folder, merges previously-fetched but unmerged changes into your local copy.

diff

From within an issue folder, will display any local changes that you have made.

field <field name>

Write the content of the field named field name to the console. Useful in scripts for gathering, for example, the ticket’s summary field.

Note that you can also access subkeys in fields containing JSON by using a dotpath, and can access the following special fields:

  • new_comment: The formatted contents of your unsubmitted comment.
  • links: Returns a JSON structure representing this issue’s links.
  • fields: Returns a JSON structure representing all field contents.

setfield <field name> <value>

Set the value of the field named field name to the value value. This is useful for programmatically changing the status of various fields.

Note that you can also access subkeys in fields containing JSON by using a dotpath.

match <field name> <value>

Return a status code of 0 if the field field name matches the value value. This is useful for allowing you to programmatically perform certain actions on fields matching certain values – for example: moving resolved issues into an archive folder.

As with all commands, check --help for this command; you’ll find utilities allowing you to invert the check (for returning 0 when the check does not match) and utilities for executing a command when the field does not match.

Note that you can also access subkeys in fields containing JSON by using a dotpath.

log

From within an issue folder, will print out the log file recording actions Jirafs has performed for this ticket folder.

config

Get, set, or list configuration values. Requires use of one of the following sub-options:

  • --get <SETTING_NAME>: Get the value of this specific parameter name.
  • --set <SETTING_NAME> <VALUE>: Set the value of this specific parameter.
  • --list: List all settings currently configured in the current context. When used within an issue folder, will list this issue’s settings, but when used outside of an issue folder, will display only global configuration.

You may also use the --global argument to ensure that configuration changes or lists use or affect only the global configuration.

plugins

List, activate, or deactivate plugins by name.

Plugins provides several sub-options:

  • --verbose: Display information about each plugin along with its name.
  • --enabled-only: List only plugins that are currently enabled.
  • --disabled-only: List only plugins that are available, but not currently enabled.
  • --enable=PLUGIN_NAME: Enable a plugin by name for the current issue folder.
  • --disable=PLUGIN_NAME: Disable a plugin by name for the current issue folder.
  • --global: Used with --enable or --disable above, will enable or disable a plugin globally. Note: per-folder settings always take priority.

git

From within an issue folder, will provide direct access to this issue folder’s internal git repository. This interface is not intended for non-developer use; please make sure you know what you’re doing before performing git operations directly.

debug

From within an issue folder, will open up a python shell having access to a variable named folder holding the Python object representing the ticket folder you are currently within.

search_users <term>

Search for users matching the specified search term. This is particularly useful if you’re not sure what somebody’s username and you were hoping to mention them in a ticket so they get an e-mail notification.

create

Creates a new issue. Provides the following options:

  • --summary: The summary to use for your new issue.
  • --description: The description to use for your new issue.
  • --issuetype: The issue type to use for your new issue (defaults to ‘Task’).
  • --project: The project key to use for your new issue. This is the short, capitalized string you see next to issues. For example, if your tickets were named something like KITTENS-12084, ‘KITTENS’ is the project key.
  • --quiet: Do not prompt user to provide values interactively.

If any of the above values are not specified, the user will be prompted to provide them interactively.

Configuration

Settings affecting all issues are set in the following files:

  • ~/.jirafs_config: Global configuration values affecting all issues.
  • ~/.jirafs_ignore: Global list of patterns to ignore completely; these files differ from .jirafs_local below in that they will not be tracked in the underlying git repository. See Ignore File Format for details.
  • ~/.jirafs_local: Global list of patterns to ignore when looking through issue directories for files to upload to Jira. Note that these files will continue to be tracked in the underlying git repository. See Ignore File Format for details.
  • ~/.jirafs_remote_ignore: A list of patterns to ignore when looking through files attached to a Jira issue. Files matching any of these patterns will not be downloaded. See Ignore File Format for details.

You may also add any of the below files into any issue directory (in this example, MYISSUE-1024):

  • MYISSUE-1024/.jirafs/config: Configuration overrides for this specific issue folder. Settings set in this file will override – for this folder only – any values you have set in ~/.jirafs_config.
  • MYISSUE-1024/.jirafs_ignore: A list of patterns to ignore completely; these files differ from .jirafs_local below in that they will not be tracked in the underlying git repository. See Ignore File Format for details.
  • MYISSUE-1024/.jirafs_local: A list of patterns to ignore when looking through this specific issue directory. This list of patterns is in addition to patterns entered into ~/.jirafs_ignore above. Note that these files will continue to be tracked in the underlying git repository. See Ignore File Format for details.
  • MYISSUE-1024/.jirafs_remote_ignore: A list of patterns to ignore when looking through files attached to this specific Jira issue. Files matching any of these patterns will not be downloaded. These patterns are in addition to the patterns entered into ~/.jirafs_remote_ignore above. See Ignore File Format for details.

Using an untrusted HTTPS certificate

If your Jira instance uses a self-signed certificate or you are working in an enterprise environment having a non-standard certificate authority, you can manually configure your Jira connection to either not verify the certificate, or to instead use a non-standard certificate authority certificate.

  1. First, find the configuration section in your ~/.jirafs_config named after the address of your Jira server.
  2. Then, after the lines starting with username and password, add a line reading verify = <VALUE> replacing <VALUE> with one of two options:
    • If your Jira instance uses a self-signed certificate: the string false.
    • If your Jira instance’s certificate uses a non-standard certificate authority, the absolute path to a place on your computer where your certificate authority’s certificate is stored.

For example:

1
2
3
4
[https://jira.mycompany.org]
username = myusername
password = mypassword
verify = /path/to/certificate/or/false

Disabling “Save Jira Password” prompt

If you would never like to save your Jira password in Jirafs, you can disable the “Save Jira Password” prompt by setting the ask_to_save setting to false in the main section of your ~/.jirafs_config file.

For example:

1
2
[main]
ask_to_save = false

Setting a Date Format for Rendered Comments

By default, Jirafs will render a date using the following international date format:

%Y-%m-%d at %H:%M:%S %Z

But you can configure the format to one more familiar to you by setting the main.date_format configuration setting using the formatting codes described here: `https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes`_

1
2
[main]
date_format = %d %B %Y at %h:%M %p

Using Plugins

  • Enable the plugin for a given ticket folder:

    jirafs plugins --enable=my_plugin_name
    
  • Enable the plugin globally:

    jirafs plugins --global --enable=my_plugin_name
    

Writing your own Plugins

Jirafs plugins come in two different varieties:

  • “Folder Plugins” are used for altering the behavior of existing commands when interacting with a Ticket Folder. They can be disabled or enabled on a per-folder basis, too.
  • “Command Plugins” are used for adding new commands to Jirafs. These are always enabled when installed.

Note

All existing Jirafs commands (‘clone’, ‘pull’, ‘push’, etc.) are “Command Plugins”.

Writing Plugins

For a working example of a folder plugin, check out Jirafs-Pandoc’s Github Repository.

Setuptools Entrypoint
  • Add a setuptools entrypoint to your plugin’s setup.py:

    entry_points={
      'jirafs_plugins': [
          "my_plugin_name = module.path:ClassName"
      ]
    }
    
  • Write a subclass of jirafs.plugin.Plugin implementing one or more methods using the interface described in Folder Plugin API.

Folder Plugin API

The following properties must be defined:

  • MIN_VERSION: The string version number representing the minimum version of Jirafs that this plugin will work with.
  • MAX_VERSION: The string version number representing the first version at which your plugin would not be guaranteed to becompatible. Note that this means that your Jirafs version must be below this number, and that users running a version of Jirafs matching this will see an error message. Note: Jirafs uses semantic versioning, so you should set this value to the next major version about the highest version you’ve tested.
Pre/Post Command Methods

All commands (including user-installed commands) can have plugins altering their behavior by defining pre_*COMMAND* and post_*COMMAND* methods. For the below, please replace *COMMAND* with the command your plugin would like to alter the behavior of.

  • pre_*COMMAND*(**kwargs):
    • Executed before handling *COMMAND*. Receives (as **kwargs) all parameters that will be passed-in to the underlying command.
    • You may alter the parameters that will be passed-in to the underlying command by returning a new or altered **kwargs dictionary.
    • Return None or the original **kwargs dictionary to pass original arguments to the command without alteration.
  • post_*COMMAND*(returned):
    • Executed after handling *COMMAND*. Receives as an argument the result returned by the underlying command.

Note

Although the return values of commands are not in the scope of this specification, many commands return a jirafs.utils.PostStatusResponse instance.

Such an instance is a named tuple containing two properties:

  • (bool) new: Whether the command’s action had an effect on the underlying git repository.
  • (string) hash: The hash of the relevant repository branch’s head commit following the action.
Properties

The plugin will have the following properties and methods at its disposal:

  • self.ticketfolder: An instance of jirafs.ticketfolder.TicketFolder representing the jira issue that this plugin is currently operating upon.
  • self.get_configuration(): Returns a dictionary of configuration settings for this plugin.
  • self.metadata: Returns a dictionary containing metadata stored for this plugin. This dictionary is modifyable, and will be preserved between plugin executions.
Methods
  • execute_macro(data: str, attrs: Dict, config: Dict) -> str: REQUIRED Your macro function. It will receive a series of parameters:

    • data: The content of your macro.
    • attrs: Any attributes of your macro.
    • config: Jirafs config parameters.

    and is expected to return a string of text that your macro will be replaced when when sending content to Jira.

  • execute_macro_reversal(data: str) -> str: If provided, will be expected to perform the reversal of execute_macro above. It will receive as parameters the full text of each field.

  • cleanup(): Perform any cleanup following macro processing for a ticket folder. If you need more-granular control, you can define methods for cleanup_pre_process() and cleanup_post_process() if you need to segment your cleanup process between before and after running macro processing methods.

Macro Plugins

Macro plugins are special kinds of folder plugins that are instead subclasses of jirafs.plugin.MacroPlugin but same setuptools entrypoints apply as are described in Setuptools Entrypoint.

Macros can be executed using either a block element format; for example:

<jirafs:my-macro>
Some content
</jirafs:my-macro>

Note

See Reserved Attributes for more information about attributes and the special src attribute.

or as a void element:

<jirafs:my-macro src="some_file_to_read_as_content.ext" />

Note

The trailing slash at the end of your macro is important!

Your execute_macro method is expected to return text that should be sent to Jira instead of your macro. Note that the method signature remains identical to that of a block element macro, but instead of receiving the content of the block, you will receive None.

Reserved Attributes
  • src: All macro plugins can be provided in either a block or void elements. When using a block element version of your macro, you provide content directly within the content of your tag. If you would like the content to be imported from a file instead, you can provide the path to the file to import via the src attribute.
Attributes

Both block and void elements can receive any number of attributes; they’re specified following the same conventions you might use for providing an HTML tag with attributes; for example:

<jirafs:flag-image country_code=”US” size=300 alternate=True /> {flag-image:country_code=US|size=300|alternate}
  • country_code: US (string)
  • size: 300.0 (float)
  • alternate: True (boolean)
Example Macro Plugin

The following plugin isn’t exactly useful, but it does demonstrate the basic functionality of a plugin:

class Plugin(MacroPlugin):
    TAG_NAME = 'upper-cased'

    def execute_macro(self, data, prefix='', **kwargs):
        return prefix + data.upper()

When you enter the following text into a Jira ticket field:

<jirafs:upper-cased prefix="Hello, ">my name is Adam.</jirafs:upper-cased>

the following content will be sent to Jira instead:

Hello, MY NAME IS ADAM.

Warning

Note that it’s always a good idea to make sure your execute_macro method has a final parameter of **kwargs! In future versions of Jirafs, we may add more keyword arguments that will be sent automatically.

Automatically-Reversed Macro Plugins

It’s not a ton of fun to have to handle reversing your own macros; so if your macro’s content will produce unique content for provided input, you can use the AutomaticReversalMacroPlugin as your base class instead of MacroPlugin. If you do so, your macro will automatically be reversed when returning content from Jira by scanning the content received from Jira and replacing any output generated by your macro during the most recent run with the macro content that generated that output.

In general, you won’t need to make any special modifications, but there are useful methods for overriding in special circumstances:

  • should_rerender(data: str, cache_entry: Dict, config: Dict) -> bool: Control whether this given input content (data) should be re-rendered. By default, should_rerender returns True only if cache_entry is empty. Values available in the cache_entry dictionary include:
    • filenames: A list of filenames generated by your macro while during processing of this input text.
    • attrs: Macro attributes set for your macro when running for this input text.
    • replacement: The replacement text generated by your macro for this input text.
    • is_temp: Whether or not this macro result was the result of generating content for your current working directory (is_temp==False), or if it was the result of processing historical content for identifying changes (is_temp==True).

See Methods for other methods that may be necessary for your macro.

Examples

See one of the following repositories for an example of this type of macro:

Image Macros

A particularly powerful Macro type is the “Image Macro”. Use of a macro of this type will allow you to automatically generate and embed images in your Jira content by passing your macro’s contents through a tool like Graphviz’ dot or plantuml.

In the case of this type of macro, you need to define just one method:

  • get_extension_and_image_data(data: str, attrs: Dict) -> Tuple[str, bytes]: For a given input text (data) and macro attributes (attrs), return a 2-tuple of the file extension to use for the file to be created, and the bytes of that file.

See Methods for other methods that may be necessary for your macro.

Note

Unlike most subclasses of MacroPlugin, you should not define your own execute_macro method!

Examples

See one of the following repositories for an example of this type of macro:

Note

Image Macros are automatically reversed.

Writing Command Plugins

For a working example of a command plugin, check out the source of Jirafs existing commands.

Setuptools Entrypoint
  • Add a setuptools entrypoint to your plugin’s setup.py:

    entry_points={
      'jirafs_commands': [
          "my_command_name = module.path:ClassName"
      ]
    }
    
  • Write a subclass of jirafs.plugin.CommandPlugin implementing one or more methods using the interface described in Plugin API.

Plugin API

The following properties must be defined:

  • MIN_VERSION: The string version number representing the minimum version of Jirafs that this plugin will work with.
  • MAX_VERSION: The string version number representing the first version at which your plugin would not be guaranteed to becompatible. Note that this means that your Jirafs version must be below this number, and that users running a version of Jirafs matching this will see an error message. Note: Jirafs uses semantic versioning, so you should set this value to the next major version about the highest version you’ve tested.

The following methods may be defined to control the behavior of your command plugin:

  • handle(self, args, folder, jira, path, **kwargs): (REQUIRED) This method (and methods called from here) is where you should write the bulk of your plugin’s functionality. handle receives several keyword arguments:
    • args: An instance of argparse.Namespace holding arguments specified on the command line. See add_arguments and parse_arguments for details.
    • folder: A jirafs.ticketfolder.TicketFolder instance corresponding with the current path. If you are writing a command that does not require a ticketfolder, set an attribute on your class named AUTOMATICALLY_INSTANTIATE_FOLDER to False (Note that this option makes the value of TRY_SUBFOLDERS irrelevant) and this value will always be None whether or not your command was invoked from within a ticket folder.
    • jira: A callable (accepting, optionally, the string domain of a Jira instance) which will return an instance of jira.client.JIRA corresponding with the domain you’ve specified, or the default Jira connection if no Jira domain was specified.
    • path: The string path from which this command was called. This can be used to create a jirafs.ticketfolder.TicketFolder instance representing the current ticket folder if so desired.
    • **kwargs: Keyword arguments may be added in the future; it is extremely important that your handle method accept arbitrary keyword arguments in order to prevent your plugin from breaking when new keyword arguments are added in the future.
  • add_arguments(self, parser): Using this method, you can add arguments that your command requires. Follow the guidelines in Python’s argparse documentation for an overview of how arguments are handled.
    • parser: An argparse.ArgumentParser instance.
  • parse_arguments(self, parser, extra_arguments): Potentially useful as a method to place argument validation.
    • parser: An argparse.ArgumentParser instance. Note that this instance will have already had attached all arguments added in the add_arguments method above.
    • extra_arguments: A list of string arguments unused by Jirafs.

You may also use any of the following properties to alter the behavior of Jirafs:

  • TRY_SUBFOLDERS: Set this class property to True if this command should be applied to all Jirafs ticket folders in subdirectories in the event that the current folder is not a ticket folder.
  • RUN_FOR_SUBTASKS: Set this class property to True if you would like your command to be automatically executed for subtask when being executed for a ticket having subtasks.
Example Plugin
import pydoc

from jirafs.plugin import CommandPlugin


class Command(CommandPlugin):
    """ Run a git command against this ticketfolder's underlying GIT repo """

    MIN_VERSION = "2.0.0"
    MAX_VERSION = "3.0.0"

    def handle(self, args, folder, **kwargs):
        return self.cmd(folder, *self.git_arguments)

    def parse_arguments(self, parser, extra_args):
        args, git_arguments = parser.parse_known_args(extra_args)
        self.git_arguments = git_arguments
        return args

    def main(self, folder, *git_arguments):
        result = folder.run_git_command(*git_arguments)
        pydoc.pager(result)
        return result

Using Macros

Macros are special kinds of plugins that perform simple functions for transforming text you enter into fields into something else when submitting them to Jira.

Existing Macros

  • For including programmatically-generated images in your Jira issues without ever leaving your editor:
    • jirafs-graphviz: Embed Graphviz (e.g. dot or neato) graphs using Graphviz’s ubiquitous graph description language.
    • jirafs-matplotlib: Embed graphs generated with the common Python charting library Matplotlib by writing simple python scripts.
    • jirafs-plantuml: Embed UML (e.g. timing, sequence, or activity) diagrams generated via PlantUML’s easy-to-use text format.
    • jirafs-mermaid: Embed beautiful diagrams (e.g. pie, gantt, or class) using Mermaid’s markdown-ish diagram description language.
  • For making tables more easily:

Writing your own Macros

Macros are really just special kinds of plugins; you can find more information about writing your own plugins in Macro Plugins.

Interesting Details

Ignore File Format

The files .jirafs_local, .jirafs_ignore and .jirafs_remote_ignore use a subset of the globbing functionality supported by git’s gitignore file syntax. Specifically, you can have comments, blank lines, and globbing patterns of files that you would not like to upload.

For example, if you’d like to ignore files having a .diff extension, and would like to add a comment indicating why those are ignored, you could enter the following into any *_ignore file:

# Hide diffs I've generated for posting to reviewboard
*.diff

Directory Structure

Each issue folder includes a hidden folder named .jirafs that stores metadata used by Jirafs for this issue. There may be many things in this folder, but two highlights include the following files/folders:

  • git: The issue folder is tracked by a git repository to enable future features, provide for a way of easily rolling-back or reviewing an issue’s previous state.
  • operation.log: This file logs all operations engaged in on this specific issue folder. You can review this log to see what jirafs has done in the past.

VIM Plugin

If you’re a vim user, I recommend you install my fork of the confluencewiki.vim plugin; if you do so, comment and description field files will use Jira/Confluence’s WikiMarkup for syntax highlighting.