Skip to content

Commit d5567f6

Browse files
IzaakGoughIzaak Goughcabljac
authored
fix: preserve crashlytics options (#279)
Co-authored-by: Izaak Gough <izaakgough@gmail.com> Co-authored-by: Jacob Cable <32874567+cabljac@users.noreply.github.com>
1 parent c86ad57 commit d5567f6

2 files changed

Lines changed: 143 additions & 12 deletions

File tree

src/firebase_functions/options.py

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -652,6 +652,27 @@ def _endpoint(
652652
)
653653

654654

655+
def _alert_options_to_firebase_alert_options(
656+
options: EventHandlerOptions,
657+
alert_type: str | AlertType,
658+
) -> FirebaseAlertOptions:
659+
app_id = getattr(options, "app_id", None)
660+
661+
# Restrict to fields supported by FirebaseAlertOptions
662+
allowed_fields = {f.name for f in _dataclasses.fields(FirebaseAlertOptions)}
663+
664+
option_values = {
665+
field.name: getattr(options, field.name)
666+
for field in _dataclasses.fields(options)
667+
if field.name in allowed_fields and field.name not in {"alert_type", "app_id"}
668+
}
669+
return FirebaseAlertOptions(
670+
**option_values,
671+
alert_type=alert_type,
672+
app_id=app_id,
673+
)
674+
675+
655676
@_dataclasses.dataclass(frozen=True, kw_only=True)
656677
class AppDistributionOptions(EventHandlerOptions):
657678
"""
@@ -669,9 +690,9 @@ def _endpoint(
669690
**kwargs,
670691
) -> _manifest.ManifestEndpoint:
671692
assert kwargs["alert_type"] is not None
672-
return FirebaseAlertOptions(
673-
alert_type=kwargs["alert_type"],
674-
app_id=self.app_id,
693+
return _alert_options_to_firebase_alert_options(
694+
self,
695+
kwargs["alert_type"],
675696
)._endpoint(**kwargs)
676697

677698

@@ -692,9 +713,9 @@ def _endpoint(
692713
**kwargs,
693714
) -> _manifest.ManifestEndpoint:
694715
assert kwargs["alert_type"] is not None
695-
return FirebaseAlertOptions(
696-
alert_type=kwargs["alert_type"],
697-
app_id=self.app_id,
716+
return _alert_options_to_firebase_alert_options(
717+
self,
718+
kwargs["alert_type"],
698719
)._endpoint(**kwargs)
699720

700721

@@ -715,9 +736,9 @@ def _endpoint(
715736
**kwargs,
716737
) -> _manifest.ManifestEndpoint:
717738
assert kwargs["alert_type"] is not None
718-
return FirebaseAlertOptions(
719-
alert_type=kwargs["alert_type"],
720-
app_id=self.app_id,
739+
return _alert_options_to_firebase_alert_options(
740+
self,
741+
kwargs["alert_type"],
721742
)._endpoint(**kwargs)
722743

723744

@@ -733,8 +754,9 @@ def _endpoint(
733754
**kwargs,
734755
) -> _manifest.ManifestEndpoint:
735756
assert kwargs["alert_type"] is not None
736-
return FirebaseAlertOptions(
737-
alert_type=kwargs["alert_type"],
757+
return _alert_options_to_firebase_alert_options(
758+
self,
759+
kwargs["alert_type"],
738760
)._endpoint(**kwargs)
739761

740762

tests/test_options.py

Lines changed: 110 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,19 @@
1717

1818
from pytest import raises
1919

20-
from firebase_functions import https_fn, options, params
20+
from firebase_functions import alerts_fn, https_fn, options, params
21+
from firebase_functions.alerts import (
22+
app_distribution_fn,
23+
billing_fn,
24+
crashlytics_fn,
25+
performance_fn,
26+
)
2127
from firebase_functions.private.serving import functions_as_yaml, merge_required_apis
2228

2329
# pylint: disable=protected-access
2430

31+
ALERT_SECRET = params.SecretParam("GITLAB_PERSONAL_ACCESS_TOKEN")
32+
2533

2634
@https_fn.on_call()
2735
def asamplefunction(_):
@@ -196,3 +204,104 @@ def test_invoker_with_no_element_throws():
196204
AssertionError, match="HttpsOptions: Invalid option for invoker - must be a non-empty list."
197205
):
198206
options.HttpsOptions(invoker=[])._endpoint(func_name="test")
207+
208+
209+
def _assert_alert_endpoint_options(endpoint, expected_alert_type, expect_app_id: str | None = None):
210+
assert endpoint.region == ["europe-west1"]
211+
assert endpoint.maxInstances == 1
212+
assert endpoint.secretEnvironmentVariables == [{"key": "GITLAB_PERSONAL_ACCESS_TOKEN"}]
213+
assert endpoint.eventTrigger["retry"] is True
214+
assert endpoint.eventTrigger["eventFilters"]["alerttype"] == expected_alert_type
215+
if expect_app_id is None:
216+
assert "appid" not in endpoint.eventTrigger["eventFilters"]
217+
else:
218+
assert endpoint.eventTrigger["eventFilters"]["appid"] == expect_app_id
219+
220+
221+
def test_crashlytics_options_preserved_in_alert_endpoint():
222+
@crashlytics_fn.on_new_fatal_issue_published(
223+
secrets=[ALERT_SECRET],
224+
region="europe-west1",
225+
max_instances=1,
226+
retry=True,
227+
app_id="app-123",
228+
)
229+
def sample(_event):
230+
return None
231+
232+
_assert_alert_endpoint_options(
233+
sample.__firebase_endpoint__,
234+
"crashlytics.newFatalIssue",
235+
expect_app_id="app-123",
236+
)
237+
238+
239+
def test_app_distribution_options_preserved_in_alert_endpoint():
240+
@app_distribution_fn.on_new_tester_ios_device_published(
241+
secrets=[ALERT_SECRET],
242+
region="europe-west1",
243+
max_instances=1,
244+
retry=True,
245+
app_id="app-123",
246+
)
247+
def sample(_event):
248+
return None
249+
250+
_assert_alert_endpoint_options(
251+
sample.__firebase_endpoint__,
252+
"appDistribution.newTesterIosDevice",
253+
expect_app_id="app-123",
254+
)
255+
256+
257+
def test_performance_options_preserved_in_alert_endpoint():
258+
@performance_fn.on_threshold_alert_published(
259+
secrets=[ALERT_SECRET],
260+
region="europe-west1",
261+
max_instances=1,
262+
retry=True,
263+
app_id="app-123",
264+
)
265+
def sample(_event):
266+
return None
267+
268+
_assert_alert_endpoint_options(
269+
sample.__firebase_endpoint__,
270+
"performance.threshold",
271+
expect_app_id="app-123",
272+
)
273+
274+
275+
def test_billing_options_preserved_in_alert_endpoint():
276+
@billing_fn.on_plan_update_published(
277+
secrets=[ALERT_SECRET],
278+
region="europe-west1",
279+
max_instances=1,
280+
retry=True,
281+
)
282+
def sample(_event):
283+
return None
284+
285+
_assert_alert_endpoint_options(
286+
sample.__firebase_endpoint__,
287+
"billing.planUpdate",
288+
)
289+
290+
291+
def test_firebase_alert_options_preserved_in_alert_endpoint():
292+
@alerts_fn.on_alert_published(
293+
alert_type=alerts_fn.AlertType.CRASHLYTICS_NEW_FATAL_ISSUE,
294+
secrets=[ALERT_SECRET],
295+
region="europe-west1",
296+
max_instances=1,
297+
retry=True,
298+
app_id="app-123",
299+
)
300+
def sample(_event):
301+
return None
302+
303+
_assert_alert_endpoint_options(
304+
sample.__firebase_endpoint__,
305+
"crashlytics.newFatalIssue",
306+
expect_app_id="app-123",
307+
)

0 commit comments

Comments
 (0)