firefighter-incident 0.0.21__py3-none-any.whl → 0.0.23__py3-none-any.whl
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/_version.py +2 -2
- firefighter/api/serializers.py +18 -0
- firefighter/api/views/incidents.py +3 -0
- firefighter/components/avatar/avatar.html +2 -2
- firefighter/components/avatar/avatar.py +2 -2
- firefighter/confluence/models.py +66 -6
- firefighter/confluence/signals/incident_updated.py +8 -26
- firefighter/firefighter/settings/components/jira_app.py +33 -0
- firefighter/incidents/admin.py +3 -0
- firefighter/incidents/models/impact.py +3 -5
- firefighter/incidents/models/incident.py +24 -9
- firefighter/incidents/views/views.py +2 -0
- firefighter/jira_app/admin.py +15 -1
- firefighter/jira_app/apps.py +3 -0
- firefighter/jira_app/client.py +151 -3
- firefighter/jira_app/management/__init__.py +1 -0
- firefighter/jira_app/management/commands/__init__.py +1 -0
- firefighter/jira_app/migrations/0002_add_jira_postmortem_model.py +71 -0
- firefighter/jira_app/models.py +50 -0
- firefighter/jira_app/service_postmortem.py +292 -0
- firefighter/jira_app/signals/__init__.py +10 -0
- firefighter/jira_app/signals/incident_key_events_updated.py +88 -0
- firefighter/jira_app/signals/postmortem_created.py +155 -0
- firefighter/jira_app/templates/jira/postmortem/impact.txt +12 -0
- firefighter/jira_app/templates/jira/postmortem/incident_summary.txt +17 -0
- firefighter/jira_app/templates/jira/postmortem/mitigation_actions.txt +9 -0
- firefighter/jira_app/templates/jira/postmortem/root_causes.txt +12 -0
- firefighter/jira_app/templates/jira/postmortem/timeline.txt +7 -0
- firefighter/raid/signals/incident_updated.py +31 -11
- firefighter/slack/messages/slack_messages.py +39 -3
- firefighter/slack/signals/postmortem_created.py +51 -3
- firefighter/slack/views/modals/closure_reason.py +15 -0
- firefighter/slack/views/modals/key_event_message.py +9 -0
- firefighter/slack/views/modals/postmortem.py +32 -40
- firefighter/slack/views/modals/update_status.py +7 -1
- {firefighter_incident-0.0.21.dist-info → firefighter_incident-0.0.23.dist-info}/METADATA +2 -1
- {firefighter_incident-0.0.21.dist-info → firefighter_incident-0.0.23.dist-info}/RECORD +52 -33
- {firefighter_incident-0.0.21.dist-info → firefighter_incident-0.0.23.dist-info}/WHEEL +1 -1
- firefighter_tests/test_api/test_renderer.py +41 -0
- firefighter_tests/test_incidents/test_models/test_incident_model.py +29 -0
- firefighter_tests/test_jira_app/test_incident_key_events_sync.py +112 -0
- firefighter_tests/test_jira_app/test_models.py +138 -0
- firefighter_tests/test_jira_app/test_postmortem_issue_link.py +201 -0
- firefighter_tests/test_jira_app/test_postmortem_service.py +416 -0
- firefighter_tests/test_jira_app/test_timeline_template.py +135 -0
- firefighter_tests/test_raid/test_raid_signals.py +50 -8
- firefighter_tests/test_slack/messages/test_slack_messages.py +112 -23
- firefighter_tests/test_slack/views/modals/test_closure_reason_modal.py +18 -2
- firefighter_tests/test_slack/views/modals/test_key_event_message.py +30 -0
- firefighter_tests/test_slack/views/modals/test_update_status.py +161 -133
- {firefighter_incident-0.0.21.dist-info → firefighter_incident-0.0.23.dist-info}/entry_points.txt +0 -0
- {firefighter_incident-0.0.21.dist-info → firefighter_incident-0.0.23.dist-info}/licenses/LICENSE +0 -0
|
@@ -6,7 +6,7 @@ gunicorn.conf.py,sha256=vHsTGjaKOr8FDMp6fTKYTX4AtokmPgYvvt5Mr0Q6APc,273
|
|
|
6
6
|
main.py,sha256=CsbprHoOYhjCLpTJmq9Z_aRYFoFgWxoz2pDLuwm8Eqg,1558
|
|
7
7
|
manage.py,sha256=5ivHGD13C6nJ8QvltKsJ9T9akA5he8da70HLWaEP3k8,689
|
|
8
8
|
firefighter/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
-
firefighter/_version.py,sha256=
|
|
9
|
+
firefighter/_version.py,sha256=ibKwfdtUKJ8ftEJ-ANHeQVfItYjoZhYBzigrJx5AdJU,706
|
|
10
10
|
firefighter/api/__init__.py,sha256=JQW0Bv6xwGqy7ioxx3h6UGMzkkJ4DntDpbvV1Ncgi8k,136
|
|
11
11
|
firefighter/api/admin.py,sha256=x9Ysy-GiYjb0rynmFdS9g56e6n24fkN0ouGy5QD9Yrc,4629
|
|
12
12
|
firefighter/api/apps.py,sha256=P5uU1_gMrDfzurdMbfqw1Bnb2uNKKcMq17WBPg2sLhc,204
|
|
@@ -14,7 +14,7 @@ firefighter/api/authentication.py,sha256=1OEeTF0NU54ZLgq2Vy3GxrR-7skj6HmobVp4UGP
|
|
|
14
14
|
firefighter/api/models.py,sha256=HJh0PtlrUX8HVCdcdQlClwA6kIFVYnivnKmiQ30D0nQ,1533
|
|
15
15
|
firefighter/api/permissions.py,sha256=1uxMg5ylFkmvIIonJVlQKL0RJAcgAY79a0y5ROiNrTg,608
|
|
16
16
|
firefighter/api/renderer.py,sha256=RCQFnjZBIq9fF3dapu3kid2B1s0in8XOEBJmbh5cPlU,4057
|
|
17
|
-
firefighter/api/serializers.py,sha256=
|
|
17
|
+
firefighter/api/serializers.py,sha256=Dbixi7HIVnqzv9zuB6NU9syakdkz9mF8SS1XoNaA3O8,11266
|
|
18
18
|
firefighter/api/urls.py,sha256=kjL6TwO836laVMn8e4fF4GiULyCXQkZiTDqXiVxrGtY,2103
|
|
19
19
|
firefighter/api/migrations/0001_initial.py,sha256=8Q3Q_OUjAOsB_NzjYunAefC9WPk1FUwL3PA7N_gMylc,1496
|
|
20
20
|
firefighter/api/migrations/0002_alter_apitokenproxy_options.py,sha256=BRuXscZS1gmcbF9mFlUyYy_Mwf-5xnUHcuFL2VA89eY,933
|
|
@@ -27,12 +27,12 @@ firefighter/api/views/environments.py,sha256=B9j5qFnFHzXw20ZVzJIJJSKjlNXINNeXqJ8
|
|
|
27
27
|
firefighter/api/views/groups.py,sha256=mu75XdBNBCMXaVCbiFSLNd0YtpmneNa5u-tgXadAsCE,331
|
|
28
28
|
firefighter/api/views/incident_cost_types.py,sha256=cNYqk3ez5ud_BA45aS2ySLEIJotHdCu_fLc4YRiULk4,410
|
|
29
29
|
firefighter/api/views/incident_costs.py,sha256=aZYEGlT8nF09He4hV_90QJToKFRgi-cJdrsKHR_8HUM,409
|
|
30
|
-
firefighter/api/views/incidents.py,sha256=
|
|
30
|
+
firefighter/api/views/incidents.py,sha256=UvPUUXWOR8kOYQXWjmDH25nGQLcSRwtXePYiiY8XPHc,10387
|
|
31
31
|
firefighter/api/views/severities.py,sha256=mdkR4GjZibydC1Dx-Sglm-f35GZxWbjmqStAx_kRv7U,352
|
|
32
32
|
firefighter/components/__init__.py,sha256=Vd_Uk5Uq7Mqp6NOFp5QiniWZAyzmYLqNSFEEw1x7COk,167
|
|
33
33
|
firefighter/components/avatar/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
34
|
-
firefighter/components/avatar/avatar.html,sha256=
|
|
35
|
-
firefighter/components/avatar/avatar.py,sha256=
|
|
34
|
+
firefighter/components/avatar/avatar.html,sha256=_0SXz5JavwYeUwCKX9Lt3ZNm67caGjdUMKyFWyZqSJI,794
|
|
35
|
+
firefighter/components/avatar/avatar.py,sha256=MqWm0VJTVOoB4DhW1mcTes48rlmrGD6IZO0BC7hUp3o,837
|
|
36
36
|
firefighter/components/card/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
37
37
|
firefighter/components/card/card.html,sha256=ziahql8X7WiQdprMktzy7sx0gVXNIxqtAsh_Rc5Iy0g,725
|
|
38
38
|
firefighter/components/card/card.py,sha256=yB4veoRQ3zfdJPCsAGIYtmLCDz3G2kmcYFg12jzkNks,487
|
|
@@ -55,7 +55,7 @@ firefighter/confluence/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
|
|
|
55
55
|
firefighter/confluence/admin.py,sha256=aDXghuuLc7G_TLt-655M31smx-H6vkIgLtEmmNCA3lg,1490
|
|
56
56
|
firefighter/confluence/apps.py,sha256=vKswBwQL7L9e2JQwvRb7xy3myyE_GRldYX78jSY3XCM,406
|
|
57
57
|
firefighter/confluence/client.py,sha256=xjSsrsGPF75JANNvam2YgiUkztuXhOcs9pMmPbb7ymk,6361
|
|
58
|
-
firefighter/confluence/models.py,sha256
|
|
58
|
+
firefighter/confluence/models.py,sha256=ExFip6Tw199jI5LVLqC8t4pOPsvQxfEhtQeWCqTijFw,8769
|
|
59
59
|
firefighter/confluence/serializers.py,sha256=CzuHVXIJNS47NCAJLXSTDOevtg5sf309XXEcWKQ1sAQ,258
|
|
60
60
|
firefighter/confluence/service.py,sha256=MU_wHGxgLmfR7t4wLJbfldwivlBfyaeXFKjOfFJzEqk,12307
|
|
61
61
|
firefighter/confluence/tables.py,sha256=ANEtFXzXyPK6E5FIrBC5XoQt5R3ZUY1DME_RbD1h_NE,732
|
|
@@ -70,7 +70,7 @@ firefighter/confluence/management/commands/sync_runbooks.py,sha256=EgapI-TO9NXoH
|
|
|
70
70
|
firefighter/confluence/migrations/0001_initial_oss.py,sha256=FdR7hie-0vwx_tcuYUziBZMSiIuQ-yNO5LRhizJ7CQg,3860
|
|
71
71
|
firefighter/confluence/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
72
72
|
firefighter/confluence/signals/__init__.py,sha256=nmuEEoawaYFVOlK880DT5-VOkXVIKYVLzrJIEnrXku0,121
|
|
73
|
-
firefighter/confluence/signals/incident_updated.py,sha256=
|
|
73
|
+
firefighter/confluence/signals/incident_updated.py,sha256=DNx-nZvss98H-1_4GwrQPxainRNo2nyC6GuaCVdEj8k,1169
|
|
74
74
|
firefighter/confluence/tasks/__init__.py,sha256=-NrthX2GIVmqjgiGAFg0r72Djc54Jl05k6Zb_UHUlf4,427
|
|
75
75
|
firefighter/confluence/tasks/archive_postmortems.py,sha256=k2kgRaTC56SRzV9neGUZfvl8BpRZ_pKHoHr_sETykms,8098
|
|
76
76
|
firefighter/confluence/tasks/sort_runbooks.py,sha256=rac-AjP14sYYulHHBbhuBbh9PK16Y3zBZ-7ywIdF5lo,2958
|
|
@@ -115,7 +115,7 @@ firefighter/firefighter/settings/components/caches.py,sha256=C7WULBbKwU3tjtzg6vU
|
|
|
115
115
|
firefighter/firefighter/settings/components/celery.py,sha256=AjWlIqAdwaZOh9QK-31Qtw60QjETy4Q-VjadyNf7pCM,1974
|
|
116
116
|
firefighter/firefighter/settings/components/common.py,sha256=sKflgempBG3wWVP53IG-kx64Kb6qhS4zhMQBd0JvnF4,9827
|
|
117
117
|
firefighter/firefighter/settings/components/confluence.py,sha256=DPpP9FYyXZM1S3JGDL46UIlu518oSLzLi6mSfgsHKIM,1789
|
|
118
|
-
firefighter/firefighter/settings/components/jira_app.py,sha256=
|
|
118
|
+
firefighter/firefighter/settings/components/jira_app.py,sha256=2Ei9NCp4TSVOKqgn7FNFOoIgccx8ZBLjGShXLY5ddgI,2184
|
|
119
119
|
firefighter/firefighter/settings/components/logging.py,sha256=PzaDYr2BxspK2tXaTecUAKu7BlVZOLQYizQMAa959KA,3336
|
|
120
120
|
firefighter/firefighter/settings/components/pagerduty.py,sha256=_LT0_RPhN2E4qW2XQiyywky_iGAQK_eSaabXJyAYMRc,698
|
|
121
121
|
firefighter/firefighter/settings/components/raid.py,sha256=i16Gtgmbye-GpUqHYX0HwzC2CipQhLjGDeeOuquB7y8,1004
|
|
@@ -128,7 +128,7 @@ firefighter/firefighter/templates/admin/base.html,sha256=JZbBsYmdr77PMeMMGHss1lY
|
|
|
128
128
|
firefighter/firefighter/templates/admin/login.html,sha256=EY9AvQe8Y9GNQAAMr9g9Wl1hBfbYC-hLIDzY0rR5SAc,536
|
|
129
129
|
firefighter/firefighter/templates/admin/send_message_conversation.html,sha256=LavOB38P3GFcDzzzdsvUhwMr5jzE4H1wyFTGITucAmE,2058
|
|
130
130
|
firefighter/incidents/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
131
|
-
firefighter/incidents/admin.py,sha256
|
|
131
|
+
firefighter/incidents/admin.py,sha256=-uhKuutkMNFuDEq4bJEQqt1dUHjTFrljrs2cZcJnAxg,22171
|
|
132
132
|
firefighter/incidents/apps.py,sha256=GySoDZsz-BH-nsIZWTOd0H1hgL9s9il1BEuLC4gKTXs,378
|
|
133
133
|
firefighter/incidents/enums.py,sha256=FsoxsZCBB_19MmxnxKu-hb4CzOJQjJVPtv1AwKjUAaI,1840
|
|
134
134
|
firefighter/incidents/factories.py,sha256=EXrJ83H28QrD7J0SpzmO8rq2RgkQ8iRj8hmil4QD0Rs,3723
|
|
@@ -180,8 +180,8 @@ firefighter/incidents/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRk
|
|
|
180
180
|
firefighter/incidents/models/__init__.py,sha256=FLVyBwIdyxLdgSvXRAKC3fry9YwwqlqhitTIuG0vWrk,877
|
|
181
181
|
firefighter/incidents/models/environment.py,sha256=51txwua3dCrWZ1iSG3ZA8rbDn9c00pyMAZujl9gwE5c,827
|
|
182
182
|
firefighter/incidents/models/group.py,sha256=VrVL315VFUvKW69AZuRUBg1h0jZJvn8zWeMxMOWec1Y,700
|
|
183
|
-
firefighter/incidents/models/impact.py,sha256=
|
|
184
|
-
firefighter/incidents/models/incident.py,sha256=
|
|
183
|
+
firefighter/incidents/models/impact.py,sha256=bzTTW79FmclLcAKN0wmk739cXBiYIY_YHpkkASGn5Rw,4776
|
|
184
|
+
firefighter/incidents/models/incident.py,sha256=UdL9bc-3Ou-OS8P-nHO4YF6-Hk0mDkGNq1zjOq-TNFk,28022
|
|
185
185
|
firefighter/incidents/models/incident_category.py,sha256=g4OHv_XQhWcH6dvkqkyCgjlruo_1eih_CdtAPgPhaW4,7744
|
|
186
186
|
firefighter/incidents/models/incident_cost.py,sha256=juwOfJKRaNQpOHkRUCHShDDba0FU98YjRPkU4I0ofAU,1346
|
|
187
187
|
firefighter/incidents/models/incident_cost_type.py,sha256=wm8diry_VySJzIjC9M3Yavv2tYbvJgpN9UDb2gFRuH4,845
|
|
@@ -259,7 +259,7 @@ firefighter/incidents/views/date_filter.py,sha256=fUhTjkBulMokI5tAHuqNDVv1dyspjm
|
|
|
259
259
|
firefighter/incidents/views/date_utils.py,sha256=tiRTlh7PmRv4eAH0asiSX3Gn7ajsal9egm4S1d7s3_s,5759
|
|
260
260
|
firefighter/incidents/views/errors.py,sha256=yDuH0YOdGf-voVNEC51yR9Ie3OU-az7g2EqWs_uV1Kk,7855
|
|
261
261
|
firefighter/incidents/views/reports.py,sha256=1Iegx04w-oHw4cj7u9w2_s7T_e9FH5I6RRPTwDZwZhg,20973
|
|
262
|
-
firefighter/incidents/views/views.py,sha256
|
|
262
|
+
firefighter/incidents/views/views.py,sha256=TnmPeVYXNDU6MSUHqqnbTLYUBpzFsng_fy6qVcxEwVU,10655
|
|
263
263
|
firefighter/incidents/views/components/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
264
264
|
firefighter/incidents/views/components/details.py,sha256=gFEezmL1TcVYnM_ryLNNMaynuIdjYV31Qzx_GfzrQiA,1040
|
|
265
265
|
firefighter/incidents/views/components/list.py,sha256=u8HfXetmdL59h_4AZIhiHmKcmrPRZXgekPfnucB4Rek,2207
|
|
@@ -269,16 +269,28 @@ firefighter/incidents/views/docs/role_types.py,sha256=88dGBAL7NMC24lyqLDN0jGnh5-
|
|
|
269
269
|
firefighter/incidents/views/users/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
270
270
|
firefighter/incidents/views/users/details.py,sha256=xqDUEMorplAdSJNQ2vcNzntKKn6UsMDb_dXjVBN2GeY,1853
|
|
271
271
|
firefighter/jira_app/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
272
|
-
firefighter/jira_app/admin.py,sha256=
|
|
273
|
-
firefighter/jira_app/apps.py,sha256=
|
|
274
|
-
firefighter/jira_app/client.py,sha256=
|
|
275
|
-
firefighter/jira_app/models.py,sha256=
|
|
272
|
+
firefighter/jira_app/admin.py,sha256=ZHAAbhy0hm_DcklK59KMmid_ZiPn8n5V6g7cZCSNrpc,1299
|
|
273
|
+
firefighter/jira_app/apps.py,sha256=T6vHrQuMZHJoTth-xjy3CbNfPv6DyXgcR3PSMju2JS4,504
|
|
274
|
+
firefighter/jira_app/client.py,sha256=qpMqNTjJUq5OqAxmwvVOE20uJe7kp737HSdsiqUu1G4,21982
|
|
275
|
+
firefighter/jira_app/models.py,sha256=2zKy5VaKkhiHYA8Dukz8g0NTG82Qy5UHAHY9eMv67NE,3097
|
|
276
|
+
firefighter/jira_app/service_postmortem.py,sha256=b76f1uv-zUo4jUWXTul4nv8UnaqQXHzuoTYEDrEpcMA,10620
|
|
276
277
|
firefighter/jira_app/types.py,sha256=Ukak1U1EhcH2jQPN-UoEL6AMZ-kzPsQ8c7FUr7GmahE,956
|
|
277
278
|
firefighter/jira_app/utils.py,sha256=3xuzr8viZCBm6j2J9oFzA4bUvVW8TN1DOdlpbruJ_TE,3443
|
|
279
|
+
firefighter/jira_app/management/__init__.py,sha256=wy4qMZb7_K-INwwGGEhMtEeI0XTLqgUw4P8_-VEnrEw,40
|
|
280
|
+
firefighter/jira_app/management/commands/__init__.py,sha256=wy4qMZb7_K-INwwGGEhMtEeI0XTLqgUw4P8_-VEnrEw,40
|
|
278
281
|
firefighter/jira_app/migrations/0001_initial_oss.py,sha256=AR5UKfKi4vUGSmckeSxQ2qMnsjdhZZqr5Q-RoXw1WKM,2992
|
|
282
|
+
firefighter/jira_app/migrations/0002_add_jira_postmortem_model.py,sha256=oFSbYNcLIdHAoZ99SPRgL8n4ceoAd2YpBGxAoEtcBYQ,2442
|
|
279
283
|
firefighter/jira_app/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
284
|
+
firefighter/jira_app/signals/__init__.py,sha256=OpXFlbRgIrh73DGlUzQ6WUTedKsD5wYW9bxGMq_DnIs,325
|
|
285
|
+
firefighter/jira_app/signals/incident_key_events_updated.py,sha256=uaV3MON1QzeOZizzAwSdyktBwe2mWxHJeNSvy9MYc3k,3204
|
|
286
|
+
firefighter/jira_app/signals/postmortem_created.py,sha256=eOTQKcjspL-JHvXiCu-U1FzrqIr6OJ20GOK6gJ4dojw,5904
|
|
280
287
|
firefighter/jira_app/tasks/__init__.py,sha256=XLCPkolM6LwIUGv0MNbk_0lCuBHyzgRFHsE3vTRD5ds,86
|
|
281
288
|
firefighter/jira_app/tasks/sync_users_jira.py,sha256=sSSLsVCdzkPNRS6Gt8j0YwCTuoRqkJAJLxDBu7IElmM,1437
|
|
289
|
+
firefighter/jira_app/templates/jira/postmortem/impact.txt,sha256=eYlX0rytUiKZZIrWxMN23QXkLZ8JwlwPe5S2oiqZyFA,259
|
|
290
|
+
firefighter/jira_app/templates/jira/postmortem/incident_summary.txt,sha256=Bnias41O8TR2v0CAWpOoyRVVBAyx6vk2iICeQsLOuCs,392
|
|
291
|
+
firefighter/jira_app/templates/jira/postmortem/mitigation_actions.txt,sha256=7DWOcMhU0NiJugiUmEvSg1Z3ajW7IDZejprxt8urue0,242
|
|
292
|
+
firefighter/jira_app/templates/jira/postmortem/root_causes.txt,sha256=27DgQdrtHvHcju1llyYqU1jufegeHjJN_qvVkyECINM,291
|
|
293
|
+
firefighter/jira_app/templates/jira/postmortem/timeline.txt,sha256=NpUkBNknF4AUj2w20YqTjQ-o_EmGOYcoTZIhc8iWe3k,530
|
|
282
294
|
firefighter/logging/__init__.py,sha256=SSTapLdwQsMkBy8FDFOjLkzJlutfT152mmPEGErirK4,60
|
|
283
295
|
firefighter/logging/custom_json_formatter.py,sha256=dckOtllNTfeDLc1J4FWJ-_PVeT_CqfQIyTs9FKfZsqE,5601
|
|
284
296
|
firefighter/logging/pretty_formatter.py,sha256=6FxNVpQczcVhmLbLCz6HWxOQOvbqgH12-y8t1d7drfs,2411
|
|
@@ -326,7 +338,7 @@ firefighter/raid/migrations/0002_featureteam_remove_qualifierrotation_jira_user_
|
|
|
326
338
|
firefighter/raid/migrations/0003_delete_raidarea.py,sha256=M_XkKCu73ib2H09co2L-ssLQakJJFNOfqJpKrzOYP2Y,332
|
|
327
339
|
firefighter/raid/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
328
340
|
firefighter/raid/signals/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
329
|
-
firefighter/raid/signals/incident_updated.py,sha256=
|
|
341
|
+
firefighter/raid/signals/incident_updated.py,sha256=Al1S1BOWAd6s97ITG0Yg181hOOLR5Byx8OO9hM5kP9E,2231
|
|
330
342
|
firefighter/raid/tasks/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
|
|
331
343
|
firefighter/raid/views/__init__.py,sha256=C3WhAJfEoUasi2afHPuLpKiuRYixK-tc3j0-2Rw_g3E,5210
|
|
332
344
|
firefighter/slack/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -347,7 +359,7 @@ firefighter/slack/management/commands/generate_manifest.py,sha256=zFWHAC7ioozcDd
|
|
|
347
359
|
firefighter/slack/management/commands/switch_test_users.py,sha256=2KTSvCBxsEvZa61J8p0r3huPNhwuytcj2J7IawwZWpQ,11064
|
|
348
360
|
firefighter/slack/messages/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
349
361
|
firefighter/slack/messages/base.py,sha256=biH-YEAaldJ-OLHEs5ZjW-gtUYUbjOqxrAEflqV2XS0,4593
|
|
350
|
-
firefighter/slack/messages/slack_messages.py,sha256=
|
|
362
|
+
firefighter/slack/messages/slack_messages.py,sha256=xvkV_sEbBRkyqGigR_oQeC6Cr9KLWqqwxDXmPywyEok,35553
|
|
351
363
|
firefighter/slack/migrations/0001_initial_oss.py,sha256=XmTPgq7zCME2xDwzRFoVi4OegSIG9eSKoyTNoW05Qtg,12933
|
|
352
364
|
firefighter/slack/migrations/0002_usergroup_tag.py,sha256=098tmGA81mT-R2uhb6uQfZ7gKiRG9bFhEwQ8rrp4SKM,583
|
|
353
365
|
firefighter/slack/migrations/0003_alter_usergroup_tag.py,sha256=ncH3KUWEPZHlbdcAtOJ0KGt5H6EX-cKspTGU3osrAhE,591
|
|
@@ -370,7 +382,7 @@ firefighter/slack/signals/get_users.py,sha256=-ZUI3ORJZJ4tLiGhVwIU-pWHoriALtOC7K
|
|
|
370
382
|
firefighter/slack/signals/handle_incident_channel_done.py,sha256=pYoS_ZJf2u9seHCqahfPHz4BrfvF1vIZjE1_yy0P5mY,1726
|
|
371
383
|
firefighter/slack/signals/incident_closed.py,sha256=6QyUmTjEGVg0Wn5W-i2F8DlJuhvHjg3MxkcvAXFn9Bk,687
|
|
372
384
|
firefighter/slack/signals/incident_updated.py,sha256=MBouWXbLByEynGoytdFeRyioDxi5VFO8dlgI0kygX1E,10137
|
|
373
|
-
firefighter/slack/signals/postmortem_created.py,sha256=
|
|
385
|
+
firefighter/slack/signals/postmortem_created.py,sha256=cB3t4eZ96m0-2ybrJnrNHDzOXcsRyCKKwijx4g0ZJCA,2991
|
|
374
386
|
firefighter/slack/signals/roles_reminders.py,sha256=1Ef_J1PubY8WTVs2WDXz4KWa6X2Lvp1RFObIjSGpiOM,4041
|
|
375
387
|
firefighter/slack/tasks/__init__.py,sha256=28QxZkakyi9l7Ae83fQuzOS-9EaBiwuh_peUZwIxCx4,179
|
|
376
388
|
firefighter/slack/tasks/fetch_conversations_members.py,sha256=lLQ491_l8HEJrjoDpD0AETqoFUFogkyMJ002hguA-Dg,5381
|
|
@@ -399,19 +411,19 @@ firefighter/slack/views/events/message_deleted.py,sha256=tyA1-sAlG9ImcKIhqSn6Egu
|
|
|
399
411
|
firefighter/slack/views/events/reaction_added.py,sha256=AipwBnrU5B35D97YIZCXdSW8W7-9QTIIQqUcrLTLQ5c,4241
|
|
400
412
|
firefighter/slack/views/modals/__init__.py,sha256=U9PapAIlpuYqBonOUmBGWT8_HjQa35ilMQJXGaFLgd0,1945
|
|
401
413
|
firefighter/slack/views/modals/close.py,sha256=4j5iA-lmIFuCz7B9pgDmjxrqmfWFysqWEn1YIsE75zc,12161
|
|
402
|
-
firefighter/slack/views/modals/closure_reason.py,sha256=
|
|
414
|
+
firefighter/slack/views/modals/closure_reason.py,sha256=3ot1cb4Wzvwe-TAuR16ZopnWGInUmoeDUaKzOQ838kw,7600
|
|
403
415
|
firefighter/slack/views/modals/downgrade_workflow.py,sha256=cRWsm3DmKRRI1-Jpjprb5xeY2U7HvRo6eZlUbGuzr1A,3192
|
|
404
416
|
firefighter/slack/views/modals/edit.py,sha256=1N0OBSxsDuN6lJoH-djbEljy7f0LcDEpJF-U5YoEFXA,5895
|
|
405
|
-
firefighter/slack/views/modals/key_event_message.py,sha256=
|
|
417
|
+
firefighter/slack/views/modals/key_event_message.py,sha256=C6yhQLQ6jBuhIr-YAoAyt-qZKu0V6nJMGZ_t3DLtUbo,5943
|
|
406
418
|
firefighter/slack/views/modals/open.py,sha256=YIxpo8_C4cWCy_pQ3YRWl7NMyLmjqNjggTQINTBW6mo,29189
|
|
407
|
-
firefighter/slack/views/modals/postmortem.py,sha256=
|
|
419
|
+
firefighter/slack/views/modals/postmortem.py,sha256=7h_at4oMVFxN3IISbk1yzBDC46g4CFDsRnc873d8K-E,2451
|
|
408
420
|
firefighter/slack/views/modals/select.py,sha256=Y-Ji_ALnzhYkXDBAyi497UL1Xn2vCGqXCtj8eog75Jk,3312
|
|
409
421
|
firefighter/slack/views/modals/send_sos.py,sha256=bP6HgYyDwPrIcTq7n_sQz6UQsxhYbvBDS4HjM0uRccA,4838
|
|
410
422
|
firefighter/slack/views/modals/status.py,sha256=C8-eJRtquSeaHe568SC7yCFef1k14m2_6lUqBezdSH8,3970
|
|
411
423
|
firefighter/slack/views/modals/trigger_oncall.py,sha256=h_LAD5X5rjMFWiDYTEp5VB9OaF7sTvKZhNaW3KQkw5M,5065
|
|
412
424
|
firefighter/slack/views/modals/update.py,sha256=OF9sf-Z6IiviNmjN28MQNYiUbJ5tha0MdHUQyPpVFiY,2150
|
|
413
425
|
firefighter/slack/views/modals/update_roles.py,sha256=De3Gv67MZQHyNdonX3S99F5MtKF_Rj3y71gdWibxBaM,2419
|
|
414
|
-
firefighter/slack/views/modals/update_status.py,sha256=
|
|
426
|
+
firefighter/slack/views/modals/update_status.py,sha256=kJYcyruEwo7hok-z4Ge8HPxLMc-XPm-OrB7X_faNd7U,6000
|
|
415
427
|
firefighter/slack/views/modals/utils.py,sha256=zKLJD2KhTGcX2d9WCYwshYRa6ok_9-ED1_pgOLp028s,2133
|
|
416
428
|
firefighter/slack/views/modals/base_modal/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
417
429
|
firefighter/slack/views/modals/base_modal/base.py,sha256=7mvOxZTtegSmitSMnDvu8BK0qLUXoudUsda6CaLjdkY,12479
|
|
@@ -440,6 +452,7 @@ firefighter_tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU
|
|
|
440
452
|
firefighter_tests/conftest.py,sha256=fyVZNk4PX0ATjIjmq0BYjC9k3og26kkpC73npEgFlv8,3228
|
|
441
453
|
firefighter_tests/test_api/test_api_landbot.py,sha256=a5Fk-8GCLCdwqJOovFzw75uDq6pn6sKIcTRHpbMzx_M,4602
|
|
442
454
|
firefighter_tests/test_api/test_api_urls.py,sha256=Nn7Flq7dWGYJjgZK5HGdGECFMwKiDdfDYI0g09gXK-c,1936
|
|
455
|
+
firefighter_tests/test_api/test_renderer.py,sha256=ycDknfY31heSmJ1naTd4qxeSHmds9fzt5nxMHLnR6uU,1142
|
|
443
456
|
firefighter_tests/test_confluence/test_confluence_utils.py,sha256=hD5M4mYwrHlil9KPARNQ5OINdRc5njfYCIdq8a6jUB8,1847
|
|
444
457
|
firefighter_tests/test_firefighter/test_firefighter_utils.py,sha256=og79bkErCBQB-xkw88J-ronT0dDEChuqlMke2ElxATo,3590
|
|
445
458
|
firefighter_tests/test_firefighter/test_logging.py,sha256=4HUH73vLDwmOCpMiXwDasMLL7F0kA1B_DxE48mqswSk,878
|
|
@@ -458,14 +471,19 @@ firefighter_tests/test_incidents/test_forms/test_update_key_events.py,sha256=rHR
|
|
|
458
471
|
firefighter_tests/test_incidents/test_forms/test_update_status_workflow.py,sha256=q0xXU2BbBG8B0uvvyBWlo4HM8ckbcNAP05Fq8oJNtOw,16270
|
|
459
472
|
firefighter_tests/test_incidents/test_forms/test_workflow_transitions.py,sha256=priKh7QYZxGDPu2SvPC8pGnqOsZWg5cLkyC40pDvLAU,7184
|
|
460
473
|
firefighter_tests/test_incidents/test_models/test_incident_category.py,sha256=aRoBOhb8fNjLF9CMPZ1FXM8AT51Cd80XPsY2Y3wHY_M,5701
|
|
461
|
-
firefighter_tests/test_incidents/test_models/test_incident_model.py,sha256=
|
|
474
|
+
firefighter_tests/test_incidents/test_models/test_incident_model.py,sha256=P5tmU5X4grt-yvoqjfuBkbd5tAWX3TptN-b_R3-1a9A,4719
|
|
462
475
|
firefighter_tests/test_incidents/test_models/test_migrations/test_incident_migrations.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
463
476
|
firefighter_tests/test_incidents/test_utils/test_date_utils.py,sha256=ogP7qOEwItL4YGI5gbQPVssOS9ilwiuZC8OrT2qngBY,6568
|
|
464
477
|
firefighter_tests/test_incidents/test_views/test_incident_detail_view.py,sha256=gKKFWIZVrD_P4p6DJjeHCW5uGXBUBVlCd95gJJYDpWQ,680
|
|
465
478
|
firefighter_tests/test_incidents/test_views/test_index_view.py,sha256=InpxbaWOFwRn4YWeIKZhj17vMymrQQf2p2LFhe2Bcdw,816
|
|
466
479
|
firefighter_tests/test_jira_app/__init__.py,sha256=JxZ3v-0kiHOoO-N3kR8NHTmD8tEvuEYKW1GX_S1ZLMY,33
|
|
467
480
|
firefighter_tests/test_jira_app/conftest.py,sha256=HmZd7EBZgng-rb3kIaB14TPVMixMG4YEvnShVqgjodE,545
|
|
481
|
+
firefighter_tests/test_jira_app/test_incident_key_events_sync.py,sha256=ytXHzlwckhWV7eufaEqwLqA-FTWTUF1o0bFSyZ0ippQ,3891
|
|
468
482
|
firefighter_tests/test_jira_app/test_jira_client_watchers.py,sha256=IBrFjwhOP0rfm58BBq339CySxjdJkPYjGmISC4oQhZc,4803
|
|
483
|
+
firefighter_tests/test_jira_app/test_models.py,sha256=QfMLrJVXSWqu29XEbJO6xXpOkugcdWti5_bmCEX2m3Y,4626
|
|
484
|
+
firefighter_tests/test_jira_app/test_postmortem_issue_link.py,sha256=CF0UDmHOY08Oj3MYtDKNtkVDq_nbQ0nesvFWF8Rv944,7750
|
|
485
|
+
firefighter_tests/test_jira_app/test_postmortem_service.py,sha256=DAlQxlPlB_Fd038hLeSu0PCO-Izo0z1dBgLXv4twvTE,15114
|
|
486
|
+
firefighter_tests/test_jira_app/test_timeline_template.py,sha256=_PtFnIib2HfjyylNRQXcjvdhrsoAJICOKauIDsYFQRk,4902
|
|
469
487
|
firefighter_tests/test_raid/conftest.py,sha256=i_TOquYIMLDyVQ97uqxTqPJszVz4qq7L_Q7YJxTuS1o,4090
|
|
470
488
|
firefighter_tests/test_raid/test_raid_alert_p4_p5.py,sha256=rz9orbt1E1vJ5POQyVZ6-SEPvqB55-xhwIWHicdfgDg,9356
|
|
471
489
|
firefighter_tests/test_raid/test_raid_client.py,sha256=KTqELERpWno7XhF9LpabpxkHoJiWWrryUg5LHi5Yfjo,22456
|
|
@@ -474,7 +492,7 @@ firefighter_tests/test_raid/test_raid_forms.py,sha256=8hiXftYPO_lY0heKHqoreUW2s8
|
|
|
474
492
|
firefighter_tests/test_raid/test_raid_models.py,sha256=nq-fVClB_P24W8WrZruOPt8wlHUVGYI7wxJR7tH6AnM,5042
|
|
475
493
|
firefighter_tests/test_raid/test_raid_serializers.py,sha256=xkMK9npvDMAr2pUpP4mFbLszrR6qyTzsJRd-uNOzEhM,22560
|
|
476
494
|
firefighter_tests/test_raid/test_raid_service.py,sha256=AqVyrRjW2tr0sfbXS4lGlJ7mcxB2ACEXAR8Bv0pXnj0,16755
|
|
477
|
-
firefighter_tests/test_raid/test_raid_signals.py,sha256=
|
|
495
|
+
firefighter_tests/test_raid/test_raid_signals.py,sha256=QkGd3alp5O6t5kz66ukpNY-uZdIKJsqxvEPc8exORP4,8974
|
|
478
496
|
firefighter_tests/test_raid/test_raid_transitions.py,sha256=mtmMKwukxmZSM-R619BQ3Z_2AB-qY6imvDgUF0A3_tw,4784
|
|
479
497
|
firefighter_tests/test_raid/test_raid_utils.py,sha256=i6JBwim1G-qynwxprNZekxl9K7Vis4FFvNkw3wT2jTM,1016
|
|
480
498
|
firefighter_tests/test_raid/test_raid_views.py,sha256=paAhh4k2EDlmG1ehwNhMuYIhr1okqrvM7xlkaTAo2V0,6825
|
|
@@ -484,23 +502,24 @@ firefighter_tests/test_slack/test_conversation_tags.py,sha256=nNqTZRRBfF6Z4wpFSY
|
|
|
484
502
|
firefighter_tests/test_slack/test_signals_downgrade.py,sha256=mgl4H5vwr2kImf6g4IZbhv7YEPmMzbYSaVr8E6taL88,5420
|
|
485
503
|
firefighter_tests/test_slack/test_slack_utils.py,sha256=9PLobMNXh3xDyFuwzcQFpKJhe4j__sIgf_WRHIpANJw,3957
|
|
486
504
|
firefighter_tests/test_slack/messages/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
487
|
-
firefighter_tests/test_slack/messages/test_slack_messages.py,sha256=
|
|
505
|
+
firefighter_tests/test_slack/messages/test_slack_messages.py,sha256=rs7zeBa_xsAyZIfXbOI1RA-zgViEPT5ZFNw6paBJvxc,17299
|
|
488
506
|
firefighter_tests/test_slack/test_models/test_conversations.py,sha256=t3ttmgwiu7c-N55iU3XZPmrkEhvkTzJoXszJncy4Bts,793
|
|
489
507
|
firefighter_tests/test_slack/test_models/test_incident_channel.py,sha256=qWoGe9iadmK6-R8usWvjH87AHRkvhG_dHQeC3kHeJrs,17487
|
|
490
508
|
firefighter_tests/test_slack/test_models/test_slack_user.py,sha256=uzur-Rf03I5dpUTO4ZI6O1arBUrAorg1Zvgshf8M-J4,7000
|
|
491
509
|
firefighter_tests/test_slack/views/modals/conftest.py,sha256=TKJVQgqWaFs3Gg1T526pti9XpZBtQs47WBH6L_qSDeo,4532
|
|
492
510
|
firefighter_tests/test_slack/views/modals/test_close.py,sha256=wuqMkpyUWKvC_gaTnJvRmdm8-wsmbLpCU_ith4ihsLY,45447
|
|
493
|
-
firefighter_tests/test_slack/views/modals/test_closure_reason_modal.py,sha256=
|
|
511
|
+
firefighter_tests/test_slack/views/modals/test_closure_reason_modal.py,sha256=hKfBv8fHfObmZc7OL6NUnxFueA1bowkNbu_-MF1anYI,5615
|
|
494
512
|
firefighter_tests/test_slack/views/modals/test_edit.py,sha256=ykirry-S3i6PtoSs3rff_k6jqmvv1oMWC_iR8e5Jsg0,12022
|
|
495
513
|
firefighter_tests/test_slack/views/modals/test_form_utils_multiple_choice.py,sha256=Svab_ZyYTMf0T-uJEQcm7gS1WzxtC4gPh1W--Z2v_Y8,8415
|
|
514
|
+
firefighter_tests/test_slack/views/modals/test_key_event_message.py,sha256=BCg-c27ZLJqNgFuG4JDgXrSTp8_sT4FeBtpASzSq8NI,1107
|
|
496
515
|
firefighter_tests/test_slack/views/modals/test_open.py,sha256=IzgG9le5NN_CvltehAIqkj94ioTKCqdA6yoRp2NlNsE,10700
|
|
497
516
|
firefighter_tests/test_slack/views/modals/test_opening_unified.py,sha256=OejtLyc_mehav2TDaLzUnhilMNvhCzc6T4FodCqfQPk,17406
|
|
498
517
|
firefighter_tests/test_slack/views/modals/test_send_sos.py,sha256=_rE6jD-gOzcGyhlY0R9GzlGtPx65oOOguJYdENgxtLc,1289
|
|
499
518
|
firefighter_tests/test_slack/views/modals/test_status.py,sha256=oQzPfwdg2tkbo9nfkO1GfS3WydxqSC6vy1AZjZDKT30,2226
|
|
500
|
-
firefighter_tests/test_slack/views/modals/test_update_status.py,sha256=
|
|
519
|
+
firefighter_tests/test_slack/views/modals/test_update_status.py,sha256=3ARHZPs22FTx7IjgOldzEpVxxWeHqEbe4kQphUuSp34,55928
|
|
501
520
|
firefighter_tests/test_slack/views/modals/test_utils.py,sha256=DJd2n9q6fFu8UuCRdiq9U_Cn19MdnC5c-ydLLrk6rkc,5218
|
|
502
|
-
firefighter_incident-0.0.
|
|
503
|
-
firefighter_incident-0.0.
|
|
504
|
-
firefighter_incident-0.0.
|
|
505
|
-
firefighter_incident-0.0.
|
|
506
|
-
firefighter_incident-0.0.
|
|
521
|
+
firefighter_incident-0.0.23.dist-info/METADATA,sha256=5pD4MN6Pms0cgm7f16chi42i52sjKke_UItPGRcP9ds,5570
|
|
522
|
+
firefighter_incident-0.0.23.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
523
|
+
firefighter_incident-0.0.23.dist-info/entry_points.txt,sha256=c13meJbv7YNmYz7MipMOQwzQ5IeFOPXUBYAJ44XMQsM,61
|
|
524
|
+
firefighter_incident-0.0.23.dist-info/licenses/LICENSE,sha256=krRiGp-a9-1nH1bWpBEdxyTKLhjLmn6DMVVoIb0zF90,1087
|
|
525
|
+
firefighter_incident-0.0.23.dist-info/RECORD,,
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from firefighter.api.renderer import CSVRenderer
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_tablize_hides_headers_when_labels_hidden() -> None:
|
|
7
|
+
renderer = CSVRenderer()
|
|
8
|
+
rows = list(renderer.tablize([{"id": 1, "value": "foo"}], labels="__hidden__"))
|
|
9
|
+
|
|
10
|
+
assert rows == [[1, "foo"]]
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def test_tablize_applies_custom_labels() -> None:
|
|
14
|
+
renderer = CSVRenderer()
|
|
15
|
+
rows = list(
|
|
16
|
+
renderer.tablize(
|
|
17
|
+
[{"a": 1, "b": 2}],
|
|
18
|
+
header=["b", "a"],
|
|
19
|
+
labels={"a": "Column A", "b": "Column B"},
|
|
20
|
+
)
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
assert rows[0] == ["Column B", "Column A"]
|
|
24
|
+
assert rows[1] == [2, 1]
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def test_get_headers_preserves_explicit_order_without_wildcards() -> None:
|
|
28
|
+
renderer = CSVRenderer()
|
|
29
|
+
_, header = renderer._get_headers([{"x": 1, "y": 2}], ["y", "x"])
|
|
30
|
+
|
|
31
|
+
assert header == ["y", "x"]
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def test_get_headers_expands_wildcards_sorted() -> None:
|
|
35
|
+
renderer = CSVRenderer()
|
|
36
|
+
_, header = renderer._get_headers(
|
|
37
|
+
[{"fixed": 1, "meta.foo.value": 10, "meta.bar.value": 20}],
|
|
38
|
+
["fixed", "meta.*.value"],
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
assert header == ["fixed", "meta.bar.value", "meta.foo.value"]
|
|
@@ -96,3 +96,32 @@ class TestIncidentSetStatus:
|
|
|
96
96
|
|
|
97
97
|
assert recovered_event is not None
|
|
98
98
|
assert recovered_event.event_type == "recovered"
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
@pytest.mark.django_db
|
|
102
|
+
class TestIncidentNeedsPostmortem:
|
|
103
|
+
"""Test the needs_postmortem property logic.
|
|
104
|
+
|
|
105
|
+
NOTE: The needs_postmortem property checks if:
|
|
106
|
+
1. Priority requires postmortem (P1/P2)
|
|
107
|
+
2. Environment is PRD
|
|
108
|
+
3. At least one post-mortem system is enabled (Confluence OR Jira)
|
|
109
|
+
"""
|
|
110
|
+
|
|
111
|
+
def test_p3_does_not_need_postmortem(self) -> None:
|
|
112
|
+
"""Test that P3 incident does not require postmortem even in PRD."""
|
|
113
|
+
incident = IncidentFactory.create(
|
|
114
|
+
priority__value=3, # P3
|
|
115
|
+
priority__needs_postmortem=False,
|
|
116
|
+
environment__value="PRD",
|
|
117
|
+
)
|
|
118
|
+
assert incident.needs_postmortem is False
|
|
119
|
+
|
|
120
|
+
def test_p1_non_prd_does_not_need_postmortem(self) -> None:
|
|
121
|
+
"""Test that P1 incident in non-PRD environment does not require postmortem."""
|
|
122
|
+
incident = IncidentFactory.create(
|
|
123
|
+
priority__value=1, # P1
|
|
124
|
+
priority__needs_postmortem=True,
|
|
125
|
+
environment__value="STG", # Use STG instead of DEV
|
|
126
|
+
)
|
|
127
|
+
assert incident.needs_postmortem is False
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"""Tests for syncing incident key events to Jira post-mortem timeline."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
from unittest.mock import MagicMock, patch
|
|
7
|
+
|
|
8
|
+
import pytest
|
|
9
|
+
from django.test import override_settings
|
|
10
|
+
from django.utils import timezone
|
|
11
|
+
|
|
12
|
+
from firefighter.incidents.enums import IncidentStatus
|
|
13
|
+
from firefighter.incidents.factories import IncidentFactory, UserFactory
|
|
14
|
+
from firefighter.incidents.models.incident_update import IncidentUpdate
|
|
15
|
+
from firefighter.incidents.signals import incident_key_events_updated
|
|
16
|
+
from firefighter.jira_app.models import JiraPostMortem
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
from firefighter.incidents.models.incident import Incident
|
|
20
|
+
from firefighter.incidents.models.user import User
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@pytest.mark.django_db
|
|
24
|
+
class TestIncidentKeyEventsSync:
|
|
25
|
+
"""Test syncing incident key events to Jira post-mortem timeline."""
|
|
26
|
+
|
|
27
|
+
@staticmethod
|
|
28
|
+
@override_settings(ENABLE_JIRA_POSTMORTEM=True)
|
|
29
|
+
@patch("firefighter.jira_app.signals.incident_key_events_updated.JiraClient")
|
|
30
|
+
def test_key_events_update_syncs_to_jira_postmortem(
|
|
31
|
+
mock_jira_client: MagicMock,
|
|
32
|
+
) -> None:
|
|
33
|
+
"""Test that updating key events triggers Jira post-mortem timeline update."""
|
|
34
|
+
# Mock Jira client and issue
|
|
35
|
+
mock_client_instance = MagicMock()
|
|
36
|
+
mock_issue = MagicMock()
|
|
37
|
+
mock_client_instance.jira.issue.return_value = mock_issue
|
|
38
|
+
mock_jira_client.return_value = mock_client_instance
|
|
39
|
+
|
|
40
|
+
# Create a user
|
|
41
|
+
user: User = UserFactory.create()
|
|
42
|
+
|
|
43
|
+
# Create an incident
|
|
44
|
+
incident: Incident = IncidentFactory.create(
|
|
45
|
+
_status=IncidentStatus.POST_MORTEM,
|
|
46
|
+
created_by=user,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
# Create a Jira post-mortem for the incident
|
|
50
|
+
JiraPostMortem.objects.create(
|
|
51
|
+
incident=incident,
|
|
52
|
+
jira_issue_key="TEST-123",
|
|
53
|
+
jira_issue_id="12345",
|
|
54
|
+
created_by=user,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
# Create a key event (incident update)
|
|
58
|
+
now = timezone.now()
|
|
59
|
+
IncidentUpdate.objects.create(
|
|
60
|
+
incident=incident,
|
|
61
|
+
event_type="detected",
|
|
62
|
+
event_ts=now,
|
|
63
|
+
created_by=user,
|
|
64
|
+
message="Issue was detected",
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
# Trigger the signal (simulating key events update)
|
|
68
|
+
incident_key_events_updated.send(
|
|
69
|
+
sender="test",
|
|
70
|
+
incident=incident,
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
# Verify Jira issue was fetched
|
|
74
|
+
mock_client_instance.jira.issue.assert_called_once_with("TEST-123")
|
|
75
|
+
|
|
76
|
+
# Verify issue.update was called
|
|
77
|
+
mock_issue.update.assert_called_once()
|
|
78
|
+
call_kwargs = mock_issue.update.call_args.kwargs
|
|
79
|
+
|
|
80
|
+
# Verify timeline field was updated
|
|
81
|
+
assert "fields" in call_kwargs
|
|
82
|
+
# Timeline field ID should be present (exact ID depends on config)
|
|
83
|
+
assert len(call_kwargs["fields"]) > 0
|
|
84
|
+
|
|
85
|
+
# Verify timeline content was generated (contains basic incident info)
|
|
86
|
+
timeline_content = next(iter(call_kwargs["fields"].values()))
|
|
87
|
+
assert "Timeline" in timeline_content
|
|
88
|
+
assert "Incident created" in timeline_content
|
|
89
|
+
|
|
90
|
+
@staticmethod
|
|
91
|
+
@patch("firefighter.jira_app.signals.incident_key_events_updated.JiraClient")
|
|
92
|
+
def test_key_events_update_no_postmortem_skips_sync(
|
|
93
|
+
mock_jira_client: MagicMock,
|
|
94
|
+
) -> None:
|
|
95
|
+
"""Test that updating key events for incident without post-mortem skips sync."""
|
|
96
|
+
# Create a user
|
|
97
|
+
user: User = UserFactory.create()
|
|
98
|
+
|
|
99
|
+
# Create an incident WITHOUT post-mortem
|
|
100
|
+
incident: Incident = IncidentFactory.create(
|
|
101
|
+
_status=IncidentStatus.OPEN,
|
|
102
|
+
created_by=user,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
# Trigger the signal
|
|
106
|
+
incident_key_events_updated.send(
|
|
107
|
+
sender="test",
|
|
108
|
+
incident=incident,
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
# Verify Jira client was NOT called
|
|
112
|
+
mock_jira_client.assert_not_called()
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"""Tests for jira_app models."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import pytest
|
|
6
|
+
from django.conf import settings
|
|
7
|
+
from django.db.utils import IntegrityError
|
|
8
|
+
|
|
9
|
+
from firefighter.incidents.factories import IncidentFactory, UserFactory
|
|
10
|
+
from firefighter.jira_app.models import JiraPostMortem
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@pytest.mark.django_db
|
|
14
|
+
class TestJiraPostMortem:
|
|
15
|
+
"""Test JiraPostMortem model."""
|
|
16
|
+
|
|
17
|
+
def test_create_jira_postmortem(self):
|
|
18
|
+
"""Test creating a JiraPostMortem instance."""
|
|
19
|
+
incident = IncidentFactory()
|
|
20
|
+
user = UserFactory()
|
|
21
|
+
|
|
22
|
+
jira_pm = JiraPostMortem.objects.create(
|
|
23
|
+
incident=incident,
|
|
24
|
+
jira_issue_key="INCIDENT-123",
|
|
25
|
+
jira_issue_id="10001",
|
|
26
|
+
created_by=user,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
assert jira_pm.incident == incident
|
|
30
|
+
assert jira_pm.jira_issue_key == "INCIDENT-123"
|
|
31
|
+
assert jira_pm.jira_issue_id == "10001"
|
|
32
|
+
assert jira_pm.created_by == user
|
|
33
|
+
assert jira_pm.created_at is not None
|
|
34
|
+
assert jira_pm.updated_at is not None
|
|
35
|
+
|
|
36
|
+
def test_jira_postmortem_one_to_one_relationship(self):
|
|
37
|
+
"""Test OneToOne relationship with Incident."""
|
|
38
|
+
incident = IncidentFactory()
|
|
39
|
+
user = UserFactory()
|
|
40
|
+
|
|
41
|
+
# Create first post-mortem
|
|
42
|
+
jira_pm1 = JiraPostMortem.objects.create(
|
|
43
|
+
incident=incident,
|
|
44
|
+
jira_issue_key="INCIDENT-123",
|
|
45
|
+
jira_issue_id="10001",
|
|
46
|
+
created_by=user,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
# Access from incident side
|
|
50
|
+
assert hasattr(incident, "jira_postmortem_for")
|
|
51
|
+
assert incident.jira_postmortem_for == jira_pm1
|
|
52
|
+
|
|
53
|
+
# Try to create second post-mortem for same incident should fail
|
|
54
|
+
with pytest.raises(IntegrityError):
|
|
55
|
+
JiraPostMortem.objects.create(
|
|
56
|
+
incident=incident,
|
|
57
|
+
jira_issue_key="INCIDENT-456",
|
|
58
|
+
jira_issue_id="10002",
|
|
59
|
+
created_by=user,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
def test_jira_postmortem_issue_url_property(self):
|
|
63
|
+
"""Test issue_url property generates correct Jira URL."""
|
|
64
|
+
incident = IncidentFactory()
|
|
65
|
+
user = UserFactory()
|
|
66
|
+
|
|
67
|
+
jira_pm = JiraPostMortem.objects.create(
|
|
68
|
+
incident=incident,
|
|
69
|
+
jira_issue_key="INCIDENT-123",
|
|
70
|
+
jira_issue_id="10001",
|
|
71
|
+
created_by=user,
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
expected_url = f"{settings.RAID_JIRA_API_URL}/browse/INCIDENT-123"
|
|
75
|
+
assert jira_pm.issue_url == expected_url
|
|
76
|
+
|
|
77
|
+
@pytest.mark.django_db(transaction=True)
|
|
78
|
+
def test_jira_postmortem_unique_constraints(self):
|
|
79
|
+
"""Test uniqueness constraints on jira_issue_key and jira_issue_id."""
|
|
80
|
+
incident1 = IncidentFactory()
|
|
81
|
+
incident2 = IncidentFactory()
|
|
82
|
+
incident3 = IncidentFactory()
|
|
83
|
+
user = UserFactory()
|
|
84
|
+
|
|
85
|
+
# Create first post-mortem
|
|
86
|
+
JiraPostMortem.objects.create(
|
|
87
|
+
incident=incident1,
|
|
88
|
+
jira_issue_key="INCIDENT-123",
|
|
89
|
+
jira_issue_id="10001",
|
|
90
|
+
created_by=user,
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
# Try to create second post-mortem with same jira_issue_key
|
|
94
|
+
with pytest.raises(IntegrityError):
|
|
95
|
+
JiraPostMortem.objects.create(
|
|
96
|
+
incident=incident2,
|
|
97
|
+
jira_issue_key="INCIDENT-123", # Duplicate key
|
|
98
|
+
jira_issue_id="10002",
|
|
99
|
+
created_by=user,
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
# Try to create second post-mortem with same jira_issue_id
|
|
103
|
+
with pytest.raises(IntegrityError):
|
|
104
|
+
JiraPostMortem.objects.create(
|
|
105
|
+
incident=incident3,
|
|
106
|
+
jira_issue_key="INCIDENT-456",
|
|
107
|
+
jira_issue_id="10001", # Duplicate ID
|
|
108
|
+
created_by=user,
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
def test_jira_postmortem_str_representation(self):
|
|
112
|
+
"""Test string representation of JiraPostMortem."""
|
|
113
|
+
incident = IncidentFactory()
|
|
114
|
+
user = UserFactory()
|
|
115
|
+
|
|
116
|
+
jira_pm = JiraPostMortem.objects.create(
|
|
117
|
+
incident=incident,
|
|
118
|
+
jira_issue_key="INCIDENT-123",
|
|
119
|
+
jira_issue_id="10001",
|
|
120
|
+
created_by=user,
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
expected_str = f"Jira Post-mortem INCIDENT-123 for incident #{incident.id}"
|
|
124
|
+
assert str(jira_pm) == expected_str
|
|
125
|
+
|
|
126
|
+
def test_jira_postmortem_created_by_optional(self):
|
|
127
|
+
"""Test that created_by is optional (can be None)."""
|
|
128
|
+
incident = IncidentFactory()
|
|
129
|
+
|
|
130
|
+
jira_pm = JiraPostMortem.objects.create(
|
|
131
|
+
incident=incident,
|
|
132
|
+
jira_issue_key="INCIDENT-123",
|
|
133
|
+
jira_issue_id="10001",
|
|
134
|
+
created_by=None, # Optional field
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
assert jira_pm.created_by is None
|
|
138
|
+
assert jira_pm.incident == incident
|