Skip to content

Commit

Permalink
ui: port revisions page and supporting functionality (bug 1876838)
Browse files Browse the repository at this point in the history
  • Loading branch information
zzzeid committed Jun 28, 2024
1 parent b6cf49a commit 2b60be5
Show file tree
Hide file tree
Showing 39 changed files with 490 additions and 511 deletions.
6 changes: 2 additions & 4 deletions src/lando/api/legacy/api/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
# 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/.
from lando.api.legacy.api import stacks, transplants


def get():
"""Return a redirect repsonse to the swagger specification."""
return None, 302, {"Location": "/swagger.json"}
__all__ = ["stacks", "transplants"]
10 changes: 5 additions & 5 deletions src/lando/api/legacy/api/landing_jobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,13 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
import logging

from lando.api.legacy import auth
from lando.main.models.landing_job import LandingJob, LandingJobAction, LandingJobStatus
from lando.main.support import ProblemException, g
from lando.main.support import ProblemException

logger = logging.getLogger(__name__)


@auth.require_auth0(scopes=("lando", "profile", "email"), userinfo=True)
def put(landing_job_id: str, data: dict):
def put(request, landing_job_id: str, data: dict):
"""Update a landing job.
Checks whether the logged in user is allowed to modify the landing job that is
Expand All @@ -29,6 +27,8 @@ def put(landing_job_id: str, data: dict):
updated (for example, when trying to cancel a job that is already in
progress).
"""
if not request.user.is_authenticated:
raise PermissionError
with LandingJob.lock_table:
landing_job = LandingJob.objects.get(pk=landing_job_id)

Expand All @@ -40,7 +40,7 @@ def put(landing_job_id: str, data: dict):
type="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404",
)

ldap_username = g.auth0_user.email
ldap_username = request.user.email
if landing_job.requester_email != ldap_username:
raise ProblemException(
403,
Expand Down
16 changes: 5 additions & 11 deletions src/lando/api/legacy/api/stacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import urllib.parse

from django.conf import settings
from django.http import Http404

from lando.api.legacy.commit_message import format_commit_message
from lando.api.legacy.decorators import require_phabricator_api_key
Expand Down Expand Up @@ -41,39 +42,32 @@
from lando.api.legacy.users import user_search
from lando.api.legacy.validation import revision_id_to_int
from lando.main.models.revision import Revision
from lando.main.support import problem

logger = logging.getLogger(__name__)

not_found_problem = problem(
404,
"Revision not found",
"The requested revision does not exist",
type="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404",
)


@require_phabricator_api_key(optional=True)
def get(phab: PhabricatorClient, revision_id: str):
def get(phab: PhabricatorClient, request, revision_id: str):
"""Get the stack a revision is part of.
Args:
revision_id: (string) ID of the revision in 'D{number}' format
"""
revision_id = f"D{revision_id}"
revision_id_int = revision_id_to_int(revision_id)

revision = phab.call_conduit(
"differential.revision.search", constraints={"ids": [revision_id_int]}
)
revision = phab.single(revision, "data", none_when_empty=True)
if revision is None:
return not_found_problem
raise Http404

nodes, edges = build_stack_graph(revision)
try:
stack_data = request_extended_revision_data(phab, list(nodes))
except ValueError:
return not_found_problem
raise Http404

supported_repos = get_repos_for_env(settings.ENVIRONMENT)
landable_repos = get_landable_repos_for_revision_data(stack_data, supported_repos)
Expand Down
43 changes: 28 additions & 15 deletions src/lando/api/legacy/api/transplants.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@

import kombu
from django.conf import settings
from django.contrib.auth.models import User
from django.core.exceptions import PermissionDenied

from lando.api.legacy import auth
from lando.api.legacy.commit_message import format_commit_message
from lando.api.legacy.decorators import require_phabricator_api_key
from lando.api.legacy.phabricator import PhabricatorClient
Expand Down Expand Up @@ -65,7 +66,7 @@
add_revisions_to_job,
)
from lando.main.models.revision import Revision
from lando.main.support import ProblemException, g, problem
from lando.main.support import ProblemException, problem
from lando.utils.tasks import admin_remove_phab_project

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -133,7 +134,10 @@ def _find_stack_from_landing_path(


def _assess_transplant_request(
phab: PhabricatorClient, landing_path: list[tuple[int, int]], relman_group_phid: str
lando_user: User,
phab: PhabricatorClient,
landing_path: list[tuple[int, int]],
relman_group_phid: str,
) -> tuple[
TransplantAssessment,
Optional[list[tuple[dict, dict]]],
Expand All @@ -158,7 +162,7 @@ def _assess_transplant_request(
)

assessment = check_landing_blockers(
g.auth0_user, landing_path_phid, stack_data, landable, landable_repos
lando_user, landing_path_phid, stack_data, landable, landable_repos
)
if assessment.blocker is not None:
return (assessment, None, None, None)
Expand Down Expand Up @@ -195,7 +199,7 @@ def _assess_transplant_request(

assessment = check_landing_warnings(
phab,
g.auth0_user,
lando_user,
to_land,
repo,
landing_repo,
Expand All @@ -209,24 +213,31 @@ def _assess_transplant_request(
return (assessment, to_land, landing_repo, stack_data)


# TODO: auth stuff
@auth.require_auth0(scopes=("lando", "profile", "email"), userinfo=True)
@require_phabricator_api_key(optional=True)
def dryrun(phab: PhabricatorClient, data: dict):
def dryrun(phab: PhabricatorClient, request, data: dict):
lando_user = request.user
if not lando_user.is_authenticated:
raise PermissionDenied

landing_path = _parse_transplant_request(data)["landing_path"]

release_managers = get_release_managers(phab)
if not release_managers:
raise Exception("Could not find `#release-managers` project on Phabricator.")

relman_group_phid = phab.expect(release_managers, "phid")
assessment, *_ = _assess_transplant_request(phab, landing_path, relman_group_phid)
assessment, *_ = _assess_transplant_request(
lando_user, phab, landing_path, relman_group_phid
)
return assessment.to_dict()


@auth.require_auth0(scopes=("lando", "profile", "email"), userinfo=True)
@require_phabricator_api_key(optional=True)
def post(phab: PhabricatorClient, data: dict):
def post(phab: PhabricatorClient, request, data: dict):
lando_user = request.user
if not lando_user.is_authenticated:
raise PermissionDenied

parsed_transplant_request = _parse_transplant_request(data)
confirmation_token = parsed_transplant_request["confirmation_token"]
flags = parsed_transplant_request["flags"]
Expand All @@ -248,7 +259,7 @@ def post(phab: PhabricatorClient, data: dict):
relman_group_phid = phab.expect(release_managers, "phid")

assessment, to_land, landing_repo, stack_data = _assess_transplant_request(
phab, landing_path, relman_group_phid
lando_user, phab, landing_path, relman_group_phid
)

assessment.raise_if_blocked_or_unacknowledged(confirmation_token)
Expand Down Expand Up @@ -353,6 +364,7 @@ def post(phab: PhabricatorClient, data: dict):
lando_revision = Revision.get_from_revision_id(revision_id)
if not lando_revision:
lando_revision = Revision(revision_id=revision_id)

lando_revision.diff_id = diff_id
lando_revision.save()

Expand All @@ -373,7 +385,7 @@ def post(phab: PhabricatorClient, data: dict):
lando_revision.save()
lando_revisions.append(lando_revision)

ldap_username = g.auth0_user.email
ldap_username = lando_user.email

submitted_assessment = TransplantAssessment(
blocker=(
Expand All @@ -399,6 +411,7 @@ def post(phab: PhabricatorClient, data: dict):
repository_url=landing_repo.url,
)
job.save()

add_revisions_to_job(lando_revisions, job)
logger.info(f"Setting {revision_reviewers} reviewer data on each revision.")
for revision in lando_revisions:
Expand Down Expand Up @@ -429,7 +442,7 @@ def post(phab: PhabricatorClient, data: dict):


@require_phabricator_api_key(optional=True)
def get_list(phab: PhabricatorClient, stack_revision_id: str):
def get_list(phab: PhabricatorClient, request, stack_revision_id: str):
"""Return a list of Transplant objects"""
revision_id_int = revision_id_to_int(stack_revision_id)

Expand All @@ -456,4 +469,4 @@ def get_list(phab: PhabricatorClient, stack_revision_id: str):

landing_jobs = LandingJob.revisions_query(rev_ids).all()

return [job.serialize() for job in landing_jobs], 200
return [job.serialize() for job in landing_jobs]
4 changes: 0 additions & 4 deletions src/lando/api/legacy/cache.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
# 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/.

from __future__ import annotations

import logging
Expand Down
35 changes: 15 additions & 20 deletions src/lando/api/legacy/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
)

from django.conf import settings
from django.http import HttpResponse

from lando.api.legacy.phabricator import PhabricatorClient
from lando.main.support import problem, request


class require_phabricator_api_key:
Expand All @@ -36,35 +36,30 @@ def __init__(self, optional: bool = False, provide_client: bool = True):

def __call__(self, f: Callable) -> Callable:
@functools.wraps(f)
def wrapped(*args, **kwargs):
api_key = request["headers"].get("X-Phabricator-API-Key")
def wrapped(request, *args, **kwargs):
user = request.user
if (
user.is_authenticated
and hasattr(user, "profile")
and user.profile.phabricator_api_key
):
api_key = user.profile.phabricator_api_key
else:
api_key = None

if api_key is None and not self.optional:
return problem(
401,
"X-Phabricator-API-Key Required",
(
"Phabricator api key not provided in "
"X-Phabricator-API-Key header"
),
type="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/401",
)
return HttpResponse("Phabricator API key is required", status=401)

phab = PhabricatorClient(
settings.PHABRICATOR_URL,
api_key or settings.PHABRICATOR_UNPRIVILEGED_API_KEY,
)
if api_key is not None and not phab.verify_api_token():
return problem(
403,
"X-Phabricator-API-Key Invalid",
"Phabricator api key is not valid",
type="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/403",
)
return HttpResponse("Phabricator API key is invalid", status=403)

if self.provide_client:
return f(phab, *args, **kwargs)
return f(phab, request, *args, **kwargs)
else:
return f(*args, **kwargs)
return f(request, *args, **kwargs)

return wrapped
11 changes: 11 additions & 0 deletions src/lando/api/legacy/repos.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
AccessGroup = namedtuple(
"AccessGroup",
(
# Django permission equivalent to having the right group membership.
"permission",
# LDAP group for active members. Required for landing.
"active_group",
# LDAP group for expired members. Indicates the user had the
Expand Down Expand Up @@ -110,54 +112,63 @@ def phab_identifier(self) -> str | None:


SCM_ALLOW_DIRECT_PUSH = AccessGroup(
permission="scm_allow_direct_push",
active_group="active_scm_allow_direct_push",
expired_group="expired_scm_allow_direct_push",
membership_group="all_scm_allow_direct_push",
display_name="Above Level 3 Commit Access",
)
SCM_LEVEL_3 = AccessGroup(
permission="scm_level_3",
active_group="active_scm_level_3",
expired_group="expired_scm_level_3",
membership_group="all_scm_level_3",
display_name="Level 3 Commit Access",
)
SCM_LEVEL_2 = AccessGroup(
permission="scm_level_2",
active_group="active_scm_level_2",
expired_group="expired_scm_level_2",
membership_group="all_scm_level_2",
display_name="Level 2 Commit Access",
)
SCM_LEVEL_1 = AccessGroup(
permission="scm_level_1",
active_group="active_scm_level_1",
expired_group="expired_scm_level_1",
membership_group="all_scm_level_1",
display_name="Level 1 Commit Access",
)
SCM_VERSIONCONTROL = AccessGroup(
permission="scm_versioncontrol",
active_group="active_scm_versioncontrol",
expired_group="expired_scm_versioncontrol",
membership_group="all_scm_versioncontrol",
display_name="scm_versioncontrol",
)
SCM_CONDUIT = AccessGroup(
permission="scm_conduit",
active_group="active_scm_conduit",
expired_group="expired_scm_conduit",
membership_group="all_scm_conduit",
display_name="scm_conduit",
)
SCM_L10N_INFRA = AccessGroup(
permission="scm_l10n_infra",
active_group="active_scm_l10n_infra",
expired_group="expired_scm_l10n_infra",
membership_group="all_scm_l10n_infra",
display_name="scm_l10n_infra",
)
SCM_NSS = AccessGroup(
permission="scm_nss",
active_group="active_scm_nss",
expired_group="expired_scm_nss",
membership_group="all_scm_nss",
display_name="scm_nss",
)
SCM_FIREFOXCI = AccessGroup(
permission="scm_firefoxci",
active_group="active_scm_firefoxci",
expired_group="expired_scm_firefoxci",
membership_group="all_scm_firefoxci",
Expand Down
3 changes: 0 additions & 3 deletions src/lando/api/legacy/revisions.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
# 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 logging
from collections import Counter
from typing import (
Expand Down
Loading

0 comments on commit 2b60be5

Please sign in to comment.