firefighter-incident 0.0.22__tar.gz → 0.0.23__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/PKG-INFO +1 -1
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/_version.py +2 -2
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/api/serializers.py +18 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/api/views/incidents.py +3 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/confluence/models.py +66 -6
- firefighter_incident-0.0.23/firefighter/confluence/signals/incident_updated.py +36 -0
- firefighter_incident-0.0.23/firefighter/firefighter/settings/components/jira_app.py +54 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/admin.py +3 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/models/impact.py +3 -5
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/models/incident.py +24 -9
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/views/views.py +2 -0
- firefighter_incident-0.0.23/firefighter/jira_app/admin.py +38 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/jira_app/apps.py +3 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/jira_app/client.py +151 -3
- firefighter_incident-0.0.23/firefighter/jira_app/management/__init__.py +1 -0
- firefighter_incident-0.0.23/firefighter/jira_app/management/commands/__init__.py +1 -0
- firefighter_incident-0.0.23/firefighter/jira_app/migrations/0002_add_jira_postmortem_model.py +71 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/jira_app/models.py +50 -0
- firefighter_incident-0.0.23/firefighter/jira_app/service_postmortem.py +292 -0
- firefighter_incident-0.0.23/firefighter/jira_app/signals/__init__.py +10 -0
- firefighter_incident-0.0.23/firefighter/jira_app/signals/incident_key_events_updated.py +88 -0
- firefighter_incident-0.0.23/firefighter/jira_app/signals/postmortem_created.py +155 -0
- firefighter_incident-0.0.23/firefighter/jira_app/templates/jira/postmortem/impact.txt +12 -0
- firefighter_incident-0.0.23/firefighter/jira_app/templates/jira/postmortem/incident_summary.txt +17 -0
- firefighter_incident-0.0.23/firefighter/jira_app/templates/jira/postmortem/mitigation_actions.txt +9 -0
- firefighter_incident-0.0.23/firefighter/jira_app/templates/jira/postmortem/root_causes.txt +12 -0
- firefighter_incident-0.0.23/firefighter/jira_app/templates/jira/postmortem/timeline.txt +7 -0
- firefighter_incident-0.0.23/firefighter/raid/signals/incident_updated.py +59 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/messages/slack_messages.py +39 -3
- firefighter_incident-0.0.23/firefighter/slack/signals/postmortem_created.py +84 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/modals/closure_reason.py +15 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/modals/key_event_message.py +9 -0
- firefighter_incident-0.0.23/firefighter/slack/views/modals/postmortem.py +79 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/modals/update_status.py +7 -1
- firefighter_incident-0.0.23/firefighter_tests/test_api/test_renderer.py +41 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_incidents/test_models/test_incident_model.py +29 -0
- firefighter_incident-0.0.23/firefighter_tests/test_jira_app/test_incident_key_events_sync.py +112 -0
- firefighter_incident-0.0.23/firefighter_tests/test_jira_app/test_models.py +138 -0
- firefighter_incident-0.0.23/firefighter_tests/test_jira_app/test_postmortem_issue_link.py +201 -0
- firefighter_incident-0.0.23/firefighter_tests/test_jira_app/test_postmortem_service.py +416 -0
- firefighter_incident-0.0.23/firefighter_tests/test_jira_app/test_timeline_template.py +135 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_raid/test_raid_signals.py +50 -8
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_slack/messages/test_slack_messages.py +112 -23
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_slack/views/modals/test_closure_reason_modal.py +18 -2
- firefighter_incident-0.0.23/firefighter_tests/test_slack/views/modals/test_key_event_message.py +30 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_slack/views/modals/test_update_status.py +161 -129
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/pyproject.toml +2 -0
- firefighter_incident-0.0.22/firefighter/confluence/signals/incident_updated.py +0 -54
- firefighter_incident-0.0.22/firefighter/firefighter/settings/components/jira_app.py +0 -21
- firefighter_incident-0.0.22/firefighter/jira_app/admin.py +0 -24
- firefighter_incident-0.0.22/firefighter/raid/signals/incident_updated.py +0 -39
- firefighter_incident-0.0.22/firefighter/slack/signals/postmortem_created.py +0 -36
- firefighter_incident-0.0.22/firefighter/slack/views/modals/postmortem.py +0 -87
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/.gitignore +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/LICENSE +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/README.md +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/api/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/api/admin.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/api/apps.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/api/authentication.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/api/migrations/0001_initial.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/api/migrations/0002_alter_apitokenproxy_options.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/api/migrations/0003_alter_apitokenproxy_options.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/api/migrations/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/api/models.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/api/permissions.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/api/renderer.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/api/urls.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/api/views/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/api/views/_base.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/api/views/components.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/api/views/environments.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/api/views/groups.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/api/views/incident_cost_types.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/api/views/incident_costs.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/api/views/severities.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/components/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/components/avatar/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/components/avatar/avatar.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/components/avatar/avatar.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/components/card/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/components/card/card.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/components/card/card.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/components/export_button/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/components/export_button/export_button.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/components/export_button/export_button.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/components/form/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/components/form/form.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/components/form/form.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/components/form_field/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/components/form_field/form_field.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/components/form_field/form_field.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/components/messages/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/components/messages/messages.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/components/messages/messages.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/components/modal/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/components/modal/modal.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/components/modal/modal.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/confluence/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/confluence/admin.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/confluence/apps.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/confluence/client.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/confluence/management/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/confluence/management/commands/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/confluence/management/commands/sort_postmortems.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/confluence/management/commands/sort_runbooks.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/confluence/management/commands/sync_postmortems.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/confluence/management/commands/sync_runbooks.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/confluence/migrations/0001_initial_oss.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/confluence/migrations/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/confluence/serializers.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/confluence/service.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/confluence/signals/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/confluence/tables.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/confluence/tasks/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/confluence/tasks/archive_postmortems.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/confluence/tasks/sort_runbooks.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/confluence/tasks/sync_pages_content.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/confluence/tasks/sync_postmortems.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/confluence/tasks/sync_runbooks.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/confluence/templates/oncall_team.xml +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/confluence/templates/pages/runbook_list.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/confluence/urls.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/confluence/utils.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/confluence/views/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/confluence/views/api.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/confluence/views/postmortem/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/confluence/views/postmortem/postmortem_detail.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/confluence/views/runbook/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/confluence/views/runbook/runbook_list.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/firefighter/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/firefighter/admin.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/firefighter/apps.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/firefighter/asgi.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/firefighter/celery_client.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/firefighter/fields_forms_widgets.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/firefighter/filters.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/firefighter/formats/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/firefighter/formats/en/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/firefighter/formats/en/formats.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/firefighter/http_client.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/firefighter/management/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/firefighter/management/commands/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/firefighter/management/commands/task.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/firefighter/middleware.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/firefighter/settings/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/firefighter/settings/components/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/firefighter/settings/components/api.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/firefighter/settings/components/caches.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/firefighter/settings/components/celery.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/firefighter/settings/components/common.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/firefighter/settings/components/confluence.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/firefighter/settings/components/logging.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/firefighter/settings/components/pagerduty.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/firefighter/settings/components/raid.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/firefighter/settings/components/slack.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/firefighter/settings/environments/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/firefighter/settings/environments/dev.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/firefighter/settings/environments/prod.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/firefighter/settings/settings_builder.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/firefighter/settings/settings_utils.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/firefighter/sso.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/firefighter/tables_utils.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/firefighter/templates/admin/base.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/firefighter/templates/admin/login.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/firefighter/templates/admin/send_message_conversation.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/firefighter/templates/robots.txt +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/firefighter/urls.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/firefighter/utils.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/firefighter/views.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/firefighter/wsgi.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/apps.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/enums.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/factories.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/forms/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/forms/close_incident.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/forms/closure_reason.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/forms/create_incident.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/forms/edit.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/forms/select_impact.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/forms/unified_incident.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/forms/update_key_events.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/forms/update_roles.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/forms/update_status.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/forms/utils.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/menus.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/migrations/0001_initial_oss.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/migrations/0002_alter_severity_name_alter_user_password_featureteam.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/migrations/0003_delete_featureteam.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/migrations/0004_incidentupdate_environment.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/migrations/0005_enable_from_p1_to_p5_priority.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/migrations/0006_update_group_names.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/migrations/0007_update_component_name.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/migrations/0008_impact_level.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/migrations/0009_update_sla.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/migrations/0010_update_components.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/migrations/0011_update_incidents.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/migrations/0012_alter_impactlevel.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/migrations/0013_add_missing_component.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/migrations/0014_update_components_slack_groups.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/migrations/0015_update_impact_level.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/migrations/0016_update_business_incidents_and_level.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/migrations/0017_reorder_impact_types.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/migrations/0018_update_impactlevel_names.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/migrations/0019_set_security_components_private.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/migrations/0020_create_incident_category_model.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/migrations/0021_copy_component_data_to_incident_category.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/migrations/0022_add_incident_category_fields.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/migrations/0023_populate_incident_category_references.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/migrations/0024_remove_component_fields_and_model.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/migrations/0025_make_incident_category_required.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/migrations/0026_alter_incidentcategory_options_and_more.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/migrations/0027_add_closure_fields.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/migrations/0028_add_closure_reason_constraint.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/migrations/0029_add_custom_fields_to_incident.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/migrations/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/models/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/models/environment.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/models/group.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/models/incident_category.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/models/incident_cost.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/models/incident_cost_type.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/models/incident_membership.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/models/incident_role_type.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/models/incident_update.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/models/metric_type.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/models/milestone_type.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/models/priority.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/models/severity.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/models/user.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/signals.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/static/css/incident.css +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/static/css/main.css +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/static/css/main.min.css +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/static/css/tailwind.css +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/static/img/favicon/android-chrome-192x192.png +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/static/img/favicon/android-chrome-512x512.png +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/static/img/favicon/apple-touch-icon.png +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/static/img/favicon/favicon-16x16.png +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/static/img/favicon/favicon-32x32.png +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/static/img/favicon/favicon.ico +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/static/img/favicon/site.webmanifest +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/static/img/gameday.png +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/static/img/logo-firefighter.png +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/static/img/p1.png +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/static/img/p2.png +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/static/img/p3.png +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/static/img/p4.png +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/static/img/p5.png +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/static/js/main.js +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/static/js/main.min.js +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/tables.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/tasks/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/tasks/updateoncall.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/templates/incidents/errors/base.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/templates/incidents/filter.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/templates/incidents/table/priority_column.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/templates/incidents/table/status_column.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/templates/incidents/table.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/templates/incidents/widgets/form_container.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/templates/incidents/widgets/grouped_checkbox_nested.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/templates/incidents/widgets/input_option.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/templates/layouts/index.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/templates/layouts/partials/created_at_help.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/templates/layouts/partials/environment_pill.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/templates/layouts/partials/footer.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/templates/layouts/partials/header.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/templates/layouts/partials/incident_card.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/templates/layouts/partials/incident_metrics.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/templates/layouts/partials/incident_timeline.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/templates/layouts/partials/incident_update_key_events_view.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/templates/layouts/partials/incident_update_key_events_view_modal.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/templates/layouts/partials/partial_table_list_paginated.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/templates/layouts/partials/priority_icon.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/templates/layouts/partials/priority_pill.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/templates/layouts/partials/status_pill.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/templates/layouts/partials/table.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/templates/layouts/partials/user_card.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/templates/layouts/partials/user_tooltip.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/templates/layouts/view_filters.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/templates/pages/dashboard.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/templates/pages/docs_metrics.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/templates/pages/incident_category_detail.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/templates/pages/incident_category_list.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/templates/pages/incident_create.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/templates/pages/incident_detail.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/templates/pages/incident_list.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/templates/pages/incident_role_types_detail.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/templates/pages/incident_role_types_list.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/templates/pages/incident_statistics.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/templates/pages/incident_statistics_partial.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/templates/pages/incident_update_key_events_form.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/templates/pages/user_detail.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/urls.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/views/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/views/components/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/views/components/details.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/views/components/list.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/views/date_filter.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/views/date_utils.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/views/docs/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/views/docs/metrics.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/views/docs/role_types.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/views/errors.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/views/reports.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/views/users/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/views/users/details.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/jira_app/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/jira_app/migrations/0001_initial_oss.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/jira_app/migrations/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/jira_app/tasks/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/jira_app/tasks/sync_users_jira.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/jira_app/types.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/jira_app/utils.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/logging/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/logging/custom_json_formatter.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/logging/pretty_formatter.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/pagerduty/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/pagerduty/admin.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/pagerduty/apps.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/pagerduty/client.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/pagerduty/forms/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/pagerduty/forms/create_pagerduty_incident.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/pagerduty/migrations/0001_initial_oss.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/pagerduty/migrations/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/pagerduty/models.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/pagerduty/service.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/pagerduty/signals/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/pagerduty/signals/get_invites_from_pagerduty.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/pagerduty/signals/incident_channel_done_oncall.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/pagerduty/tasks/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/pagerduty/tasks/fetch_oncall.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/pagerduty/tasks/fetch_services.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/pagerduty/tasks/fetch_users.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/pagerduty/tasks/trigger_oncall.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/pagerduty/templates/pages/oncall_list.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/pagerduty/templates/pages/oncall_trigger.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/pagerduty/templates/partials/trigger_oncall_form_view.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/pagerduty/templates/partials/trigger_oncall_form_view_modal.html +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/pagerduty/urls.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/pagerduty/views/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/pagerduty/views/oncall_list.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/pagerduty/views/oncall_trigger.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/raid/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/raid/admin.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/raid/apps.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/raid/client.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/raid/forms.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/raid/messages.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/raid/migrations/0001_initial_oss.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/raid/migrations/0002_featureteam_remove_qualifierrotation_jira_user_and_more.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/raid/migrations/0003_delete_raidarea.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/raid/migrations/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/raid/models.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/raid/resources.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/raid/serializers.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/raid/service.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/raid/signals/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/raid/tasks/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/raid/types.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/raid/urls.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/raid/utils.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/raid/views/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/admin.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/apps.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/factories.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/forms/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/forms/sos_form.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/management/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/management/commands/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/management/commands/generate_manifest.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/management/commands/switch_test_users.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/messages/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/messages/base.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/migrations/0001_initial_oss.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/migrations/0002_usergroup_tag.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/migrations/0003_alter_usergroup_tag.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/migrations/0004_alter_usergroup_components.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/migrations/0005_add_incident_categories_fields.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/migrations/0006_copy_components_to_incident_categories.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/migrations/0007_remove_components_fields.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/migrations/0008_alter_conversation_incident_categories_and_more.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/migrations/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/models/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/models/conversation.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/models/incident_channel.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/models/message.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/models/sos.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/models/user.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/models/user_group.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/rules.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/signals/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/signals/create_incident_conversation.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/signals/get_users.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/signals/handle_incident_channel_done.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/signals/incident_closed.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/signals/incident_updated.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/signals/roles_reminders.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/slack_app.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/slack_incident_context.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/slack_templating.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/tasks/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/tasks/fetch_conversations_members.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/tasks/reminder_postmortem.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/tasks/send_message.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/tasks/send_reminders.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/tasks/sync_users.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/tasks/update_usergroups_members.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/tasks/update_users.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/urls.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/utils.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/events/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/events/actions_and_shortcuts.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/events/channel_archive.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/events/channel_id_changed.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/events/channel_rename.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/events/channel_shared.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/events/channel_unarchive.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/events/channel_unshared.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/events/commands.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/events/home.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/events/member_joined_channel.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/events/member_left_channel.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/events/message.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/events/message_deleted.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/events/reaction_added.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/modals/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/modals/base_modal/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/modals/base_modal/base.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/modals/base_modal/base_mixins.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/modals/base_modal/form_utils.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/modals/base_modal/mixins.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/modals/base_modal/modal_utils.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/modals/close.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/modals/downgrade_workflow.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/modals/edit.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/modals/open.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/modals/opening/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/modals/opening/check_current_incidents.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/modals/opening/details/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/modals/opening/details/unified.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/modals/opening/select_impact.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/modals/opening/set_details.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/modals/opening/types.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/modals/select.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/modals/send_sos.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/modals/status.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/modals/trigger_oncall.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/modals/update.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/modals/update_roles.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/modals/utils.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/slack/views/views.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_fixtures/incidents/environments.json +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_fixtures/incidents/groups.json +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_fixtures/incidents/impact_level.json +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_fixtures/incidents/impact_type.json +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_fixtures/incidents/incident_categories.json +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_fixtures/incidents/incident_role_type.json +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_fixtures/incidents/metric_type.json +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_fixtures/incidents/milestone_type.json +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_fixtures/incidents/priorities.json +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_fixtures/incidents/severities.json +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/conftest.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_api/test_api_landbot.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_api/test_api_urls.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_confluence/test_confluence_utils.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_firefighter/test_firefighter_utils.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_firefighter/test_logging.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_firefighter/test_sso.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_firefighter/test_urls.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_incidents/test_enums.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_incidents/test_forms/conftest.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_incidents/test_forms/test_closure_reason.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_incidents/test_forms/test_form_select_impact.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_incidents/test_forms/test_form_utils.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_incidents/test_forms/test_unified_incident_form.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_incidents/test_forms/test_unified_incident_form_integration.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_incidents/test_forms/test_unified_incident_form_p4_p5.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_incidents/test_forms/test_update_key_events.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_incidents/test_forms/test_update_status_workflow.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_incidents/test_forms/test_workflow_transitions.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_incidents/test_incident_urls.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_incidents/test_models/test_incident_category.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_incidents/test_models/test_migrations/test_incident_migrations.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_incidents/test_utils/test_date_utils.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_incidents/test_views/test_incident_detail_view.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_incidents/test_views/test_index_view.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_jira_app/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_jira_app/conftest.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_jira_app/test_jira_client_watchers.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_raid/conftest.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_raid/test_raid_alert_p4_p5.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_raid/test_raid_client.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_raid/test_raid_client_users.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_raid/test_raid_forms.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_raid/test_raid_models.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_raid/test_raid_serializers.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_raid/test_raid_service.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_raid/test_raid_transitions.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_raid/test_raid_utils.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_raid/test_raid_views.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_raid/test_zendesk_integration.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_slack/conftest.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_slack/messages/__init__.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_slack/test_conversation_tags.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_slack/test_models/test_conversations.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_slack/test_models/test_incident_channel.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_slack/test_models/test_slack_user.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_slack/test_signals_downgrade.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_slack/test_slack_utils.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_slack/views/modals/conftest.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_slack/views/modals/test_close.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_slack/views/modals/test_edit.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_slack/views/modals/test_form_utils_multiple_choice.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_slack/views/modals/test_open.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_slack/views/modals/test_opening_unified.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_slack/views/modals/test_send_sos.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_slack/views/modals/test_status.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter_tests/test_slack/views/modals/test_utils.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/gunicorn.conf.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/main.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/manage.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/package-lock.json +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/package.json +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/scripts/gen_credits.py +0 -0
- {firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/scripts/hatch_build.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: firefighter-incident
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.23
|
|
4
4
|
Summary: Incident Management tool made for Slack using Django
|
|
5
5
|
Project-URL: Repository, https://github.com/ManoManoTech/firefighter-incident
|
|
6
6
|
Project-URL: Documentation, https://manomanotech.github.io/firefighter-incident/latest/
|
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '0.0.
|
|
32
|
-
__version_tuple__ = version_tuple = (0, 0,
|
|
31
|
+
__version__ = version = '0.0.23'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 0, 23)
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
|
@@ -219,6 +219,8 @@ class IncidentSerializer(TaggitSerializer, serializers.ModelSerializer[Incident]
|
|
|
219
219
|
created_by = UserSerializer(read_only=True)
|
|
220
220
|
slack_channel_name = serializers.SerializerMethodField()
|
|
221
221
|
postmortem_url = serializers.SerializerMethodField()
|
|
222
|
+
jira_ticket_key = serializers.SerializerMethodField()
|
|
223
|
+
jira_ticket_url = serializers.SerializerMethodField()
|
|
222
224
|
|
|
223
225
|
created_by_email = CreatableSlugRelatedField[User](
|
|
224
226
|
source="created_by",
|
|
@@ -260,6 +262,20 @@ class IncidentSerializer(TaggitSerializer, serializers.ModelSerializer[Incident]
|
|
|
260
262
|
return obj.postmortem_for.page_url
|
|
261
263
|
return None
|
|
262
264
|
|
|
265
|
+
@staticmethod
|
|
266
|
+
def get_jira_ticket_key(obj: Incident) -> str | None:
|
|
267
|
+
"""Return the Jira ticket key if it exists."""
|
|
268
|
+
if hasattr(obj, "jira_ticket") and obj.jira_ticket:
|
|
269
|
+
return obj.jira_ticket.key
|
|
270
|
+
return None
|
|
271
|
+
|
|
272
|
+
@staticmethod
|
|
273
|
+
def get_jira_ticket_url(obj: Incident) -> str | None:
|
|
274
|
+
"""Return the Jira ticket URL if it exists."""
|
|
275
|
+
if hasattr(obj, "jira_ticket") and obj.jira_ticket:
|
|
276
|
+
return obj.jira_ticket.url
|
|
277
|
+
return None
|
|
278
|
+
|
|
263
279
|
def create(self, validated_data: dict[str, Any]) -> Incident:
|
|
264
280
|
return Incident.objects.declare(**validated_data)
|
|
265
281
|
|
|
@@ -288,6 +304,8 @@ class IncidentSerializer(TaggitSerializer, serializers.ModelSerializer[Incident]
|
|
|
288
304
|
"slack_channel_name",
|
|
289
305
|
"status_page_url",
|
|
290
306
|
"postmortem_url",
|
|
307
|
+
"jira_ticket_key",
|
|
308
|
+
"jira_ticket_url",
|
|
291
309
|
"status",
|
|
292
310
|
"environment_id",
|
|
293
311
|
"incident_category_id",
|
{firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/api/views/incidents.py
RENAMED
|
@@ -78,6 +78,7 @@ class IncidentViewSet(
|
|
|
78
78
|
"environment",
|
|
79
79
|
"conversation",
|
|
80
80
|
"created_by",
|
|
81
|
+
"jira_ticket",
|
|
81
82
|
)
|
|
82
83
|
.prefetch_related(
|
|
83
84
|
Prefetch(
|
|
@@ -118,6 +119,8 @@ class IncidentViewSet(
|
|
|
118
119
|
"created_at",
|
|
119
120
|
"slack_channel_name",
|
|
120
121
|
"status_page_url",
|
|
122
|
+
"jira_ticket_key",
|
|
123
|
+
"jira_ticket_url",
|
|
121
124
|
"metrics.*.duration_seconds",
|
|
122
125
|
"costs.*.amount",
|
|
123
126
|
"roles.*.email",
|
{firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/confluence/models.py
RENAMED
|
@@ -19,16 +19,78 @@ from firefighter.incidents.signals import postmortem_created
|
|
|
19
19
|
|
|
20
20
|
if TYPE_CHECKING:
|
|
21
21
|
from django.db.models import QuerySet
|
|
22
|
+
|
|
23
|
+
from firefighter.jira_app.models import JiraPostMortem
|
|
24
|
+
from firefighter.jira_app.service_postmortem import JiraPostMortemService
|
|
25
|
+
|
|
22
26
|
logger = logging.getLogger(__name__)
|
|
23
27
|
|
|
24
28
|
|
|
29
|
+
def _get_jira_postmortem_service() -> JiraPostMortemService:
|
|
30
|
+
"""Lazy import to avoid circular dependency with jira_app."""
|
|
31
|
+
from firefighter.jira_app.service_postmortem import jira_postmortem_service
|
|
32
|
+
|
|
33
|
+
return jira_postmortem_service
|
|
34
|
+
|
|
35
|
+
|
|
25
36
|
class PostMortemManager(models.Manager["PostMortem"]):
|
|
26
37
|
@staticmethod
|
|
27
|
-
def create_postmortem_for_incident(
|
|
28
|
-
|
|
29
|
-
|
|
38
|
+
def create_postmortem_for_incident(
|
|
39
|
+
incident: Incident,
|
|
40
|
+
) -> tuple[PostMortem | None, JiraPostMortem | None]:
|
|
41
|
+
"""Create post-mortem(s) for incident based on feature flags.
|
|
30
42
|
|
|
31
|
-
|
|
43
|
+
Returns:
|
|
44
|
+
Tuple of (confluence_postmortem, jira_postmortem)
|
|
45
|
+
Either or both can be None depending on feature flags
|
|
46
|
+
|
|
47
|
+
Raises:
|
|
48
|
+
ValueError: If both backends are disabled or post-mortem already exists
|
|
49
|
+
"""
|
|
50
|
+
confluence_pm = None
|
|
51
|
+
jira_pm = None
|
|
52
|
+
|
|
53
|
+
enable_confluence = getattr(settings, "ENABLE_CONFLUENCE", False)
|
|
54
|
+
enable_jira_postmortem = getattr(settings, "ENABLE_JIRA_POSTMORTEM", False)
|
|
55
|
+
|
|
56
|
+
# Check Confluence post-mortem
|
|
57
|
+
if enable_confluence:
|
|
58
|
+
if hasattr(incident, "postmortem_for"):
|
|
59
|
+
logger.warning(
|
|
60
|
+
f"Incident #{incident.id} already has a Confluence post-mortem"
|
|
61
|
+
)
|
|
62
|
+
else:
|
|
63
|
+
confluence_pm = PostMortemManager._create_confluence_postmortem(
|
|
64
|
+
incident
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
# Check Jira post-mortem
|
|
68
|
+
if enable_jira_postmortem:
|
|
69
|
+
if hasattr(incident, "jira_postmortem_for"):
|
|
70
|
+
logger.warning(
|
|
71
|
+
f"Incident #{incident.id} already has a Jira post-mortem"
|
|
72
|
+
)
|
|
73
|
+
else:
|
|
74
|
+
jira_pm = _get_jira_postmortem_service().create_postmortem_for_incident(
|
|
75
|
+
incident
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
# Validate at least one was created
|
|
79
|
+
if confluence_pm is None and jira_pm is None:
|
|
80
|
+
if not enable_confluence and not enable_jira_postmortem:
|
|
81
|
+
raise ValueError("Both Confluence and Jira post-mortems are disabled")
|
|
82
|
+
raise ValueError("Post-mortem already exists for this incident")
|
|
83
|
+
|
|
84
|
+
# Send signal if at least one post-mortem was created
|
|
85
|
+
if confluence_pm or jira_pm:
|
|
86
|
+
postmortem_created.send_robust(sender=__name__, incident=incident)
|
|
87
|
+
|
|
88
|
+
return confluence_pm, jira_pm
|
|
89
|
+
|
|
90
|
+
@staticmethod
|
|
91
|
+
def _create_confluence_postmortem(incident: Incident) -> PostMortem:
|
|
92
|
+
"""Create Confluence post-mortem (existing logic)."""
|
|
93
|
+
logger.info("Creating Confluence PostMortem for %s", incident)
|
|
32
94
|
|
|
33
95
|
topic_prefix = (
|
|
34
96
|
""
|
|
@@ -58,8 +120,6 @@ class PostMortemManager(models.Manager["PostMortem"]):
|
|
|
58
120
|
)
|
|
59
121
|
pm_page.save()
|
|
60
122
|
|
|
61
|
-
postmortem_created.send_robust(sender=__name__, incident=incident)
|
|
62
|
-
|
|
63
123
|
previous_postmortem = (
|
|
64
124
|
PostMortem.objects.exclude(id=pm_page.id)
|
|
65
125
|
.exclude(incident__isnull=True)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from typing import TYPE_CHECKING, Any, Never
|
|
5
|
+
|
|
6
|
+
from django.apps import apps
|
|
7
|
+
from django.dispatch.dispatcher import receiver
|
|
8
|
+
|
|
9
|
+
from firefighter.incidents.signals import incident_updated
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from firefighter.incidents.models.incident import Incident
|
|
13
|
+
from firefighter.incidents.models.incident_update import IncidentUpdate
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@receiver(signal=incident_updated)
|
|
19
|
+
def incident_updated_handler(
|
|
20
|
+
sender: Any,
|
|
21
|
+
incident: Incident,
|
|
22
|
+
incident_update: IncidentUpdate,
|
|
23
|
+
updated_fields: list[str],
|
|
24
|
+
**kwargs: Never,
|
|
25
|
+
) -> None:
|
|
26
|
+
"""Handle Confluence-specific incident updates.
|
|
27
|
+
|
|
28
|
+
Note: Post-mortem creation logic has been moved to jira_app.signals.postmortem_created
|
|
29
|
+
to handle both Confluence and Jira post-mortems independently of Confluence being enabled.
|
|
30
|
+
"""
|
|
31
|
+
if not apps.is_installed("firefighter.slack"):
|
|
32
|
+
logger.error("Slack app is not installed. Skipping.")
|
|
33
|
+
return
|
|
34
|
+
|
|
35
|
+
# This handler is now empty but kept for future Confluence-specific logic
|
|
36
|
+
# Post-mortem creation is handled by jira_app.signals.postmortem_created
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from firefighter.firefighter.settings.components.common import INSTALLED_APPS
|
|
4
|
+
from firefighter.firefighter.settings.settings_utils import config
|
|
5
|
+
|
|
6
|
+
ENABLE_JIRA: bool = config("ENABLE_JIRA", cast=bool, default=False)
|
|
7
|
+
"Enable the Jira app."
|
|
8
|
+
|
|
9
|
+
if ENABLE_JIRA:
|
|
10
|
+
INSTALLED_APPS += ("firefighter.jira_app",)
|
|
11
|
+
|
|
12
|
+
RAID_JIRA_API_USER: str = config("RAID_JIRA_API_USER")
|
|
13
|
+
"""The Jira API user to use."""
|
|
14
|
+
RAID_JIRA_API_PASSWORD: str = config("RAID_JIRA_API_PASSWORD")
|
|
15
|
+
"""The Jira API password to use."""
|
|
16
|
+
RAID_JIRA_API_URL: str = config("RAID_JIRA_API_URL")
|
|
17
|
+
"""The Jira API URL to use. If no protocol is defined, https will be used."""
|
|
18
|
+
|
|
19
|
+
if not RAID_JIRA_API_URL.startswith("http"):
|
|
20
|
+
RAID_JIRA_API_URL = f"https://{RAID_JIRA_API_URL}"
|
|
21
|
+
RAID_JIRA_API_URL = RAID_JIRA_API_URL.rstrip("/")
|
|
22
|
+
|
|
23
|
+
# Jira Post-mortem Configuration
|
|
24
|
+
ENABLE_JIRA_POSTMORTEM: bool = config(
|
|
25
|
+
"ENABLE_JIRA_POSTMORTEM", cast=bool, default=False
|
|
26
|
+
)
|
|
27
|
+
"Enable Jira post-mortem creation (in addition to or instead of Confluence)."
|
|
28
|
+
|
|
29
|
+
if ENABLE_JIRA_POSTMORTEM:
|
|
30
|
+
JIRA_POSTMORTEM_PROJECT_KEY: str = config(
|
|
31
|
+
"JIRA_POSTMORTEM_PROJECT_KEY", default="INCIDENT"
|
|
32
|
+
)
|
|
33
|
+
"Jira project key for post-mortems."
|
|
34
|
+
|
|
35
|
+
JIRA_POSTMORTEM_ISSUE_TYPE: str = config(
|
|
36
|
+
"JIRA_POSTMORTEM_ISSUE_TYPE", default="Post-mortem"
|
|
37
|
+
)
|
|
38
|
+
"Jira issue type for post-mortems."
|
|
39
|
+
|
|
40
|
+
# Jira Custom Field IDs
|
|
41
|
+
JIRA_POSTMORTEM_FIELDS: dict[str, str] = {
|
|
42
|
+
"incident_summary": config(
|
|
43
|
+
"JIRA_FIELD_INCIDENT_SUMMARY", default="customfield_12699"
|
|
44
|
+
),
|
|
45
|
+
"timeline": config("JIRA_FIELD_TIMELINE", default="customfield_12700"),
|
|
46
|
+
"root_causes": config("JIRA_FIELD_ROOT_CAUSES", default="customfield_12701"),
|
|
47
|
+
"impact": config("JIRA_FIELD_IMPACT", default="customfield_12702"),
|
|
48
|
+
"mitigation_actions": config(
|
|
49
|
+
"JIRA_FIELD_MITIGATION_ACTIONS", default="customfield_12703"
|
|
50
|
+
),
|
|
51
|
+
"incident_category": config(
|
|
52
|
+
"JIRA_FIELD_INCIDENT_CATEGORY", default="customfield_12369"
|
|
53
|
+
),
|
|
54
|
+
}
|
|
@@ -6,6 +6,7 @@ from functools import cached_property
|
|
|
6
6
|
from typing import TYPE_CHECKING, Any
|
|
7
7
|
|
|
8
8
|
from django import apps
|
|
9
|
+
from django.conf import settings
|
|
9
10
|
from django.contrib import admin
|
|
10
11
|
from django.contrib.admin import AdminSite, helpers
|
|
11
12
|
from django.contrib.admin.decorators import action
|
|
@@ -514,6 +515,8 @@ class IncidentAdmin(admin.ModelAdmin[Incident]):
|
|
|
514
515
|
]
|
|
515
516
|
if apps.apps.is_installed("firefighter.confluence"):
|
|
516
517
|
select_related.append("postmortem_for")
|
|
518
|
+
if getattr(settings, "ENABLE_JIRA_POSTMORTEM", False):
|
|
519
|
+
select_related.append("jira_postmortem_for")
|
|
517
520
|
return select_related
|
|
518
521
|
|
|
519
522
|
|
{firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/models/impact.py
RENAMED
|
@@ -12,8 +12,6 @@ from django.utils.translation import gettext_lazy as _
|
|
|
12
12
|
from django_stubs_ext.db.models import TypedModelMeta
|
|
13
13
|
|
|
14
14
|
if TYPE_CHECKING:
|
|
15
|
-
from django.db.models.fields.related import ManyToManyField
|
|
16
|
-
|
|
17
15
|
from firefighter.incidents.models.incident import Incident # noqa: F401
|
|
18
16
|
|
|
19
17
|
|
|
@@ -50,7 +48,7 @@ class LevelChoices(models.TextChoices):
|
|
|
50
48
|
self.LOWEST: 5,
|
|
51
49
|
self.NONE: 6,
|
|
52
50
|
}
|
|
53
|
-
return priority_mapping.get(self, 6) # type: ignore
|
|
51
|
+
return priority_mapping.get(self, 6) # type: ignore[call-overload]
|
|
54
52
|
|
|
55
53
|
@property
|
|
56
54
|
def emoji(self) -> str:
|
|
@@ -64,7 +62,7 @@ class LevelChoices(models.TextChoices):
|
|
|
64
62
|
self.LOWEST: "⏬",
|
|
65
63
|
self.NONE: none_emoji,
|
|
66
64
|
}
|
|
67
|
-
return emoji_mapping.get(self, none_emoji) # type: ignore
|
|
65
|
+
return emoji_mapping.get(self, none_emoji) # type: ignore[call-overload]
|
|
68
66
|
|
|
69
67
|
|
|
70
68
|
class ImpactLevel(models.Model):
|
|
@@ -156,4 +154,4 @@ class IncidentImpact(models.Model):
|
|
|
156
154
|
|
|
157
155
|
class HasImpactProtocol(Protocol):
|
|
158
156
|
id: Any
|
|
159
|
-
impacts:
|
|
157
|
+
impacts: Any
|
{firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/models/incident.py
RENAMED
|
@@ -69,6 +69,8 @@ if TYPE_CHECKING:
|
|
|
69
69
|
|
|
70
70
|
if settings.ENABLE_CONFLUENCE:
|
|
71
71
|
from firefighter.confluence.models import PostMortem
|
|
72
|
+
if getattr(settings, "ENABLE_JIRA_POSTMORTEM", False):
|
|
73
|
+
from firefighter.jira_app.models import JiraPostMortem
|
|
72
74
|
|
|
73
75
|
|
|
74
76
|
NON_ALPHANUMERIC_CHARACTERS = re.compile(r"[^\da-zA-Z]+")
|
|
@@ -338,15 +340,25 @@ class Incident(models.Model):
|
|
|
338
340
|
|
|
339
341
|
@property
|
|
340
342
|
def needs_postmortem(self) -> bool:
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
343
|
+
"""Check if incident requires a post-mortem based on priority and environment.
|
|
344
|
+
|
|
345
|
+
Post-mortem is required if:
|
|
346
|
+
- Priority requires it (P1/P2)
|
|
347
|
+
- Environment is PRD
|
|
348
|
+
- At least one post-mortem system is enabled (Confluence OR Jira)
|
|
349
|
+
"""
|
|
350
|
+
# Check if at least one post-mortem system is enabled
|
|
351
|
+
has_confluence = apps.is_installed("firefighter.confluence")
|
|
352
|
+
has_jira_postmortem = getattr(settings, "ENABLE_JIRA_POSTMORTEM", False)
|
|
353
|
+
|
|
354
|
+
if not (has_confluence or has_jira_postmortem):
|
|
355
|
+
return False
|
|
356
|
+
|
|
357
|
+
return bool(
|
|
358
|
+
self.priority
|
|
359
|
+
and self.environment
|
|
360
|
+
and self.priority.needs_postmortem
|
|
361
|
+
and self.environment.value == "PRD"
|
|
350
362
|
)
|
|
351
363
|
|
|
352
364
|
@property
|
|
@@ -649,6 +661,9 @@ class Incident(models.Model):
|
|
|
649
661
|
if settings.ENABLE_CONFLUENCE:
|
|
650
662
|
postmortem_for: PostMortem
|
|
651
663
|
postmortem_for_id: UUID
|
|
664
|
+
if getattr(settings, "ENABLE_JIRA_POSTMORTEM", False):
|
|
665
|
+
jira_postmortem_for: JiraPostMortem
|
|
666
|
+
jira_postmortem_for_id: UUID
|
|
652
667
|
priority_id: UUID
|
|
653
668
|
environment_id: UUID
|
|
654
669
|
component_id: UUID
|
{firefighter_incident-0.0.22 → firefighter_incident-0.0.23}/firefighter/incidents/views/views.py
RENAMED
|
@@ -150,6 +150,8 @@ class IncidentDetailView(CustomDetailView[Incident]):
|
|
|
150
150
|
]
|
|
151
151
|
if settings.ENABLE_CONFLUENCE:
|
|
152
152
|
select_related.append("postmortem_for")
|
|
153
|
+
if getattr(settings, "ENABLE_JIRA_POSTMORTEM", False):
|
|
154
|
+
select_related.append("jira_postmortem_for")
|
|
153
155
|
queryset = Incident.objects.select_related(*select_related).prefetch_related(
|
|
154
156
|
Prefetch(
|
|
155
157
|
"incidentupdate_set",
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from django.contrib import admin
|
|
4
|
+
|
|
5
|
+
from firefighter.jira_app.models import JiraIssue, JiraPostMortem, JiraUser
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@admin.register(JiraUser)
|
|
9
|
+
class JiraUserAdmin(admin.ModelAdmin[JiraUser]):
|
|
10
|
+
model = JiraUser
|
|
11
|
+
list_display = ["id", "user"]
|
|
12
|
+
list_display_links = ["id", "user"]
|
|
13
|
+
search_fields = ["id", "user__username"]
|
|
14
|
+
list_select_related = ["user"]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@admin.register(JiraIssue)
|
|
18
|
+
class JiraIssueAdmin(admin.ModelAdmin[JiraIssue]):
|
|
19
|
+
model = JiraIssue
|
|
20
|
+
list_display = ["id", "key", "summary"]
|
|
21
|
+
list_display_links = ["id", "key", "summary"]
|
|
22
|
+
search_fields = ["id", "key", "summary", "description"]
|
|
23
|
+
|
|
24
|
+
autocomplete_fields = ["watchers", "assignee", "reporter"]
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@admin.register(JiraPostMortem)
|
|
28
|
+
class JiraPostMortemAdmin(admin.ModelAdmin[JiraPostMortem]):
|
|
29
|
+
model = JiraPostMortem
|
|
30
|
+
list_display = ["jira_issue_key", "incident", "created_at", "created_by"]
|
|
31
|
+
list_display_links = ["jira_issue_key", "incident"]
|
|
32
|
+
search_fields = ["jira_issue_key", "jira_issue_id", "incident__id"]
|
|
33
|
+
list_select_related = ["incident", "created_by"]
|
|
34
|
+
autocomplete_fields = ["incident", "created_by"]
|
|
35
|
+
readonly_fields = ["created_at", "updated_at", "issue_url"]
|
|
36
|
+
|
|
37
|
+
def issue_url(self, obj: JiraPostMortem) -> str:
|
|
38
|
+
return obj.issue_url
|
|
@@ -10,6 +10,9 @@ class JiraAppConfig(AppConfig):
|
|
|
10
10
|
verbose_name = "Jira"
|
|
11
11
|
|
|
12
12
|
def ready(self) -> None:
|
|
13
|
+
# Register signals
|
|
14
|
+
# E.g. usage: create PostMortem (Jira and/or Confluence) on incident_updated
|
|
15
|
+
import firefighter.jira_app.signals
|
|
13
16
|
import firefighter.jira_app.tasks
|
|
14
17
|
|
|
15
18
|
return super().ready()
|
|
@@ -268,9 +268,7 @@ class JiraClient:
|
|
|
268
268
|
raise
|
|
269
269
|
else:
|
|
270
270
|
if len(watchers) == 0:
|
|
271
|
-
logger.debug(
|
|
272
|
-
"No watchers found for jira_issue_id '%s'.", jira_issue_id
|
|
273
|
-
)
|
|
271
|
+
logger.debug("No watchers found for jira_issue_id '%s'.", jira_issue_id)
|
|
274
272
|
return watchers
|
|
275
273
|
|
|
276
274
|
@staticmethod
|
|
@@ -461,5 +459,155 @@ class JiraClient:
|
|
|
461
459
|
|
|
462
460
|
return statuses_info_list
|
|
463
461
|
|
|
462
|
+
def create_postmortem_issue(
|
|
463
|
+
self,
|
|
464
|
+
project_key: str,
|
|
465
|
+
issue_type: str,
|
|
466
|
+
fields: dict[str, Any],
|
|
467
|
+
parent_issue_key: str | None = None,
|
|
468
|
+
) -> dict[str, Any]:
|
|
469
|
+
"""Create a Jira post-mortem issue with custom fields.
|
|
470
|
+
|
|
471
|
+
Args:
|
|
472
|
+
project_key: Jira project key (e.g., "INCIDENT")
|
|
473
|
+
issue_type: Issue type name (e.g., "Post-mortem")
|
|
474
|
+
fields: Dictionary of field IDs to values
|
|
475
|
+
parent_issue_key: Optional parent issue key to link this post-mortem to
|
|
476
|
+
|
|
477
|
+
Returns:
|
|
478
|
+
Dictionary with 'key' and 'id' of created issue
|
|
479
|
+
|
|
480
|
+
Raises:
|
|
481
|
+
JiraAPIError: If issue creation fails
|
|
482
|
+
"""
|
|
483
|
+
try:
|
|
484
|
+
issue_dict: dict[str, Any] = {
|
|
485
|
+
"project": {"key": project_key},
|
|
486
|
+
"issuetype": {"name": issue_type},
|
|
487
|
+
**fields,
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
# Create the issue first without parent link
|
|
491
|
+
issue = self.jira.create_issue(fields=issue_dict)
|
|
492
|
+
logger.info(
|
|
493
|
+
"Created post-mortem issue %s in project %s", issue.key, project_key
|
|
494
|
+
)
|
|
495
|
+
|
|
496
|
+
# Create issue link to parent if provided
|
|
497
|
+
# Using link instead of parent to avoid hierarchy restrictions
|
|
498
|
+
if parent_issue_key:
|
|
499
|
+
self._create_issue_link_safe(
|
|
500
|
+
parent_issue_key=parent_issue_key,
|
|
501
|
+
postmortem_issue_key=issue.key,
|
|
502
|
+
)
|
|
503
|
+
|
|
504
|
+
except exceptions.JIRAError as e:
|
|
505
|
+
logger.exception("Failed to create Jira issue in project %s", project_key)
|
|
506
|
+
error_msg = f"Failed to create Jira issue: {e.status_code} {e.text}"
|
|
507
|
+
raise JiraAPIError(error_msg) from e
|
|
508
|
+
else:
|
|
509
|
+
return {
|
|
510
|
+
"key": issue.key,
|
|
511
|
+
"id": issue.id,
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
def _create_issue_link_safe(
|
|
515
|
+
self, parent_issue_key: str, postmortem_issue_key: str
|
|
516
|
+
) -> None:
|
|
517
|
+
"""Create an issue link between parent and post-mortem, with robust error handling.
|
|
518
|
+
|
|
519
|
+
This method tries multiple link types in order of preference:
|
|
520
|
+
1. "Relates" - Standard link type
|
|
521
|
+
2. "Blocks" - Alternative link type
|
|
522
|
+
3. "Relates to" - Another common variant
|
|
523
|
+
|
|
524
|
+
Args:
|
|
525
|
+
parent_issue_key: Parent incident issue key
|
|
526
|
+
postmortem_issue_key: Post-mortem issue key
|
|
527
|
+
|
|
528
|
+
Note:
|
|
529
|
+
This method will not raise exceptions - it logs warnings instead.
|
|
530
|
+
The post-mortem creation should succeed even if linking fails.
|
|
531
|
+
"""
|
|
532
|
+
# List of link types to try, in order of preference
|
|
533
|
+
link_types = ["Relates", "Blocks", "Relates to"]
|
|
534
|
+
|
|
535
|
+
for link_type in link_types:
|
|
536
|
+
try:
|
|
537
|
+
# Validate that both issues exist before attempting link
|
|
538
|
+
try:
|
|
539
|
+
self.jira.issue(parent_issue_key)
|
|
540
|
+
self.jira.issue(postmortem_issue_key)
|
|
541
|
+
except exceptions.JIRAError as validation_error:
|
|
542
|
+
logger.warning(
|
|
543
|
+
"Issue validation failed before creating link: %s",
|
|
544
|
+
validation_error,
|
|
545
|
+
)
|
|
546
|
+
return
|
|
547
|
+
|
|
548
|
+
# Create the link
|
|
549
|
+
self.jira.create_issue_link(
|
|
550
|
+
type=link_type,
|
|
551
|
+
inwardIssue=parent_issue_key,
|
|
552
|
+
outwardIssue=postmortem_issue_key,
|
|
553
|
+
comment={
|
|
554
|
+
"body": f"Post-mortem {postmortem_issue_key} created for incident {parent_issue_key}"
|
|
555
|
+
},
|
|
556
|
+
)
|
|
557
|
+
|
|
558
|
+
except exceptions.JIRAError as link_error:
|
|
559
|
+
logger.warning(
|
|
560
|
+
"Failed to create issue link (%s) from %s to %s: %s",
|
|
561
|
+
link_type,
|
|
562
|
+
parent_issue_key,
|
|
563
|
+
postmortem_issue_key,
|
|
564
|
+
link_error,
|
|
565
|
+
)
|
|
566
|
+
# Continue to try next link type
|
|
567
|
+
else:
|
|
568
|
+
logger.info(
|
|
569
|
+
"Created issue link (%s) from %s to %s",
|
|
570
|
+
link_type,
|
|
571
|
+
parent_issue_key,
|
|
572
|
+
postmortem_issue_key,
|
|
573
|
+
)
|
|
574
|
+
return # Success - exit early
|
|
575
|
+
|
|
576
|
+
# All link types failed
|
|
577
|
+
logger.error(
|
|
578
|
+
"Failed to create any issue link from %s to %s after trying all link types: %s",
|
|
579
|
+
parent_issue_key,
|
|
580
|
+
postmortem_issue_key,
|
|
581
|
+
link_types,
|
|
582
|
+
)
|
|
583
|
+
|
|
584
|
+
def assign_issue(self, issue_key: str, account_id: str) -> bool:
|
|
585
|
+
"""Assign a Jira issue to a user.
|
|
586
|
+
|
|
587
|
+
Args:
|
|
588
|
+
issue_key: Jira issue key (e.g., "INCIDENT-123")
|
|
589
|
+
account_id: Jira account ID of the user
|
|
590
|
+
|
|
591
|
+
Returns:
|
|
592
|
+
True if assignment succeeded, False otherwise
|
|
593
|
+
|
|
594
|
+
Note:
|
|
595
|
+
This method does not raise exceptions. Assignment failures are logged
|
|
596
|
+
as warnings since assignment is typically an optional operation.
|
|
597
|
+
"""
|
|
598
|
+
try:
|
|
599
|
+
self.jira.assign_issue(issue_key, account_id)
|
|
600
|
+
except exceptions.JIRAError as e:
|
|
601
|
+
logger.warning(
|
|
602
|
+
"Failed to assign issue %s to user %s: %s",
|
|
603
|
+
issue_key,
|
|
604
|
+
account_id,
|
|
605
|
+
e.text if hasattr(e, "text") else str(e),
|
|
606
|
+
)
|
|
607
|
+
return False
|
|
608
|
+
else:
|
|
609
|
+
logger.info("Assigned issue %s to user %s", issue_key, account_id)
|
|
610
|
+
return True
|
|
611
|
+
|
|
464
612
|
|
|
465
613
|
client = JiraClient()
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Management commands for jira_app."""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Management commands for jira_app."""
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Generated by Django 4.2.21 on 2025-11-06 15:15
|
|
2
|
+
|
|
3
|
+
import django.db.models.deletion
|
|
4
|
+
from django.conf import settings
|
|
5
|
+
from django.db import migrations, models
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Migration(migrations.Migration):
|
|
9
|
+
|
|
10
|
+
dependencies = [
|
|
11
|
+
("incidents", "0029_add_custom_fields_to_incident"),
|
|
12
|
+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
|
13
|
+
("jira_app", "0001_initial_oss"),
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
operations = [
|
|
17
|
+
migrations.CreateModel(
|
|
18
|
+
name="JiraPostMortem",
|
|
19
|
+
fields=[
|
|
20
|
+
(
|
|
21
|
+
"id",
|
|
22
|
+
models.BigAutoField(
|
|
23
|
+
auto_created=True,
|
|
24
|
+
primary_key=True,
|
|
25
|
+
serialize=False,
|
|
26
|
+
verbose_name="ID",
|
|
27
|
+
),
|
|
28
|
+
),
|
|
29
|
+
(
|
|
30
|
+
"jira_issue_key",
|
|
31
|
+
models.CharField(
|
|
32
|
+
help_text="Jira issue key (e.g., INCIDENT-123)",
|
|
33
|
+
max_length=32,
|
|
34
|
+
unique=True,
|
|
35
|
+
),
|
|
36
|
+
),
|
|
37
|
+
(
|
|
38
|
+
"jira_issue_id",
|
|
39
|
+
models.CharField(
|
|
40
|
+
help_text="Jira issue ID", max_length=32, unique=True
|
|
41
|
+
),
|
|
42
|
+
),
|
|
43
|
+
("created_at", models.DateTimeField(auto_now_add=True)),
|
|
44
|
+
("updated_at", models.DateTimeField(auto_now=True)),
|
|
45
|
+
(
|
|
46
|
+
"created_by",
|
|
47
|
+
models.ForeignKey(
|
|
48
|
+
blank=True,
|
|
49
|
+
null=True,
|
|
50
|
+
on_delete=django.db.models.deletion.SET_NULL,
|
|
51
|
+
related_name="jira_postmortems_created",
|
|
52
|
+
to=settings.AUTH_USER_MODEL,
|
|
53
|
+
),
|
|
54
|
+
),
|
|
55
|
+
(
|
|
56
|
+
"incident",
|
|
57
|
+
models.OneToOneField(
|
|
58
|
+
help_text="Incident this post-mortem is for",
|
|
59
|
+
on_delete=django.db.models.deletion.CASCADE,
|
|
60
|
+
related_name="jira_postmortem_for",
|
|
61
|
+
to="incidents.incident",
|
|
62
|
+
),
|
|
63
|
+
),
|
|
64
|
+
],
|
|
65
|
+
options={
|
|
66
|
+
"verbose_name": "Jira Post-mortem",
|
|
67
|
+
"verbose_name_plural": "Jira Post-mortems",
|
|
68
|
+
"db_table": "jira_postmortem",
|
|
69
|
+
},
|
|
70
|
+
),
|
|
71
|
+
]
|