bot/code_review_bot/tasks/tgdiff.py (74 lines of code) (raw):
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
import os
from urllib.parse import unquote
import structlog
from code_review_bot import taskcluster as tc_config
from code_review_bot.tasks.base import NoticeTask
logger = structlog.get_logger(__name__)
SUMMARY_ARTIFACT_PATH = "public/taskgraph/diffs/summary.json"
COMMENT_TASKGRAPH_DIFF = """
NOTE: Tasks were added or removed in diff {diff_id}.
The following parameter set{s} {have} differences:
* {markdown_links}
"""
class TaskGraphDiffTask(NoticeTask):
"""
Notify when CI task configuration has changed.
"""
artifact_urls = {} # map of artifact name to url
@property
def display_name(self):
return "taskgraph-diff"
def load_artifacts(self, queue_service):
# Process only the supported final states
# as some tasks do not always have relevant output
if self.state in self.skipped_states:
logger.info("Skipping task", state=self.state, id=self.id, name=self.name)
return
elif self.state not in self.valid_states:
logger.warning(
"Invalid task state", state=self.state, id=self.id, name=self.name
)
return
logger.info("List artifacts", task_id=self.id)
orig_root_url = queue_service.options["rootUrl"]
summary = None
try:
# Make sure we avoid using the proxy URL.
queue_service.options["rootUrl"] = tc_config.default_url
for a in queue_service.listArtifacts(self.id, self.run_id)["artifacts"]:
if a["name"] == SUMMARY_ARTIFACT_PATH:
summary, _ = self.load_artifact(
queue_service, SUMMARY_ARTIFACT_PATH
)
# We don't want to add the summary.json to the artifact_urls list
continue
if a["name"].startswith("public/taskgraph/diffs/"):
self.artifact_urls[a["name"]] = queue_service.buildUrl(
"getArtifact", self.id, self.run_id, a["name"]
)
except Exception as e:
logger.warn(
"Failed to list artifacts",
task_id=self.id,
run_id=self.run_id,
error=e,
)
return
finally:
queue_service.options["rootUrl"] = orig_root_url
logger.info("Parsing the summary.json artifact if it exists", task_id=self.id)
if summary is None:
logger.warn("Missing summary.json")
elif "status" in summary and summary["status"] == "WARNING":
logger.info(
"TaskGraphDiff summary status is in WARNING, the #taskgraph-reviewers group will be added to the revision"
)
self.extra_reviewers_groups.append("taskgraph-reviewers")
# We don't actually want the contents of these artifacts, just their
# urls (which are now stored in `self.artifact_urls`).
return {}
def build_notice(self, _, revision):
if not self.artifact_urls:
return ""
urls = [unquote(url) for url in self.artifact_urls.values()]
mdlinks = []
for url in urls:
name = url.rsplit("/", 1)[-1]
name = os.path.splitext(name)[0]
if name.startswith("diff_"):
name = name[len("diff_") :]
mdlinks.append(f"[{name}]({url})")
mdlinks = "\n * ".join(mdlinks)
return COMMENT_TASKGRAPH_DIFF.format(
diff_id=revision.diff_id,
s="s" if len(urls) > 1 else "",
have="have" if len(urls) > 1 else "has",
markdown_links=mdlinks,
)