Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/experimenter/experiments/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class ExperimentAdmin(admin.ModelAdmin):
"proposed_enrollment",
"proposed_duration",
"bugzilla_id",
"normandy_slug",
"data_science_bugzilla_url",
"feature_bugzilla_url",
"related_work",
Expand Down
3 changes: 3 additions & 0 deletions app/experimenter/experiments/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -812,6 +812,9 @@ def save(self, *args, **kwargs):
and self.new_status == Experiment.STATUS_SHIP
and experiment.bugzilla_id
):
experiment.normandy_slug = experiment.generate_normandy_slug()
experiment.save()

tasks.add_experiment_comment_task.delay(
self.request.user.id, experiment.id
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Generated by Django 2.1.7 on 2019-03-13 16:05

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [("experiments", "0030_experiment_engineering_owner")]

operations = [
migrations.AddField(
model_name="experiment",
name="normandy_slug",
field=models.CharField(blank=True, max_length=255, null=True),
)
]
20 changes: 20 additions & 0 deletions app/experimenter/experiments/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ class Experiment(ExperimentConstants, models.Model):
dashboard_image_url = models.URLField(blank=True, null=True)

bugzilla_id = models.CharField(max_length=255, blank=True, null=True)
normandy_slug = models.CharField(max_length=255, blank=True, null=True)

data_science_bugzilla_url = models.URLField(blank=True, null=True)
feature_bugzilla_url = models.URLField(blank=True, null=True)
Expand Down Expand Up @@ -236,6 +237,25 @@ def test_tube_url(self):
"https://firefox-test-tube.herokuapp.com/experiments/{slug}/"
).format(slug=self.slug)

def generate_normandy_slug(self):
error_msg = (
"The {field} must be set before a Normandy slug can be generated"
)

if not self.firefox_version:
raise ValueError(error_msg.format(field="Firefox version"))

if not self.firefox_channel:
raise ValueError(error_msg.format(field="Firefox channel"))

if not self.bugzilla_id:
raise ValueError(error_msg.format(field="Bugzilla ID"))

return (
f"{self.type}-{self.slug}-{self.firefox_channel}"
f"-{self.firefox_version}-bug-{self.bugzilla_id}"
).lower()

@property
def has_external_urls(self):
return (
Expand Down
18 changes: 16 additions & 2 deletions app/experimenter/experiments/tests/test_forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -1047,17 +1047,31 @@ def test_sets_bugzilla_id_when_draft_becomes_review(self):
self.user.id, experiment.id
)

def test_adds_bugzilla_comment_when_review_becomes_ship(self):
def test_adds_bugzilla_comment_and_normandy_slug_when_becomes_ship(self):
experiment = ExperimentFactory.create_with_status(
Experiment.STATUS_REVIEW, bugzilla_id="12345"
target_status=Experiment.STATUS_REVIEW,
type=Experiment.TYPE_PREF,
name="Experiment Name",
slug="experiment-slug",
firefox_version="57.0",
firefox_channel=Experiment.CHANNEL_NIGHTLY,
bugzilla_id="12345",
)
self.assertEqual(experiment.normandy_slug, None)

form = ExperimentStatusForm(
request=self.request,
data={"status": experiment.STATUS_SHIP},
instance=experiment,
)

self.assertTrue(form.is_valid())
experiment = form.save()

self.assertEqual(
experiment.normandy_slug,
"pref-experiment-slug-nightly-57.0-bug-12345",
)
self.mock_tasks_add_comment.delay.assert_called_with(
self.user.id, experiment.id
)
Expand Down
50 changes: 50 additions & 0 deletions app/experimenter/experiments/tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,56 @@ def test_has_external_urls_is_true_when_bugzilla_and_test_tube_urls(self):
)
self.assertTrue(experiment.has_external_urls)

def test_generate_normandy_slug_raises_valueerror_without_version(self):
experiment = ExperimentFactory.create(
type=Experiment.TYPE_PREF,
slug="experiment-slug",
firefox_version="",
firefox_channel="Nightly",
bugzilla_id="12345",
)

with self.assertRaises(ValueError):
experiment.generate_normandy_slug()

def test_generate_normandy_slug_raises_valueerror_without_channel(self):
experiment = ExperimentFactory.create(
type=Experiment.TYPE_PREF,
slug="experiment-slug",
firefox_version="57.0",
firefox_channel="",
bugzilla_id="12345",
)

with self.assertRaises(ValueError):
experiment.generate_normandy_slug()

def test_generate_normandy_slug_raises_valueerror_without_bugzilla(self):
experiment = ExperimentFactory.create(
type=Experiment.TYPE_PREF,
slug="experiment-slug",
firefox_version="57.0",
firefox_channel="Nightly",
bugzilla_id="",
)

with self.assertRaises(ValueError):
experiment.generate_normandy_slug()

def test_generate_normandy_slug_returns_expected_slug(self):
experiment = ExperimentFactory.create(
type=Experiment.TYPE_PREF,
slug="experiment-slug",
firefox_version="57.0",
firefox_channel="Nightly",
bugzilla_id="12345",
)

self.assertEqual(
experiment.generate_normandy_slug(),
"pref-experiment-slug-nightly-57.0-bug-12345",
)

def test_start_date_returns_proposed_start_date_if_change_is_missing(self):
experiment = ExperimentFactory.create_with_variants()
self.assertEqual(experiment.start_date, experiment.proposed_start_date)
Expand Down