Skip to content

Commit

Permalink
feat(schemas): Add a firefoxLabsDescriptionLinks field to DesktopNimb…
Browse files Browse the repository at this point in the history
…usExperiment (#12137)

Because:

- some Firefox Labs descriptions include placeholder links; and
- we need to provide the URLs for those links outside the Fluent strings

This comit:

- adds a new field to the DesktopNimbusExperiment model; and
- bumps the version of mozilla-nimbus-schemas to 2025.1.1.

Fixes #12132
  • Loading branch information
brennie authored Feb 3, 2025
1 parent 5cea8f1 commit fa4a7e3
Show file tree
Hide file tree
Showing 12 changed files with 207 additions and 14 deletions.
2 changes: 1 addition & 1 deletion schemas/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2024.12.2
2025.1.1
12 changes: 12 additions & 0 deletions schemas/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,12 @@ export interface DesktopAllVersionsNimbusExperiment {
* The description shown in Firefox Labs (Fluent ID)
*/
firefoxLabsDescription?: string | null;
/**
* Links that will be used with the firefoxLabsDescription Fluent ID. May be null for Firefox Labs Opt-In recipes that do not use links.
*/
firefoxLabsDescriptionLinks?: {
[k: string]: string;
} | null;
/**
* Opt out of feature schema validation.
*/
Expand Down Expand Up @@ -512,6 +518,12 @@ export interface DesktopNimbusExperiment {
* The description shown in Firefox Labs (Fluent ID)
*/
firefoxLabsDescription?: string | null;
/**
* Links that will be used with the firefoxLabsDescription Fluent ID. May be null for Firefox Labs Opt-In recipes that do not use links.
*/
firefoxLabsDescriptionLinks?: {
[k: string]: string;
} | null;
/**
* Opt out of feature schema validation.
*/
Expand Down
10 changes: 9 additions & 1 deletion schemas/mozilla_nimbus_schemas/experiments/experiments.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from enum import Enum
from typing import Any, Literal

from pydantic import BaseModel, ConfigDict, Field, RootModel, model_validator
from pydantic import BaseModel, ConfigDict, Field, HttpUrl, RootModel, model_validator
from pydantic.json_schema import SkipJsonSchema
from typing_extensions import Self

Expand Down Expand Up @@ -302,6 +302,13 @@ class DesktopNimbusExperiment(BaseExperiment):
description="The description shown in Firefox Labs (Fluent ID)",
default=None,
)
firefoxLabsDescriptionLinks: dict[str, HttpUrl] | None = Field(
description=(
"Links that will be used with the firefoxLabsDescription Fluent ID. May be "
"null for Firefox Labs Opt-In recipes that do not use links."
),
default=None,
)
featureValidationOptOut: bool | SkipJsonSchema[None] = Field(
description="Opt out of feature schema validation.",
default=None,
Expand Down Expand Up @@ -358,6 +365,7 @@ def validate_firefox_labs(cls, data: Self) -> Self:
"then": {
"required": [
"firefoxLabsDescription",
"firefoxLabsDescriptionLinks",
"firefoxLabsGroup",
"firefoxLabsTitle",
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
"isFirefoxLabsOptIn": true,
"firefoxLabsTitle": "test-title",
"firefoxLabsDescription": "test-desc",
"firefoxLabsDescriptionLinks": null,
"firefoxLabsGroup": "test",
"isRollout": false,
"requiresRestart": false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
"isFirefoxLabsOptIn": true,
"firefoxLabsTitle": "test-title",
"firefoxLabsDescription": "test-desc",
"firefoxLabsDescriptionLinks": null,
"firefoxLabsGroup": "test",
"isRollout": true,
"requiresRestart": false
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@

{
"appId": "firefox-desktop",
"appName": "firefox_desktop",
"application": "firefox-desktop",
"arguments": {},
"branches": [
{
"feature": {
"featureId": "this-is-included-for-desktop-pre-95-support",
"enabled": false,
"value": {}
},
"features": [
{
"featureId": "pocketNewtab",
"value": { "enabled": "true" }
},
{
"featureId": "upgradeDialog",
"value": {
"enabled": false
}
}
],
"ratio": 1,
"slug": "control"
},
{
"feature": {
"featureId": "this-is-included-for-desktop-pre-95-support",
"enabled": false,
"value": {}
},
"features": [
{
"featureId": "pocketNewtab",
"value": {
"enabled": true,
"compactLayout": true,
"lastCardMessageEnabled": true,
"loadMore": true,
"newFooterSection": true
}
},
{
"featureId": "upgradeDialog",
"value": {
"enabled": true
}
}
],
"ratio": 1,
"slug": "treatment"
}
],
"bucketConfig": {
"count": 10000,
"namespace": "firefox-desktop-multifeature-test",
"randomizationUnit": "normandy_id",
"start": 0,
"total": 10000
},
"channel": "nightly",
"endDate": null,
"featureIds": ["upgradeDialog", "pocketNewtab"],
"id": "mr2-upgrade-spotlight-holdback",
"isEnrollmentPaused": false,
"outcomes": [],
"probeSets": [],
"proposedDuration": 63,
"proposedEnrollment": 7,
"referenceBranch": "control",
"schemaVersion": "1.7.1",
"slug": "firefox-desktop-multifeature-test",
"startDate": "2021-10-26",
"targeting": "true",
"userFacingDescription": "Experimenting on onboarding content when you upgrade Firefox.",
"userFacingName": "MR2 Upgrade Spotlight Holdback",
"isFirefoxLabsOptIn": true,
"firefoxLabsTitle": "test-title",
"firefoxLabsDescription": "test-desc",
"firefoxLabsDescriptionLinks": {
"foo": "https://example.com/foo",
"bar": "https://example.com/bar"
},
"firefoxLabsGroup": "test",
"isRollout": true,
"requiresRestart": false
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ def load_schema(name: str) -> Validator:
validator = validator_for(schema)
validator.check_schema(schema)

return validator(schema)
return validator(schema, format_checker=validator.FORMAT_CHECKER)


@pytest.mark.parametrize("experiment_file", FIXTURE_DIR.joinpath("desktop").iterdir())
Expand Down Expand Up @@ -137,6 +137,7 @@ def test_desktop_nimbus_expirement_with_fxlabs_opt_in_is_not_rollout(
"isFirefoxLabsOptIn": True,
"firefoxLabsTitle": "test-title",
"firefoxLabsDescription": "test-desc",
"firefoxLabsDescriptionLinks": None,
"firefoxLabsGroup": "test-group",
}
)
Expand All @@ -154,6 +155,7 @@ def test_desktop_nimbus_experiment_with_fxlabs_opt_in_is_rollout(
"isFirefoxLabsOptIn": True,
"firefoxLabsTitle": "test-title",
"firefoxLabsDescription": "test-desc",
"firefoxLabsDescriptionLinks": None,
"firefoxLabsGroup": "test-group",
}
)
Expand All @@ -174,19 +176,50 @@ def test_desktop_nimbus_experiment_with_fxlabs_opt_in_but_missing_required_field
experiment_json["isFirefoxLabsOptIn"] = True
validate_desktop_experiment(experiment_json, valid=False, valid_all_versions=False)

errors = list(
desktop_all_versions_nimbus_experiment_schema_validator.iter_errors(
error_messages = [
e.message
for e in desktop_all_versions_nimbus_experiment_schema_validator.iter_errors(
experiment_json
)
)
error_messages = [e.message for e in errors]
]

assert len(error_messages) == 5
assert len(error_messages) == 6
assert error_messages.count("'firefoxLabsTitle' is a required property") == 3
assert error_messages.count("'firefoxLabsDescription' is a required property") == 1
assert (
error_messages.count("'firefoxLabsDescriptionLinks' is a required property") == 1
)
assert error_messages.count("'firefoxLabsGroup' is a required property") == 1


def test_desktop_nimbus_experiment_with_fxlabs_opt_in_invalid_description_links(
validate_desktop_experiment,
desktop_all_versions_nimbus_experiment_schema_validator,
):
experiment_json = _desktop_nimbus_experiment(isRollout=True)
experiment_json.update(
{
"isFirefoxLabsOptIn": True,
"firefoxLabsTitle": "placeholder-title",
"firefoxLabsDescription": "placeholder-desc",
"firefoxLabsDescriptionLinks": {"foo": "bar"},
"firefoxLabsGroup": "placeholder-group",
}
)

validate_desktop_experiment(experiment_json, valid=False, valid_all_versions=False)

error_messages = [
e.message
for e in desktop_all_versions_nimbus_experiment_schema_validator.iter_errors(
experiment_json
)
]

assert len(error_messages) == 1
assert "{'foo': 'bar'} is not valid under any of the given schemas" in error_messages


def _desktop_nimbus_experiment(isRollout: bool) -> dict[str, Any]:
return {
"appId": "firefox-desktop",
Expand Down
2 changes: 1 addition & 1 deletion schemas/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@mozilla/nimbus-schemas",
"version": "2024.12.2",
"version": "2025.1.1",
"description": "Schemas used by Mozilla Nimbus and related projects.",
"main": "index.d.ts",
"repository": {
Expand Down
15 changes: 13 additions & 2 deletions schemas/poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions schemas/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "mozilla-nimbus-schemas"
version = "2024.12.2"
version = "2025.1.1"
description = "Schemas used by Mozilla Nimbus and related projects."
authors = ["mikewilli"]
license = "MPL 2.0"
Expand All @@ -21,11 +21,12 @@ typing-extensions = ">=4.0.1" # Required until Python 3.11
jsonschema = "^4.23.0"

[tool.poetry.group.dev.dependencies]
ruff = ">=0.5.0,<0.9.2"
PyYAML = "^6.0"
black = ">=23.3,<25.0"
pytest = "^7.3.1"
rfc3987 = "^1.3.8"
ruff = ">=0.5.0,<0.9.2"
twine = "^5.1.1"
PyYAML = "^6.0"


[build-system]
Expand Down
18 changes: 18 additions & 0 deletions schemas/schemas/DesktopAllVersionsNimbusExperiment.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,23 @@
],
"description": "The description shown in Firefox Labs (Fluent ID)"
},
"firefoxLabsDescriptionLinks": {
"anyOf": [
{
"additionalProperties": {
"format": "uri",
"maxLength": 2083,
"minLength": 1,
"type": "string"
},
"type": "object"
},
{
"type": "null"
}
],
"description": "Links that will be used with the firefoxLabsDescription Fluent ID. May be null for Firefox Labs Opt-In recipes that do not use links."
},
"featureValidationOptOut": {
"description": "Opt out of feature schema validation.",
"type": "boolean"
Expand Down Expand Up @@ -256,6 +273,7 @@
},
"required": [
"firefoxLabsDescription",
"firefoxLabsDescriptionLinks",
"firefoxLabsGroup",
"firefoxLabsTitle"
],
Expand Down
18 changes: 18 additions & 0 deletions schemas/schemas/DesktopNimbusExperiment.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,23 @@
],
"description": "The description shown in Firefox Labs (Fluent ID)"
},
"firefoxLabsDescriptionLinks": {
"anyOf": [
{
"additionalProperties": {
"format": "uri",
"maxLength": 2083,
"minLength": 1,
"type": "string"
},
"type": "object"
},
{
"type": "null"
}
],
"description": "Links that will be used with the firefoxLabsDescription Fluent ID. May be null for Firefox Labs Opt-In recipes that do not use links."
},
"featureValidationOptOut": {
"description": "Opt out of feature schema validation.",
"type": "boolean"
Expand Down Expand Up @@ -256,6 +273,7 @@
},
"required": [
"firefoxLabsDescription",
"firefoxLabsDescriptionLinks",
"firefoxLabsGroup",
"firefoxLabsTitle"
],
Expand Down

0 comments on commit fa4a7e3

Please sign in to comment.