Developer Resources

Customizing the Workflow

SG Jira Bridge is structured so that studios can tailor the workflow to meet their specific needs. Because both Shotgun and Jira are highly customizable, exposing a handful of settings would not be sufficient. Therefore, the bridge has been structured to allow subclassing the various components that control syncing and handling events in order to give full control over the logic of what is being done.

Structure Overview

_images/sg_jira_bridge_classes.png

Bridge

The Bridge is the main class for the sync. It handles the connections to both Shotgun and Jira, manages sync settings from the settings.py file, and initiates the calls to sync in Shotgun and Jira.

This class is intended to be used as-is without requiring customization since the details of the workflow logic are defined in the Syncer and SyncHandler. When creating a new instance of Bridge, typically you’ll use the Bridge.get_bridge() factory method and pass in the full path to the settings file.

Syncers

The Syncer is in charge of initially determining whether to accept or reject events from Shotgun and Jira for syncing. This is done with the accept_shotgun_event() and accept_jira_event() methods. It performs initial basic checks on the event to determine if it should immediately be rejected without needing to ask the handlers. These checks should be completely independent of the implementation details of the handlers. For example, a Shotgun event can be inspected to ensure it has the basic required fields in an event like the meta and project keys. Without either of these keys in the event, no handlers could process the event anyway.

If nothing in the event immediately disqualifies itself from consideration, the Syncer then hands the event off to each SyncHandler to accept the event or not. The first handler that accepts the event is then returned to process the event.

Note

Only one handler may process an event since having multiple handlers process a single event could cause issues where one handler undoes what a previous one did for the same event.

Syncers must be sub-classed from the base Syncer class in order to implement a list of Handlers to dispatch events to. The handlers() property must be overridden but additional parameters can be accepted by the class as well, to pass on to Handlers:

from .syncer import Syncer
from .handlers import TaskIssueHandler, NoteCommentHandler, EnableSyncingHandler


class TaskIssueSyncer(Syncer):
    """
    Sync Shotgun Tasks as Jira Issues.
    """
    def __init__(self, issue_type="Task", **kwargs):
        """
        Instatiate a new Task/Issue syncer for the given bridge.

        :param str issue_type: Jira Issue type to use when creating new Issues.
        """
        self._issue_type = issue_type
        super(TaskIssueSyncer, self).__init__(**kwargs)
        self._task_issue_handler = TaskIssueHandler(self, self._issue_type)
        self._note_comment_handler = NoteCommentHandler(self)
        # A handler combining the Task <-> Issue handler and the Note <-> Comment
        # handler. Task syncing to Jira starts if the Task "Sync in Jira" checkbox
        # is turned on. Notes linked to a Task being actively synced are automatically
        # synced without having to manually select them. A full sync is performed
        # when the Task checkbox is turned on.
        self._enable_syncing_handler = EnableSyncingHandler(
            self,
            [self._task_issue_handler, self._note_comment_handler]
        )

    @property
    def handlers(self):
        """
        Return a list of :class:`~handlers.SyncHandler` instances.
        """
        return [
            self._enable_syncing_handler,
            self._task_issue_handler,
            self._note_comment_handler
        ]

Sync Handlers

A SyncHandler holds the logic for syncing values between a Shotgun Entity type and a Jira resource and is owned by a Syncer instance. The base class defines the interface all handlers should support and provides a set of helper methods useful for implementations.

The following methods must be overridden from the Syncer base class:

# public methods
accept_shotgun_event()
accept_jira_event()
process_shotgun_event()
process_jira_event()

# private property
_sg_jira_status_mapping()

Setup

When a syncer is first loaded, it calls setup() on each SyncHandler. This can be used to check the Jira and Shotgun sites for specific conditions or setup requirements, ensuring that the sync can safely happen.

Additionally, this can be used to cache value(s) from either site if there are queries that might be done repeatedly that slow things down during the sync process.

Accepting the Event

After the Syncer has done its initial checks to decide whether to accept an event, it then passes the event off to its handlers to check for themselves. Each SyncHandler must define a accept_shotgun_event() and accept_jira_event() which overrides the Syncer base class. This is where the more specific logic for accepting or rejecting an event can occur. Checks for things like whether the event is for a Shotgun Entity type or Jira resource type that the handler cares about are appropriate. Or for example, you may wish to check a Shotgun event to see if the Task field that was changed, is one that is supported by your handler.

The goal of these methods is to quickly determine whether to process the event given the information provided. Queries are expensive. If after checking all of the given event info, there are still more questions to answer that require making additional queries to Shotgun or Jira, it is perfectly fine for these to be done in the process_shotgun_event() or process_jira_event() methods later.

Processing the Event

process_shotgun_event() and process_jira_event() process the event data, perform any additional validation required to determine whether to continue with the sync (which may include additional queries to Jira and/or Shotgun), and then do the actual update.

Once the event itself has been validated fully, the actual data that has changed is validated and converted to a format appropriate for the recipient of the sync. There are private methods in the base classes that perform some of the heavy lifting for this.

If the event was processed successfully, it returns True. If the event was not processed for any reason it returns False.

EntityIssueHandler

In addition to the base SyncHandler, there is also a EntityIssueHandler which serves as a base class for handlers that sync between a Shotgun Entity type and a Jira Issue resource. Since this is probably how a majority of workflows will work, it is provided to add an additional level of convenience.

It inherits from SyncHandler. When using EntityIssueHander as a base class, the following methods must be overridden in addition to the ones required by SyncHandler:

_get_jira_issue_field_for_shotgun_field()
_supported_shotgun_fields_for_jira_event()
_get_shotgun_entity_field_for_issue_field()

API

Connections to Shotgun and Jira

These classes manage the specific connections to Shotgun and Jira.

ShotgunSession

class sg_jira.shotgun_session.ShotgunSession(base_url, script_name=None, *args, **kwargs)[source]

Wraps a shotgun_api3.shotgun.Shotgun instance and provide some helpers and session caches.

Ensures all the values we get from Shotgun are unicode and not utf-8 encoded strings. Utf-8 encodes unicode values before sending them to Shotgun.

assert_field(entity_type, field_name, field_type)[source]

Check if the given field with the given type exists for the given Shotgun Entity type.

Parameters:
  • entity_type (str) – A Shotgun Entity type.
  • field_name (str) – A Shotgun field name, e.g. ‘sg_my_precious’.
  • field_type (str) – A Shotgun field type, e.g. ‘text’.
Raises:

RuntimeError – if the field does not exist or does not have the expected type.

clear_cached_field_schema(entity_type=None)[source]

Clear all cached Shotgun schema or just the cached schema for the given Shotgun Entity type.

Parameters:entity_type (str) – A Shotgun Entity type or None.
consolidate_entity(shotgun_entity, fields=None)[source]

Consolidate the given Shotgun Entity: collect additional field values, ensure the Entity name is available under a “name” key.

Parameters:
  • shotgun_entity – A Shotgun Entity dictionary with at least its id and its type.
  • fields – An optional list of fields to add to the query.
Returns:

The consolidated Shotgun Entity or None if it can’t be retrieved.

current_user

Return the Shotgun user used for the connection.

Returns:A Shotgun record dictionary with an id key and a type key.
static get_entity_name_field(entity_type)[source]

Return the Shotgun name field to use for the specified entity type.

Parameters:entity_type (str) – The entity type to get the name field for.
Returns:The name field for the specified entity type.
get_entity_page_url(shotgun_entity)[source]

Return the Shotgun page url for the given Entity.

Parameters:shotgun_entity – A Shotgun Entity dictionary with at least a ‘type’ key and an ‘id’ key.
get_field_schema(entity_type, field_name)[source]

Return the Shotgun schema for the given Entity field.

Note

Shotgun schemas are cached and the bridge needs to be restarted if schemas are changed in Shotgun.

Parameters:
  • entity_type (str) – A Shotgun Entity type.
  • field_name (str) – A Shotgun field name, e.g. ‘sg_my_precious’.
Returns:

The Shotgun schema for the given field as a dictionary or None.

is_project_entity(entity_type)[source]

Return True if the given Shotgun Entity type is a project Entity, that is an Entity linked to a Project, False if it is a non-project Entity.

Parameters:entity_type (str) – A Shotgun Entity type.
match_entity_by_name(name, entity_types, shotgun_project)[source]

Retrieve a Shotgun Entity with the given name from the given list of Entity types.

Project Shotgun Entities are restricted to the given Shotgun Project.

Parameters:
  • name (str) – A name to match.
  • entity_types – A list of Shotgun Entity types to consider.
  • shotgun_project – A Shotgun Project dictionary.
Returns:

A Shotgun Entity dictionary or None.

setup()[source]

Check the Shotgun site and cache site level values.

Raises:RuntimeError – if the Shotgun site was not correctly configured to be used with this bridge.

JiraSession

class sg_jira.jira_session.JiraSession(jira_site, *args, **kwargs)[source]

Extend jira.JIRA with helpers.

__init__(jira_site, *args, **kwargs)[source]

Instantiate a JiraSession.

Connect to the given Jira site with given parameters.

Parameters:jira_site (str) – A Jira site url.
Raises:RuntimeError – on Jira connection errors.
create_issue_from_data(jira_project, issue_type, data)[source]

Create an Issue from the given data.

Sanity check the data against Jira create meta data. Try to amend the data, if possible, to complete the Issue creation. Raise ValueError if the data can’t be amended to complete the Issue creation.

Parameters:
  • jira_project – A jira.resources.Project instance.
  • issue_type (str) – The target Issue type name.
  • data – A dictionary where keys are Jira Issue field ids and values are Jira values.
Returns:

A jira.Issue instance.

Raises:
  • RuntimeError – if the Jira create meta data can’t be retrieved.
  • ValueError – if invalid and unfixable data is provided.
find_jira_assignee_for_issue(user_email, jira_project=None, jira_issue=None)[source]

Return a Jira user the given issue can be assigned to, based on the given email address.

A Jira Project must be specified when creating an Issue. A Jira Issue must be specified when editing an Issue.

Parameters:
  • jira_project – A jira.resources.Project instance or None.
  • jira_issue – A jira.Issue instance or None.
  • user_email – An email address as a string.
Returns:

A jira.resources.User instance or None.

Raises:

ValueError – if no Project nor Issue is specified.

find_jira_user(user_email, jira_project=None, jira_issue=None, for_assignment=False)[source]

Return a Jira an assignable user or with browse permission for the given Project or Issue, with the given email address. Either a jira_project or jira_issue must be provided.

Note

Due to problems with user searching in Jira, this method always returns assignable users for the time being.

Parameters:
  • user_email – An email address as a string.
  • jira_project – A jira.resources.Project instance or None.
  • jira_issue – A jira.Issue instance or None.
  • for_assignment – A boolean, if False the user just needs to have read permission. If True the user needs to be suitable for Issue assignments.
Returns:

A jira.resources.User instance or None.

Raises:

ValueError – if no Project nor Issue is specified.

get_jira_issue_edit_meta(jira_issue)[source]

Return the edit metadata for the given Jira Issue.

Parameters:jira_issue – A jira.Issue.
Returns:The Jira Issue edit metadata fields property.
Raises:RuntimeError – if the edit metadata can’t be retrieved for the given Issue.
get_jira_issue_field_id(name)[source]

Return the Jira field id for the Issue field with the given name.

Returns:The id as a string or None if the field is unknown.
jira_shotgun_id_field

Return the id of the Jira field used to store the id of a linked Shotgun Entity.

Two custom fields are used in Jira to store a reference to a Shotgun Entity: its Shotgun Entity type and id. This method returns the id of the Jira field used to store the Shotgun id.

jira_shotgun_type_field

Return the id of the Jira field used to store the type of a linked Shotgun Entity.

Two custom fields are used in Jira to store a reference to a Shotgun Entity: its Shotgun Entity type and id. This method returns the id of the Jira field used to store the Shotgun type.

jira_shotgun_url_field

Return the id of the Jira field used to store the url of a linked Shotgun Entity.

sanitize_jira_update_value(jira_value, jira_field_schema)[source]

Perform sanity checks for the given Jira value and ensure it can be used to update the Jira field with the given schema.

Returns:A Jira value which can safely be used to update the Jira field.
Raises:UserWarning – if a safe value can’t be obtained.
set_jira_issue_status(jira_issue, jira_status_name, comment)[source]

Attempt to change the Jira Issue status to the given value.

Lookup for a Jira transition where the target status is the given one and try to apply it.

Parameters:
  • jira_issue – A jira.Issue instance.
  • jira_status (str) – A Jira status name, e.g. In Progress.
  • comment – A string, a comment to apply to the Jira transition.
Returns:

True if the status could be set, False otherwise.

setup()[source]

Check the Jira site and cache site level values.

Raises:RuntimeError – if the Jira site was not correctly configured to be used with this bridge.

Bridge

This is the main class that holds handles to both Shotgun and Jira and handles dispatching events to both sites.

class sg_jira.Bridge(sg_site, sg_script, sg_script_key, jira_site, jira_user, jira_secret, sync_settings=None, sg_http_proxy=None)[source]

A bridge between Shotgun and Jira.

The bridge handles connections to the Shotgun and Jira servers and dispatches sync events.

__init__(sg_site, sg_script, sg_script_key, jira_site, jira_user, jira_secret, sync_settings=None, sg_http_proxy=None)[source]

Instatiate a new bridge between the given SG site and Jira site.

Parameters:
  • sg_site (str) – A Shotgun site url.
  • sg_script (str) – A Shotgun script user name.
  • sg_script_key (str) – The script user key for the Shotgun script.
  • jira_site (str) – A Jira site url.
  • jira_user (str) – A Jira user name, either his email address or short name.
  • jira_secret (str) – The Jira user password.
  • sync_settings – A dictionary where keys are settings names.
  • sg_http_proxy (str) – Optional, a http proxy to use for the Shotgun connection, or None.
current_jira_username

Return the username of the current Jira user.

The jira API escapes special characters using %xx syntax when storing the username. For example, the username richard+hendricks is stored as richard%2bhendricks by the jira API. We decode the username here before returning it to ensure we return the exact value (eg. richard+hendricks)

Returns:A string with the username.
current_shotgun_user

Return the Shotgun user used for the connection.

Returns:A Shotgun record dictionary with an id key and a type key.
classmethod get_bridge(settings_file)[source]

Read the given settings and instantiate a new Bridge with them.

Parameters:settings_file (str) – Path to a settings Python file.
Raises:ValueError – on missing required settings.
get_syncer(name)[source]

Returns a Syncer instance for the given settings name.

Parameters:str – A settings name.
Raises:ValueError – for invalid settings.
jira

Return a connected JiraSession instance.

classmethod read_settings(settings_file)[source]

Read the given settings file.

Parameters:settings_file (str) – Path to a settings Python file.
Returns:A dictionary with the settings.
Raises:ValueError – if the file does not exist or if its name does not end with .py.
shotgun

Return a connected ShotgunSession instance.

sync_in_jira(settings_name, entity_type, entity_id, event, **kwargs)[source]

Sync the given Shotgun Entity to Jira.

Parameters:
  • settings_name (str) – The name of the settings to use for this sync.
  • entity_type (str) – The Shotgun Entity type to sync.
  • entity_id (int) – The id of the Shotgun Entity to sync.
  • event – A dictionary with the event meta data for the change.
Returns:

True if the Entity was actually synced in Jira, False if syncing was skipped for any reason.

sync_in_shotgun(settings_name, resource_type, resource_id, event, **kwargs)[source]

Sync the given Jira Resource to Shotgun.

Parameters:
  • settings_name (str) – The name of the settings to use for this sync.
  • resource_type (str) – The type of Jira resource sync, e.g. Issue.
  • resource_id (str) – The id of the Jira resource to sync.
  • event – A dictionary with the event meta data for the change.
Returns:

True if the resource was actually synced in Shotgun, False if syncing was skipped for any reason.

sync_settings_names

Return the list of sync settings this bridge handles.

Syncers

Base class in charge of initially determining whether to accept events from Shotgun and Jira for syncing. If accepted, it then passes on the event to a Handler to process the event.

This must be subclassed to implement a list of Handlers to dispatch events to. Additional parameters can be accepted as well to pass on to Handlers.

from .syncer import Syncer
from .handlers import TaskIssueHandler, NoteCommentHandler, EnableSyncingHandler


class TaskIssueSyncer(Syncer):
    """
    Sync Shotgun Tasks as Jira Issues.
    """
    def __init__(self, issue_type="Task", **kwargs):
        """
        Instatiate a new Task/Issue syncer for the given bridge.

        :param str issue_type: Jira Issue type to use when creating new Issues.
        """
        self._issue_type = issue_type
        super(TaskIssueSyncer, self).__init__(**kwargs)
        self._task_issue_handler = TaskIssueHandler(self, self._issue_type)
        self._note_comment_handler = NoteCommentHandler(self)
        # A handler combining the Task <-> Issue handler and the Note <-> Comment
        # handler. Task syncing to Jira starts if the Task "Sync in Jira" checkbox
        # is turned on. Notes linked to a Task being actively synced are automatically
        # synced without having to manually select them. A full sync is performed
        # when the Task checkbox is turned on.
        self._enable_syncing_handler = EnableSyncingHandler(
            self,
            [self._task_issue_handler, self._note_comment_handler]
        )

    @property
    def handlers(self):
        """
        Return a list of :class:`~handlers.SyncHandler` instances.
        """
        return [
            self._enable_syncing_handler,
            self._task_issue_handler,
            self._note_comment_handler
        ]

Syncer

class sg_jira.Syncer(name, bridge, **kwargs)[source]

A class handling syncing between Shotgun and Jira.

All Syncers should define a list of SyncHandler which should reject or accept and process events.

__init__(name, bridge, **kwargs)[source]

Instatiate a new syncer for the given bridge.

Parameters:
  • name (str) – A unique name for the syncer.
  • bridge – A Bridge instance.
accept_jira_event(resource_type, resource_id, event)[source]

Accept or reject the given event for the given Jira resource.

Parameters:
  • resource_type (str) – The type of Jira resource sync, e.g. Issue.
  • resource_id (str) – The id of the Jira resource to sync.
  • event – A dictionary with the event meta data for the change.
Returns:

A SyncHandler instance if the event is accepted for processing, None otherwise.

accept_shotgun_event(entity_type, entity_id, event)[source]

Accept or reject the given event for the given Shotgun Entity.

Returns:A SyncHandler instance if the event is accepted for processing, None otherwise.
bridge

Returns the Bridge instance used by this syncer.

get_jira_project(project_key)[source]

Retrieve the Jira Project with the given key, if any.

Returns:A jira.resources.Project instance or None.
handlers

Needs to be re-implemented in deriving classes and return a list of SyncHandler instances.

jira

Return a connected Jira handle.

setup()[source]

Check the Jira and Shotgun site, ensure that the sync can safely happen and cache any value which is slow to retrieve.

shotgun

Return a connected ShotgunSession instance.

SyncHandlers

Base class that handles a particular sync instance between Shotgun and Jira.

Handlers hold the main logic for syncing values between a Shotgun Entity type and a Jira resource. They are owned by a Syncer instance. This base class defines the interface all handlers should support and provides helpers methods useful to all implementations.

SyncHandler

class sg_jira.handlers.SyncHandler(syncer)[source]

Base class to handle a particular sync between Shotgun and Jira.

Handlers typically handle syncing values between a Shotgun Entity type and a Jira resource and are owned by a Syncer instance.

This base class defines the interface all handlers should support and provides some helpers which can be useful to all handlers.

__init__(syncer)[source]

Instantiate a handler for the given syncer.

Parameters:syncer – A Syncer instance.
accept_jira_event(resource_type, resource_id, event)[source]

Accept or reject the given event for the given Jira resource.

Must be re-implemented in deriving classes.

Parameters:
  • resource_type (str) – The type of Jira resource sync, e.g. Issue.
  • resource_id (str) – The id of the Jira resource to sync.
  • event – A dictionary with the event meta data for the change.
Returns:

True if the event is accepted for processing, False otherwise.

accept_shotgun_event(entity_type, entity_id, event)[source]

Accept or reject the given event for the given Shotgun Entity.

Must be re-implemented in deriving classes.

Returns:True if the event is accepted for processing, False otherwise.
get_jira_issue(issue_key)[source]

Retrieve the Jira Issue with the given key, if any.

Parameters:issue_key (str) – A Jira Issue key to look for.
Returns:A jira.Issue instance or None.
Raises:RuntimeError – if the Issue if not bound to any Project.
get_jira_project(project_key)[source]

Retrieve the Jira Project with the given key, if any.

Returns:A jira.resources.Project instance or None.
process_jira_event(resource_type, resource_id, event)[source]

Process the given Jira event for the given Jira resource.

Must be re-implemented in deriving classes.

Parameters:
  • resource_type (str) – The type of Jira resource sync, e.g. Issue.
  • resource_id (str) – The id of the Jira resource to sync.
  • event – A dictionary with the event meta data for the change.
Returns:

True if the event was successfully processed, False if the sync didn’t happen for any reason.

process_shotgun_event(entity_type, entity_id, event)[source]

Process the given Shotgun event for the given Shotgun Entity

Must be re-implemented in deriving classes.

Parameters:
  • entity_type (str) – The Shotgun Entity type to sync.
  • entity_id (int) – The id of the Shotgun Entity to sync.
  • event – A dictionary with the event for the change.
Returns:

True if the event was successfully processed, False if the sync didn’t happen for any reason.

setup()[source]

This method can be re-implemented in deriving classes to Check the Jira and Shotgun site, ensure that the sync can safely happen and cache any value which is slow to retrieve.

This base implementation does nothing.

EntityIssueHandler

Base class for syncing Shotgun Entities and Jira Issues. This inherits from SyncHandler.

class sg_jira.handlers.EntityIssueHandler(syncer, issue_type)[source]

Bases: sg_jira.handlers.sync_handler.SyncHandler

Base class for handlers syncing a Shotgun Entity to a Jira Issue.

__init__(syncer, issue_type)[source]

Instantiate an Entity Issue handler for the given syncer.

Parameters:
  • syncer – A Syncer instance.
  • issue_type (str) – A target Issue type, e.g. ‘Task’, ‘Story’.
accept_jira_event(resource_type, resource_id, event)[source]

Accept or reject the given event for the given Jira resource.

Parameters:
  • resource_type (str) – The type of Jira resource sync, e.g. Issue.
  • resource_id (str) – The id of the Jira resource to sync.
  • event – A dictionary with the event meta data for the change.
Returns:

True if the event is accepted for processing, False otherwise.

accept_shotgun_event(entity_type, entity_id, event)

Accept or reject the given event for the given Shotgun Entity.

Must be re-implemented in deriving classes.

Returns:True if the event is accepted for processing, False otherwise.
get_jira_issue(issue_key)

Retrieve the Jira Issue with the given key, if any.

Parameters:issue_key (str) – A Jira Issue key to look for.
Returns:A jira.Issue instance or None.
Raises:RuntimeError – if the Issue if not bound to any Project.
get_jira_project(project_key)

Retrieve the Jira Project with the given key, if any.

Returns:A jira.resources.Project instance or None.
process_jira_event(resource_type, resource_id, event)[source]

Process the given Jira event for the given Jira resource.

Parameters:
  • resource_type (str) – The type of Jira resource to sync, e.g. Issue.
  • resource_id (str) – The id of the Jira resource to sync.
  • event – A dictionary with the event meta data for the change.
Returns:

True if the event was successfully processed, False if the sync didn’t happen for any reason.

process_shotgun_event(entity_type, entity_id, event)

Process the given Shotgun event for the given Shotgun Entity

Must be re-implemented in deriving classes.

Parameters:
  • entity_type (str) – The Shotgun Entity type to sync.
  • entity_id (int) – The id of the Shotgun Entity to sync.
  • event – A dictionary with the event for the change.
Returns:

True if the event was successfully processed, False if the sync didn’t happen for any reason.

setup()

This method can be re-implemented in deriving classes to Check the Jira and Shotgun site, ensure that the sync can safely happen and cache any value which is slow to retrieve.

This base implementation does nothing.

EnableSyncingHandler

A handler that controls the initial sync for a Shotgun Task and Jira Issue when the “Sync In Jira” checkbox is toggled in Shotgun. It combines multiple handlers to begin the syncing process by performing a full sync each time the checkbox is toggled on. This allows one to manually force a re-sync if needed by just toggling the checkbox off and then on again.

Inherits from SyncHandler.

class sg_jira.handlers.EnableSyncingHandler(syncer, handlers)[source]

A handler which combines multiple handlers to start syncing Tasks and Entities linked to them when a Task “Sync In Jira” (sg_sync_in_jira) checkbox field is changed in Shotgun.

A full sync is performed each time the checkbox is turned on. This allows to manually force a re-sync if needed by just setting off the checkbox, and then back to on.

__init__(syncer, handlers)[source]

Instantiate a new handler which combines the provided handlers.

The first handler in the list is assumed to be a primary handler, the others are assumed to be secondary handlers.

Events will be sent to secondary handlers for processing only if the primary handler was able to successfully process them.

This allows to control from the primary handler if a Shotgun Entity should be synced or not, and then automatically start syncing secondary Entities which are linked to this primary Entity, e.g. Notes on a Task, without having to explicitely enable syncing for the linked Entities.

Combined handlers shouldn’t accept the events which are accepted by this handler, but they need to be able to process them.

Parameters:
  • syncer – A Syncer instance.
  • handlers – A non empty list of SyncHandler instances.
accept_jira_event(resource_type, resource_id, event)[source]

Accept or reject the given event for the given Jira resource.

This handler rejects all Jira events.

Parameters:
  • resource_type (str) – The type of Jira resource sync, e.g. Issue.
  • resource_id (str) – The id of the Jira resource to sync.
  • event – A dictionary with the event meta data for the change.
Returns:

True if the event is accepted for processing, False otherwise.

accept_shotgun_event(entity_type, entity_id, event)[source]

Accept or reject the given event for the given Shotgun Entity.

Returns:True if the event is accepted for processing, False otherwise.
get_jira_issue(issue_key)

Retrieve the Jira Issue with the given key, if any.

Parameters:issue_key (str) – A Jira Issue key to look for.
Returns:A jira.Issue instance or None.
Raises:RuntimeError – if the Issue if not bound to any Project.
get_jira_project(project_key)

Retrieve the Jira Project with the given key, if any.

Returns:A jira.resources.Project instance or None.
process_jira_event(resource_type, resource_id, event)

Process the given Jira event for the given Jira resource.

Must be re-implemented in deriving classes.

Parameters:
  • resource_type (str) – The type of Jira resource sync, e.g. Issue.
  • resource_id (str) – The id of the Jira resource to sync.
  • event – A dictionary with the event meta data for the change.
Returns:

True if the event was successfully processed, False if the sync didn’t happen for any reason.

process_shotgun_event(entity_type, entity_id, event)[source]

Process the given Shotgun event for the given Shotgun Entity

Parameters:
  • entity_type (str) – The Shotgun Entity type to sync.
  • entity_id (int) – The id of the Shotgun Entity to sync.
  • event – A dictionary with the event for the change.
setup()[source]

Check the Jira and Shotgun site, ensure that the sync can safely happen. This can be used as well to cache any value which is slow to retrieve.

Run all handlers setup.

Utils

Common utility functions.

sg_jira.utils.unicode_to_utf8(value)[source]

Convert any unicode in the given input to an utf8 encoded string value.

Treat containers by recursively iterating over all the values they contain.

Parameters:value – A string, a list, a tuple, or a dictionary.
Returns:The value with all unicode values converted to strings.
Raises:ValueError – if a converted UTF-8 encoded key is already present in the original value of a dictionary.
sg_jira.utils.utf8_to_unicode(value)[source]

Convert any string in the given input to unicode. Strings are expected to be in utf-8 encoding.

Treat containers by recursively iterating over all the values they contain.

Parameters:value – A string, a list, a tuple, or a dictionary.
Returns:The value with all strings converted to unicode.
Raises:ValueError – if a converted UTF-8 decoded key is already present in the original value of a dictionary.

Errors

exception sg_jira.errors.InvalidJiraValue(field, value, *args, **kwargs)[source]

An exception raised when a Jira value can’t be translated to a valid Shotgun value for a given field.

field

Return the field for which the exception was raised.

value

Return the value for which the exception was raised.

exception sg_jira.errors.InvalidShotgunValue(field, value, *args, **kwargs)[source]

An exception raised when a Shotgun value can’t be translated to a valid Jira value for a given field.

field

Return the field for which the exception was raised.

value

Return the value for which the exception was raised.

exception sg_jira.errors.InvalidSyncValue(field, value, *args, **kwargs)[source]

Base class for exceptions raised when a value can’t be translated to a valid value for a given field.

field

Return the field for which the exception was raised.

value

Return the value for which the exception was raised.

Tests & CI

Unit tests are in the /tests folder. A requirements.txt file is available in this folder as well to install the required modules to run the tests.

Run the tests from the tests directory with python run_tests.py.

Continuous Integration (CI)

Azure Pipelines are used for the continuous integration and run the following validations:

  • Enforce reasonable PEP-8 conventions with Flake8.
  • Run unit tests on Linux, Mac and Windows with Python 2.7.

Azure Pipelines jobs are defined by the description files in the /azure-pipelines folder.