Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ticket): allows incident title in ticket name #5397

Merged
merged 2 commits into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
"""Adds configuration to the Dispatch Ticket PluginInstance

Revision ID: 24322617ce9a
Revises: 3c49f62d7914
Create Date: 2024-10-25 15:15:38.078421

"""

from alembic import op
from pydantic import SecretStr, ValidationError
from pydantic.json import pydantic_encoder

from sqlalchemy import Column, Integer, ForeignKey, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship, Session
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy_utils import StringEncryptedType
from sqlalchemy_utils.types.encrypted.encrypted_type import AesEngine
from dispatch.config import DISPATCH_ENCRYPTION_KEY

# revision identifiers, used by Alembic.
revision = "24322617ce9a"
down_revision = "3c49f62d7914"
branch_labels = None
depends_on = None

Base = declarative_base()


def show_secrets_encoder(obj):
if isinstance(obj, SecretStr):
return obj.get_secret_value()
else:
return pydantic_encoder(obj)


def migrate_config(instances, slug, config):
for instance in instances:
if slug == instance.plugin.slug:
instance.configuration = config


class Plugin(Base):
__tablename__ = "plugin"
__table_args__ = {"schema": "dispatch_core"}
id = Column(Integer, primary_key=True)
slug = Column(String, unique=True)


class PluginInstance(Base):
__tablename__ = "plugin_instance"
id = Column(Integer, primary_key=True)
_configuration = Column(
StringEncryptedType(key=str(DISPATCH_ENCRYPTION_KEY), engine=AesEngine, padding="pkcs5")
)
plugin_id = Column(Integer, ForeignKey(Plugin.id))
plugin = relationship(Plugin, backref="instances")

@hybrid_property
def configuration(self):
"""Property that correctly returns a plugins configuration object."""
pass

@configuration.setter
def configuration(self, configuration):
"""Property that correctly sets a plugins configuration object."""
if configuration:
self._configuration = configuration.json(encoder=show_secrets_encoder)


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
from dispatch.plugins.dispatch_core.config import DispatchTicketConfiguration

bind = op.get_bind()
session = Session(bind=bind)

instances = session.query(PluginInstance).all()

try:
dispatch_ticket_config = DispatchTicketConfiguration(
use_incident_name=False,
)

migrate_config(instances, "dispatch-ticket", dispatch_ticket_config)

except ValidationError:
print(
"Skipping automatic migration of Dispatch ticket plugin, if you are using the Dispatch ticket plugin, please manually migrate."
)

session.commit()
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
pass
# ### end Alembic commands ###
13 changes: 12 additions & 1 deletion src/dispatch/plugins/dispatch_core/config.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
import logging
from dispatch.config import BaseConfigurationModel

from starlette.config import Config

from pydantic import Field

log = logging.getLogger(__name__)


config = Config(".env")


class DispatchTicketConfiguration(BaseConfigurationModel):
"""Dispatch ticket configuration"""

use_incident_name: bool = Field(
True,
title="Use Incident Name",
description="Use the incident name as the ticket title.",
)
13 changes: 10 additions & 3 deletions src/dispatch/plugins/dispatch_core/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@
from dispatch.service.models import Service, ServiceRead
from dispatch.team import service as team_service
from dispatch.team.models import TeamContact, TeamContactRead
from dispatch.plugins.dispatch_core.config import DispatchTicketConfiguration
from dispatch.plugins.dispatch_core.service import create_resource_id

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -175,6 +177,9 @@ class DispatchTicketPlugin(TicketPlugin):
author = "Netflix"
author_url = "https://github.com/netflix/dispatch.git"

def __init__(self):
self.configuration_schema = DispatchTicketConfiguration

def create(
self,
incident_id: int,
Expand All @@ -187,9 +192,11 @@ def create(
"""Creates a Dispatch incident ticket."""
incident = incident_service.get(db_session=db_session, incident_id=incident_id)

resource_id = (
f"dispatch-{incident.project.organization.slug}-{incident.project.slug}-{incident.id}"
)
if self.configuration and self.configuration.use_incident_name:
resource_id = create_resource_id(f"{incident.project.slug}-{title}-{incident.id}")
else:
resource_id = f"dispatch-{incident.project.organization.slug}-{incident.project.slug}-{incident.id}"

return {
"resource_id": resource_id,
"weblink": f"{DISPATCH_UI_URL}/{incident.project.organization.name}/incidents/{resource_id}?project={incident.project.name}",
Expand Down
20 changes: 20 additions & 0 deletions src/dispatch/plugins/dispatch_core/service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import re


def create_resource_id(title: str) -> str:
"""Creates a Slack-friendly resource id from the incident title."""
resource_id = title.lower()

# Replace any character that is not a lowercase letter or number with a hyphen
resource_id = re.sub(r"[^a-z0-9]", "-", resource_id)

# Replace multiple consecutive hyphens with a single hyphen
resource_id = re.sub(r"-+", "-", resource_id)

# Ensure the channel name is not longer than 80 characters
resource_id = resource_id[:80]

# Remove leading or trailing hyphens
resource_id = resource_id.strip("-")

return resource_id
Loading