• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mozilla / relman-auto-nag / #5617

18 Sep 2025 05:44PM UTC coverage: 20.81% (+0.003%) from 20.807%
#5617

push

coveralls-python

web-flow
Apply suggestion from @suhaibmujahid

Co-authored-by: Suhaib Mujahid <suhaibmujahid@gmail.com>

426 of 3022 branches covered (14.1%)

0 of 1 new or added line in 1 file covered. (0.0%)

4 existing lines in 1 file now uncovered.

1943 of 9337 relevant lines covered (20.81%)

0.21 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/bugbot/rules/web_platform_features.py
1
# This Source Code Form is subject to the terms of the Mozilla Public
2
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
3
# You can obtain one at http://mozilla.org/MPL/2.0/.
4

5
import urllib
×
6
from dataclasses import dataclass
×
7
from typing import Any, Iterable, Mapping, Optional
×
8

9
from bugbot import gcp
×
10
from bugbot.bzcleaner import BzCleaner
×
11

12

13
@dataclass
×
14
class FeatureUrls:
×
15
    feature: str
×
16
    spec_url: Optional[list[str]]
×
17
    feature_url: str
×
18
    sp_url: Optional[str]
×
19

20

21
def url_keys(urls: Iterable[str]) -> Mapping[tuple[str, str], str]:
×
22
    rv = {}
×
23
    for url in urls:
×
24
        try:
×
25
            parsed = urllib.parse.urlparse(url)
×
26
            if parsed.hostname is None:
×
27
                continue
×
28
            rv[(parsed.hostname, parsed.path)] = url
×
29
        except ValueError:
×
30
            pass
×
31
    return rv
×
32

33

34
class WebPlatformFeatures(BzCleaner):
×
35
    def __init__(self) -> None:
×
36
        super().__init__()
×
37
        self.feature_bugs: Mapping[int, FeatureUrls] = {}
×
38

39
    def description(self) -> str:
×
40
        return "Update See Also for web-features bugs"
×
41

42
    def filter_no_nag_keyword(self) -> bool:
×
43
        return False
×
44

45
    def has_default_products(self) -> bool:
×
46
        return False
×
47

48
    def columns(self) -> list[str]:
×
49
        return ["id", "summary", "added"]
×
50

51
    def handle_bug(
×
52
        self, bug: dict[str, Any], data: dict[str, Any]
53
    ) -> Optional[dict[str, Any]]:
54
        features_key = bug["id"]
×
55
        bug_id = str(bug["id"])
×
56

57
        changes = {}
×
58
        if bug_id not in data:
×
59
            data[bug_id] = {}
×
60
        data[bug_id]["added"] = []
×
61
        if features_key in self.feature_bugs:
×
NEW
62
            existing_keys = url_keys(bug["see_also"] + [bug["url"]])
×
63

64
            feature_urls = self.feature_bugs[features_key]
×
65
            expected_urls = [feature_urls.feature_url]
×
66
            if feature_urls.sp_url is not None:
×
67
                expected_urls.append(feature_urls.sp_url)
×
68
            if feature_urls.spec_url is not None:
×
69
                expected_urls.extend(feature_urls.spec_url)
×
70
            expected_keys = url_keys(expected_urls)
×
UNCOV
71
            add_urls = [
×
72
                url for key, url in expected_keys.items() if key not in existing_keys
73
            ]
74
            if add_urls:
×
75
                changes["see_also"] = {"add": add_urls}
×
UNCOV
76
                data[bug_id]["added"] = add_urls
×
77

78
        if changes:
×
79
            self.autofix_changes[bug_id] = changes
×
UNCOV
80
            return bug
×
81

UNCOV
82
        return None
×
83

84
    def get_bz_params(self, date) -> dict[str, str | int | list[str] | list[int]]:
×
85
        fields = ["id", "url", "see_also"]
×
86
        self.feature_bugs = self.get_feature_bugs()
×
87
        return {"include_fields": fields, "id": list(self.feature_bugs.keys())}
×
88

89
    def get_feature_bugs(self) -> Mapping[int, FeatureUrls]:
×
90
        project = "moz-fx-dev-dschubert-wckb"
×
91

92
        client = gcp.get_bigquery_client(project, ["cloud-platform", "drive"])
×
93
        query = f"""
×
94
WITH feature_bugs as (
95
  SELECT
96
    bugs.number,
97
    feature,
98
    bugs.see_also,
99
    web_features.spec as spec_url,
100
    concat("https://web-platform-dx.github.io/web-features-explorer/features/", feature, "/") as feature_url,
101
    concat("https://github.com/mozilla/standards-positions/issues/", sp_mozilla.issue) as sp_url
102
  FROM `{project}.webcompat_knowledge_base.bugzilla_bugs` AS bugs
103
  JOIN `{project}.web_features.features_latest` AS web_features
104
    ON web_features.feature IN UNNEST(`{project}.webcompat_knowledge_base.EXTRACT_ARRAY`(bugs.user_story, "$.web-feature"))
105
  LEFT JOIN `{project}.standards_positions.mozilla_standards_positions` AS sp_mozilla
106
    ON `{project}.webcompat_knowledge_base.BUG_ID_FROM_BUGZILLA_URL`(sp_mozilla.bug) = bugs.number
107
)
108

109
SELECT number, feature, spec_url, feature_url, sp_url FROM feature_bugs
110
WHERE
111
  NOT EXISTS(SELECT 1 FROM feature_bugs.spec_url WHERE spec_url NOT IN UNNEST(see_also))
112
  OR feature_url NOT IN UNNEST(see_also)
113
  OR sp_url NOT IN UNNEST(see_also)
114
"""
115

116
        return {
×
117
            row["number"]: FeatureUrls(
118
                feature=row["feature"],
119
                spec_url=row["spec_url"],
120
                feature_url=row["feature_url"],
121
                sp_url=row["sp_url"],
122
            )
123
            for row in client.query(query).result()
124
        }
125

126

127
if __name__ == "__main__":
×
128
    WebPlatformFeatures().run()
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc