Skip to content
26 changes: 23 additions & 3 deletions bot/code_review_bot/analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,25 @@ def publish_analysis_phabricator(payload, phabricator_api):
build.target_phid, BuildState.Fail, unit=[failure]
)

elif mode == "fail:git":
extra_content = ""
if build.missing_base_revision:
extra_content = f" because the parent revision ({build.base_revision}) does not exist on the target repository. If possible, you should publish that revision"

failure = UnitResult(
namespace="code-review",
name="git",
result=UnitResultState.Fail,
details="WARNING: The code review bot failed to apply your patch{}.\n\n```{}```".format(
extra_content, extras["message"]
),
format="remarkup",
duration=extras.get("duration", 0),
)
phabricator_api.update_build_target(
build.target_phid, BuildState.Fail, unit=[failure]
)

elif mode == "test_result":
result = UnitResult(
namespace="code-review",
Expand Down Expand Up @@ -192,10 +211,11 @@ def publish_analysis_lando(payload, lando_warnings):
except Exception as ex:
logger.error(str(ex), exc_info=True)

elif mode == "fail:mercurial":
# Send mercurial message to Lando
elif mode in ("fail:mercurial", "fail:git"):
# Send patch application failure message to Lando
logger.info(
"Publishing code review hg failure.",
"Publishing code review VCS failure.",
mode=mode,
revision=build.revision["id"],
diff=build.diff_id,
)
Expand Down
12 changes: 12 additions & 0 deletions bot/code_review_bot/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ def parse_cli():
help="Taskcluster Secret path",
default=os.environ.get("TASKCLUSTER_SECRET"),
)
parser.add_argument(
"--git-ssh-key-secret",
help="Taskcluster secret holding the SSH deploy key used to push to Git try repositories",
default=os.environ.get("GIT_SSH_KEY_SECRET"),
)
parser.add_argument(
"--mercurial-repository",
help="Optional path to a up-to-date mercurial repository matching the analyzed revision.\n"
Expand Down Expand Up @@ -116,6 +121,12 @@ def main():
# Setup libmozdata configuration
setup_libmozdata("code-review-bot")

# Load the dedicated Git deploy key from its own secret when configured
git_ssh_key = None
if args.git_ssh_key_secret:
secret = taskcluster.get_service("secrets").get(args.git_ssh_key_secret)
git_ssh_key = secret["secret"]["ssh_privkey"]

# Setup settings before stats
settings.setup(
taskcluster.secrets["APP_CHANNEL"],
Expand All @@ -124,6 +135,7 @@ def main():
taskcluster.secrets["ssh_key"],
args.mercurial_repository,
args.github_repository,
git_ssh_key=git_ssh_key,
)

# Setup statistics
Expand Down
28 changes: 21 additions & 7 deletions bot/code_review_bot/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@
)
RepositoryConf = collections.namedtuple(
"RepositoryConf",
"name, try_name, url, try_url, decision_env_prefix, ssh_user",
"name, try_name, url, try_url, decision_env_prefix, ssh_user, repo_type",
# repo_type is optional and defaults to Mercurial so existing repository
# secrets keep working; set it to "git" to push to a Git remote instead.
defaults=("hg",),
)


Expand Down Expand Up @@ -63,6 +66,9 @@ def __init__(self):
# SSH Key used to push on try
self.ssh_key = None

# SSH deploy key used to push on Git try repositories
self.git_ssh_key = None

# List of users that should trigger a new analysis
# Indexed by their Phabricator ID
self.user_blacklist = {}
Expand All @@ -80,6 +86,7 @@ def setup(
ssh_key=None,
mercurial_cache=None,
git_cache=None,
git_ssh_key=None,
):
# Detect source from env
if "TRY_TASK_ID" in os.environ and "TRY_TASK_GROUP_ID" in os.environ:
Expand Down Expand Up @@ -123,13 +130,18 @@ def build_conf(nb, repo):
assert isinstance(
repo, dict
), "Repository configuration #{nb+1} is not a dict"
data = []
data = {}
for key in RepositoryConf._fields:
assert (
key in repo
), f"Missing key {key} in repository configuration #{nb+1}"
data.append(repo[key])
return RepositoryConf._make(data)
if key in repo:
data[key] = repo[key]
elif key in RepositoryConf._field_defaults:
# Optional field, fall back to its default (e.g. repo_type)
data[key] = RepositoryConf._field_defaults[key]
else:
raise AssertionError(
f"Missing key {key} in repository configuration #{nb+1}"
)
return RepositoryConf(**data)

self.repositories = [build_conf(i, repo) for i, repo in enumerate(repositories)]
assert self.repositories, "No repositories available"
Expand Down Expand Up @@ -161,6 +173,8 @@ def build_conf(nb, repo):
# Fallback to mercurial cache to ease migration on production systems
self.git_cache = self.mercurial_cache

self.git_ssh_key = git_ssh_key

def load_user_blacklist(self, usernames, phabricator_api):
"""
Load all black listed users from Phabricator API
Expand Down
Loading