diff --git a/zerver/lib/remote_server.py b/zerver/lib/remote_server.py index 1653bd62d1..7bb3841e4e 100644 --- a/zerver/lib/remote_server.py +++ b/zerver/lib/remote_server.py @@ -12,7 +12,7 @@ from pydantic import UUID4, BaseModel, ConfigDict, Field, Json, field_validator from analytics.lib.counts import LOGGING_COUNT_STAT_PROPERTIES_NOT_SENT_TO_BOUNCER from analytics.models import InstallationCount, RealmCount -from version import API_FEATURE_LEVEL, ZULIP_VERSION +from version import API_FEATURE_LEVEL, ZULIP_MERGE_BASE, ZULIP_VERSION from zerver.actions.realm_settings import ( do_set_push_notifications_enabled_end_timestamp, do_set_realm_property, @@ -107,6 +107,7 @@ class AnalyticsRequest(BaseModel): realmauditlog_rows: Optional[Json[List[RealmAuditLogDataForAnalytics]]] = None realms: Json[List[RealmDataForAnalytics]] version: Optional[Json[str]] + merge_base: Optional[Json[str]] api_feature_level: Optional[Json[int]] @@ -423,6 +424,7 @@ def send_server_data_to_push_bouncer(consider_usage_statistics: bool = True) -> realmauditlog_rows=realmauditlog_data, realms=get_realms_info_for_push_bouncer(), version=ZULIP_VERSION, + merge_base=ZULIP_MERGE_BASE, api_feature_level=API_FEATURE_LEVEL, ) diff --git a/zerver/tests/test_push_notifications.py b/zerver/tests/test_push_notifications.py index 0e1da4ada7..d9ab8a0f24 100644 --- a/zerver/tests/test_push_notifications.py +++ b/zerver/tests/test_push_notifications.py @@ -1832,12 +1832,15 @@ class AnalyticsBouncerTest(BouncerTestCase): realmauditlog_rows=realmauditlog_data, realms=[], version=None, + merge_base=None, api_feature_level=None, ) result = self.uuid_post( self.server_uuid, "/api/v1/remotes/server/analytics", - request.model_dump(round_trip=True, exclude={"realms", "version", "api_feature_level"}), + request.model_dump( + round_trip=True, exclude={"realms", "version", "merge_base", "api_feature_level"} + ), subdomain="", ) self.assert_json_error(result, "Data is out of order.") @@ -1871,12 +1874,15 @@ class AnalyticsBouncerTest(BouncerTestCase): realmauditlog_rows=[], realms=realms_data, version=None, + merge_base=None, api_feature_level=None, ) result = self.uuid_post( self.server_uuid, "/api/v1/remotes/server/analytics", - request.model_dump(round_trip=True, exclude={"version", "api_feature_level"}), + request.model_dump( + round_trip=True, exclude={"version", "merge_base", "api_feature_level"} + ), subdomain="", ) self.assert_json_error( @@ -1928,12 +1934,15 @@ class AnalyticsBouncerTest(BouncerTestCase): realmauditlog_rows=realmauditlog_data, realms=[], version=None, + merge_base=None, api_feature_level=None, ) result = self.uuid_post( self.server_uuid, "/api/v1/remotes/server/analytics", - request.model_dump(round_trip=True, exclude={"version", "api_feature_level"}), + request.model_dump( + round_trip=True, exclude={"version", "merge_base", "api_feature_level"} + ), subdomain="", ) self.assert_json_error(result, "Invalid event type.") @@ -1954,12 +1963,15 @@ class AnalyticsBouncerTest(BouncerTestCase): realmauditlog_rows=realmauditlog_data, realms=[], version=None, + merge_base=None, api_feature_level=None, ) result = self.uuid_post( self.server_uuid, "/api/v1/remotes/server/analytics", - request.model_dump(round_trip=True, exclude={"version", "api_feature_level"}), + request.model_dump( + round_trip=True, exclude={"version", "merge_base", "api_feature_level"} + ), subdomain="", ) self.assert_json_success(result) diff --git a/zilencer/migrations/0064_remotezulipserver_last_merge_base.py b/zilencer/migrations/0064_remotezulipserver_last_merge_base.py new file mode 100644 index 0000000000..37c163ad88 --- /dev/null +++ b/zilencer/migrations/0064_remotezulipserver_last_merge_base.py @@ -0,0 +1,17 @@ +# Generated by Django 5.0.6 on 2024-06-23 00:29 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("zilencer", "0063_convert_ids_to_bigints"), + ] + + operations = [ + migrations.AddField( + model_name="remotezulipserver", + name="last_merge_base", + field=models.CharField(max_length=128, null=True), + ), + ] diff --git a/zilencer/models.py b/zilencer/models.py index 095ba1ad4a..038ce90021 100644 --- a/zilencer/models.py +++ b/zilencer/models.py @@ -35,6 +35,7 @@ class RemoteZulipServer(models.Model): API_KEY_LENGTH = 64 HOSTNAME_MAX_LENGTH = 128 VERSION_MAX_LENGTH = 128 + MERGE_BASE_MAX_LENGTH = 128 # The unique UUID (`zulip_org_id`) and API key (`zulip_org_key`) # for this remote server registration. @@ -49,6 +50,7 @@ class RemoteZulipServer(models.Model): last_updated = models.DateTimeField("last updated", auto_now=True) last_request_datetime = models.DateTimeField(null=True) last_version = models.CharField(max_length=VERSION_MAX_LENGTH, null=True) + last_merge_base = models.CharField(max_length=MERGE_BASE_MAX_LENGTH, null=True) last_api_feature_level = models.PositiveIntegerField(null=True) # Whether the server registration has been deactivated. diff --git a/zilencer/views.py b/zilencer/views.py index 0193e0efc4..7f81b537ce 100644 --- a/zilencer/views.py +++ b/zilencer/views.py @@ -1147,6 +1147,7 @@ def remote_server_post_analytics( realmauditlog_rows: Optional[Json[List[RealmAuditLogDataForAnalytics]]] = None, realms: Optional[Json[List[RealmDataForAnalytics]]] = None, version: Optional[Json[str]] = None, + merge_base: Optional[Json[str]] = None, api_feature_level: Optional[Json[int]] = None, ) -> HttpResponse: # Lock the server, preventing this from racing with other @@ -1156,10 +1157,15 @@ def remote_server_post_analytics( remote_server_version_updated = False if version is not None: version = version[0 : RemoteZulipServer.VERSION_MAX_LENGTH] - if version != server.last_version or api_feature_level != server.last_api_feature_level: + if ( + version != server.last_version + or merge_base != server.last_merge_base + or api_feature_level != server.last_api_feature_level + ): server.last_version = version + server.last_merge_base = merge_base server.last_api_feature_level = api_feature_level - server.save(update_fields=["last_version", "last_api_feature_level"]) + server.save(update_fields=["last_version", "last_merge_base", "last_api_feature_level"]) remote_server_version_updated = True validate_incoming_table_data(