Skip to content

Commit cc7e530

Browse files
authored
Allow editing of first_notification_milestone for current release. (#6127)
1 parent e8f06bd commit cc7e530

File tree

3 files changed

+44
-25
lines changed

3 files changed

+44
-25
lines changed

api/features_api_test.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -925,8 +925,14 @@ def test_patch__enterprise_first_notice_wrong_non_enterprise_feature(self, mock_
925925
@mock.patch('api.channels_api.construct_specified_milestones_details')
926926
def test_patch__enterprise_first_notice_enterprise_feature(self, mock_call):
927927
"""PATCH request successful with provided first_enterprise_notification_milestone."""
928-
stable_date = _datetime_to_str(datetime.now().replace(year=datetime.now().year + 1, day=1))
929-
mock_call.return_value = { 100: { 'version': 100, 'stable_date': stable_date } }
928+
stable_date = _datetime_to_str(datetime.now().replace(
929+
year=datetime.now().year, day=1))
930+
next_stable_date = _datetime_to_str(datetime.now().replace(
931+
year=datetime.now().year + 1, day=1))
932+
mock_call.return_value = {
933+
100: { 'version': 100, 'stable_date': stable_date },
934+
101: { 'version': 101, 'stable_date': next_stable_date },
935+
}
930936

931937
# Signed-in user with permissions.
932938
testing_config.sign_in('admin@example.com', 123567890)
@@ -957,8 +963,14 @@ def test_patch__enterprise_first_notice_enterprise_feature(self, mock_call):
957963
@mock.patch('api.channels_api.construct_specified_milestones_details')
958964
def test_patch__enterprise_first_notice_newly_breaking_feature(self, mock_call):
959965
"""PATCH request successful with provided first_enterprise_notification_milestone."""
960-
stable_date = _datetime_to_str(datetime.now().replace(year=datetime.now().year + 1, day=1))
961-
mock_call.return_value = { 100: { 'version': 100, 'stable_date': stable_date } }
966+
stable_date = _datetime_to_str(datetime.now().replace(
967+
year=datetime.now().year, day=1))
968+
next_stable_date = _datetime_to_str(datetime.now().replace(
969+
year=datetime.now().year + 1, day=1))
970+
mock_call.return_value = {
971+
100: { 'version': 100, 'stable_date': stable_date },
972+
101: { 'version': 101, 'stable_date': next_stable_date },
973+
}
962974

963975
# Signed-in user with permissions.
964976
testing_config.sign_in('admin@example.com', 123567890)

internals/enterprise_helpers.py

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -85,19 +85,22 @@ def is_update_first_notification_milestone(feature: FeatureEntry, new_fields: di
8585
return False
8686
milestone = int(milestone)
8787

88-
# We cannot set a milestone that has already been released
89-
milestone_details = channels_api.construct_specified_milestones_details(milestone, milestone)
90-
if (milestone not in milestone_details or
91-
_str_to_datetime(milestone_details[milestone]['stable_date']) <= datetime.now()):
88+
# We don't allow setting an old milestone, but allow current and future.
89+
next_milestone = milestone + 1
90+
next_milestone_details = channels_api.construct_specified_milestones_details(
91+
next_milestone, next_milestone)
92+
if (next_milestone not in next_milestone_details or
93+
_str_to_datetime(next_milestone_details[next_milestone]['stable_date']) <= datetime.now()):
9294
return False
9395

94-
# We cannot update the milestone of a feature that has already been announced
96+
# We don't allow changing the existing milestone value if it was in old release notes.
9597
if feature.first_enterprise_notification_milestone != None:
96-
milestone = feature.first_enterprise_notification_milestone
97-
previous_milestone_details = channels_api.construct_specified_milestones_details(milestone,
98-
milestone)
99-
if (milestone in previous_milestone_details and
100-
_str_to_datetime(previous_milestone_details[milestone]['stable_date']) <= datetime.now()):
98+
existing_milestone = feature.first_enterprise_notification_milestone
99+
existing_next = existing_milestone + 1
100+
existing_next_details = channels_api.construct_specified_milestones_details(
101+
existing_next, existing_next)
102+
if (existing_next in existing_next_details and
103+
_str_to_datetime(existing_next_details[existing_next]['stable_date']) <= datetime.now()):
101104
return False
102105

103106
if feature.feature_type == FEATURE_TYPE_ENTERPRISE_ID:

internals/enterprise_helpers_test.py

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,12 @@ def tearDown(self):
5353
@mock.patch('api.channels_api.construct_specified_milestones_details')
5454
def test__needs_default_first_notification_milestone__new_feature(self, mock_specified_milestones):
5555
mock_specified_milestones.return_value = {
56-
99: {
57-
'version': 99,
56+
99: {
57+
'version': 99,
5858
'stable_date': self.now.replace(year=self.now.year - 1, day=1).strftime(DATETIME_FORMAT)
5959
},
60-
100: {
61-
'version': 100,
60+
100: {
61+
'version': 100,
6262
'stable_date': self.now.replace(year=self.now.year + 1, day=1).strftime(DATETIME_FORMAT)
6363
},
6464
}
@@ -124,7 +124,7 @@ def test__needs_default_first_notification_milestone__new_feature(self, mock_spe
124124

125125
@mock.patch('api.channels_api.construct_specified_milestones_details')
126126
def test__needs_default_first_notification_milestone__update(self, mock_specified_milestones):
127-
127+
128128
mock_specified_milestones.return_value = {
129129
99: {
130130
'version': 99,
@@ -187,7 +187,7 @@ def test__needs_default_first_notification_milestone__update(self, mock_specifie
187187
self.assertFalse(needs_default_first_notification_milestone(
188188
self.normal_feature,
189189
{ 'enterprise_impact': ENTERPRISE_IMPACT_LOW, 'first_enterprise_notification_milestone': 100}))
190-
190+
191191
# Breaking feature becoming normal feature missing the milestone
192192
self.assertFalse(needs_default_first_notification_milestone(
193193
self.breaking_feature, { 'enterprise_impact': ENTERPRISE_IMPACT_NONE}))
@@ -223,19 +223,23 @@ def test__is_update_first_notification_milestone(self,
223223
'version': 99,
224224
'stable_date': self.now.replace(year=self.now.year - 1, day=1).strftime(DATETIME_FORMAT)
225225
},
226-
100: {
226+
100: { # Current milestone on stable channel
227227
'version': 100,
228-
'stable_date': self.now.replace(year=self.now.year + 1, day=1).strftime(DATETIME_FORMAT)
228+
'stable_date': self.now.replace(year=self.now.year, day=1).strftime(DATETIME_FORMAT)
229229
},
230230
101: {
231231
'version': 101,
232+
'stable_date': self.now.replace(year=self.now.year + 1, day=1).strftime(DATETIME_FORMAT)
233+
},
234+
102: {
235+
'version': 102,
232236
'stable_date': self.now.replace(year=self.now.year + 2, day=1).strftime(DATETIME_FORMAT)
233237
},
234238
}
235239
mock_channel_details.return_value = {
236240
'beta': {
237241
'version': 100,
238-
'stable_date': self.now.replace(year=self.now.year + 1, day=1).strftime(DATETIME_FORMAT)
242+
'stable_date': self.now.replace(year=self.now.year, day=1).strftime(DATETIME_FORMAT)
239243
}
240244
}
241245

@@ -289,7 +293,7 @@ def test__is_update_first_notification_milestone(self,
289293
self.assertTrue(is_update_first_notification_milestone(
290294
self.normal_feature,
291295
{ 'enterprise_impact': ENTERPRISE_IMPACT_LOW, 'first_enterprise_notification_milestone': 100}))
292-
296+
293297
# Breaking feature becoming normal feature missing the milestone
294298
self.assertFalse(is_update_first_notification_milestone(
295299
self.breaking_feature, { 'enterprise_impact': ENTERPRISE_IMPACT_NONE}))
@@ -368,7 +372,7 @@ def test__should_remove_first_notice_milestone(self, mock_specified_milestones):
368372
'stable_date': now.replace(year=now.year + 2, day=1).strftime(DATETIME_FORMAT)
369373
},
370374
}
371-
375+
372376
# Enterprise feature with no changes and no existing milestone
373377
self.assertFalse(should_remove_first_notice_milestone(self.enterprise_feature, {}))
374378

0 commit comments

Comments
 (0)