Skip to content

Philimon/l10n_choose_split #713

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Aug 12, 2025
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
31 changes: 31 additions & 0 deletions .github/workflows/l10n-write-mappings.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
name: L10N output mapping splits

run-name: ${{ github.actor }} is writing L10N mapping splits
on:
schedule:
- cron: "0 0 * * 1"

permissions:
contents: "write"

jobs:
Select-Channels:
runs-on: ubuntu-latest
outputs:
channels: ${{ steps.splits.outputs.channels }}
steps:
- name: Create app token
uses: actions/create-github-app-token@v1
id: app-token
with:
app-id: ${{ secrets.BOT_CLIENT_ID }}
private-key: ${{ secrets.BOT_PRIVATE_KEY }}
- name: Checkout repository
uses: actions/checkout@v4
with:
token: ${{ steps.app-token.outputs.token }}
- name: Select test channels
id: splits
run: |
python3 choose_l10n_beta_split.py
38 changes: 38 additions & 0 deletions choose_l10n_beta_split.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import json
import logging
import sys
from collections import defaultdict

from choose_l10n_ci_set import valid_l10n_mappings


def distribute_mappings_evenly(mappings):
"""
Distribute the selected mappings into 3 splits and return the container.

Args:
mappings (dict): A dictionary of mappings, where the keys are sites and the values are sets of regions.
"""
if not mappings:
return {}
# sort the mappings by the length of the regions per site
mappings = dict(sorted(mappings.items(), key=lambda val: len(val[1]), reverse=True))
# place the mappings into 3 containers evenly according to the load
loads = [0, 0, 0]
balanced_splits = [defaultdict(list) for _ in range(3)]
for site, regions in mappings.items():
min_idx = loads.index(min(loads))
balanced_splits[min_idx][site] = list(regions)
loads[min_idx] += len(regions)
return balanced_splits


if __name__ == "__main__":
l10n_mappings = valid_l10n_mappings()
all_splits = distribute_mappings_evenly(l10n_mappings)
if not all_splits:
logging.warning("No valid l10n mappings")
sys.exit(1)
for idx, split in enumerate(all_splits, start=1):
with open(f"l10n_CM/beta_run_splits/l10n_split_{idx}.json", "w") as f:
json.dump(split, f)
51 changes: 19 additions & 32 deletions choose_l10n_ci_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,35 +34,6 @@ def valid_l10n_mappings():
return mapping


def distribute_mappings_evenly(mappings, version):
"""
Distribute the selected mappings if its a reportable run.

Args:
mappings (dict): A dictionary of mappings, where the keys are sites and the values are sets of regions.
version (int): The beta_version of the beta.
"""
if not mappings:
return {}
if os.environ.get("TESTRAIL_REPORT"):
# sort the mappings by the length of the regions per site
mappings = dict(
sorted(mappings.items(), key=lambda val: len(val[1]), reverse=True)
)
# place the mappings into 3 containers evenly according to the load
loads = [0, 0, 0]
containers = [defaultdict(set) for _ in range(3)]
for key, value in mappings.items():
min_idx = loads.index(min(loads))
containers[min_idx][key] = value
loads[min_idx] += len(value)
# get container index according to beta beta_version
run_idx = version % 3
return containers[run_idx]
else:
return mappings


def process_changed_file(f, selected_mappings):
"""
process the changed file to add the site/region mappings.
Expand Down Expand Up @@ -108,6 +79,21 @@ def save_mappings(selected_container):
f.writelines(current_running_mappings)


def select_l10n_mappings(beta_version):
"""
Select the correct l10n mappings.

Args:
beta_version: the current beta version.
"""
beta_split = (beta_version % 3) + 1
if os.path.exists(f"l10n_CM/beta_run_splits/l10n_split_{beta_split}.json"):
with open(f"l10n_CM/beta_run_splits/l10n_split_{beta_split}.json", "r") as f:
return json.load(f)
else:
return valid_l10n_mappings()


if __name__ == "__main__":
if os.path.exists(".env"):
with open(".env") as fh:
Expand All @@ -134,11 +120,12 @@ def save_mappings(selected_container):
except ValueError:
# failsafe beta_version
beta_version = 0
l10n_mappings = valid_l10n_mappings()
# choose split number
l10n_mappings = select_l10n_mappings(beta_version)
sample_mappings = {k: v for k, v in l10n_mappings.items() if k.startswith("demo")}
if os.environ.get("TESTRAIL_REPORT") or os.environ.get("MANUAL"):
# Run all tests if this is a scheduled beta or a manual run
save_mappings(distribute_mappings_evenly(l10n_mappings, beta_version))
save_mappings(l10n_mappings)
sys.exit(0)

re_set_all = [
Expand Down Expand Up @@ -199,5 +186,5 @@ def save_mappings(selected_container):
selected_mappings |= sample_mappings
break

save_mappings(distribute_mappings_evenly(selected_mappings, beta_version))
save_mappings(selected_mappings)
sys.exit(0)
32 changes: 32 additions & 0 deletions l10n_CM/beta_run_splits/l10n_split_1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"demo": [
"US",
"GB",
"DE",
"FR",
"PL",
"ES",
"CA"
],
"bijoubrigitte": [
"DE"
],
"calvinklein": [
"US"
],
"aldoshoes": [
"US"
],
"peacocks": [
"GB"
],
"assos": [
"GB"
],
"fnac": [
"FR"
],
"canadatire": [
"CA"
]
}
1 change: 1 addition & 0 deletions l10n_CM/beta_run_splits/l10n_split_2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"amazon": ["US", "CA", "DE", "FR"], "walmart": ["US", "CA"], "mediamarkt": ["DE"], "zalando": ["PL"], "bestbuy": ["US"], "apple": ["US"], "whittard": ["GB"], "tiffany": ["IT"], "yellowkorner": ["FR"], "burtsbees": ["CA"]}
1 change: 1 addition & 0 deletions l10n_CM/beta_run_splits/l10n_split_3.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"ebay": ["ES", "IT", "CA", "GB"], "etsy": ["US", "CA"], "justspices": ["DE"], "lowes": ["US"], "newegg": ["US"], "wish": ["US"], "diy": ["GB"], "artsper": ["FR"], "newbalance": ["CA"]}
16 changes: 6 additions & 10 deletions modules/testrail_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import subprocess
import sys

from choose_l10n_ci_set import distribute_mappings_evenly, valid_l10n_mappings
from choose_l10n_ci_set import select_l10n_mappings
from modules import taskcluster as tc
from modules import testrail as tr
from modules.testrail import TestRail
Expand Down Expand Up @@ -187,11 +187,9 @@ def reportable(platform_to_test=None):

plan_entries = this_plan.get("entries")
if os.environ.get("FX_L10N"):
report = True
beta_version = int(minor_num.split("b")[-1])
distributed_mappings = distribute_mappings_evenly(
valid_l10n_mappings(), beta_version
)
distributed_mappings = select_l10n_mappings(beta_version)
expected_mappings = sum(map(lambda x: len(x), distributed_mappings.values()))
covered_mappings = 0
# keeping this logic to still see how many mappings are reported.
for entry in plan_entries:
Expand All @@ -205,13 +203,11 @@ def reportable(platform_to_test=None):
and platform in run_platform
):
covered_mappings += 1
report = False
logging.warning(
f"Potentially matching run found for {platform}, may be reportable. (Found {covered_mappings} site/region mappings reported.)"
f"Potentially matching run found for {platform}, may be reportable. (Found {covered_mappings} site/region mappings reported, expected {expected_mappings}.)"
)
logging.warning(f"Run is reportable: {report}")
# Only report when there is a new beta and no other site/region mappings are reported.
return report
# Only report when there is a new beta without a reported plan or if the selected split is not completely reported.
return covered_mappings < expected_mappings
else:
covered_suites = 0
for entry in plan_entries:
Expand Down
Loading