diff --git a/src/lando/api/legacy/api/__init__.py b/src/lando/api/legacy/api/__init__.py
index 7f92ea5b..37229788 100644
--- a/src/lando/api/legacy/api/__init__.py
+++ b/src/lando/api/legacy/api/__init__.py
@@ -1,3 +1,3 @@
-from lando.api.legacy.api import stacks, transplants
+from lando.api.legacy.api import stacks, transplants, uplift
-__all__ = ["stacks", "transplants"]
+__all__ = ["stacks", "transplants", "uplift"]
diff --git a/src/lando/api/legacy/api/uplift.py b/src/lando/api/legacy/api/uplift.py
index 1f94def0..dc9dc697 100644
--- a/src/lando/api/legacy/api/uplift.py
+++ b/src/lando/api/legacy/api/uplift.py
@@ -1,57 +1,28 @@
import logging
+from django.http import Http404
+
+from lando.api.legacy.api.stacks import HTTP_404_STRING
from lando.api.legacy.uplift import (
create_uplift_revision,
get_local_uplift_repo,
get_uplift_conduit_state,
- get_uplift_repositories,
)
from lando.api.legacy.validation import revision_id_to_int
from lando.main.auth import require_authenticated_user, require_phabricator_api_key
-from lando.main.models import Repo
-from lando.main.support import problem
from lando.utils.phabricator import PhabricatorClient
logger = logging.getLogger(__name__)
-@require_phabricator_api_key(optional=True)
-def get(phab: PhabricatorClient):
- """Return the list of valid uplift repositories."""
- repos = [
- phab.expect(repo, "fields", "shortName")
- for repo in get_uplift_repositories(phab)
- ]
-
- return {"repos": repos}, 201
-
-
-@require_phabricator_api_key(optional=False)
@require_authenticated_user
-def create(phab: PhabricatorClient, data: dict):
+@require_phabricator_api_key(optional=False)
+def create(phab: PhabricatorClient, request, data: dict):
"""Create new uplift requests for requested repository & revision"""
- repo_name = data["repository"]
+ repository = data["repository"]
+ repo_name = repository.name
revision_id = revision_id_to_int(data["revision_id"])
- # Validate repository.
- all_repos = Repo.get_mapping()
- repository = all_repos.get(repo_name)
- if repository is None:
- return problem(
- 400,
- f"Repository {repo_name} is not a repository known to Lando.",
- "Please select an uplift repository to create the uplift request.",
- type="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/400",
- )
-
- if not repository.approval_required:
- return problem(
- 400,
- f"Repository {repo_name} is not an uplift repository.",
- "Please select an uplift repository to create the uplift request.",
- type="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/400",
- )
-
try:
logger.info(
"Checking approval state",
@@ -72,12 +43,7 @@ def create(phab: PhabricatorClient, data: dict):
"Hit an error retreiving uplift state from conduit.",
extra={"error": str(err)},
)
- return problem(
- 404,
- "Revision not found",
- err.args[0],
- type="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404",
- )
+ raise Http404(HTTP_404_STRING)
revision_phid = next(
rev["phid"]
@@ -138,4 +104,4 @@ def create(phab: PhabricatorClient, data: dict):
output = {rev["revision_phid"]: rev for rev in commit_stack}
output["tip_differential"] = commit_stack[-1]
- return output, 201
+ return output
diff --git a/src/lando/api/legacy/uplift.py b/src/lando/api/legacy/uplift.py
index 3d75b78c..a68c7f3e 100644
--- a/src/lando/api/legacy/uplift.py
+++ b/src/lando/api/legacy/uplift.py
@@ -22,7 +22,7 @@
request_extended_revision_data,
)
from lando.main.models import Repo
-from lando.utils.phabricator import PhabricatorClient
+from lando.utils.phabricator import PhabricatorClient, get_phabricator_client
logger = logging.getLogger(__name__)
@@ -59,18 +59,16 @@ def get_uplift_request_form(revision: dict) -> Optional[str]:
return bug
-# @cache.cached(
-# key_prefix="uplift-repositories"
-# )
-def get_uplift_repositories(phab: PhabricatorClient) -> list:
+def get_uplift_repositories() -> list:
+ # TODO: cache
+ phab = get_phabricator_client()
repos = phab.call_conduit(
"diffusion.repository.search",
constraints={"projects": ["uplift"]},
)
repos = phab.expect(repos, "data")
-
- return repos
+ return [phab.expect(repo, "fields", "shortName") for repo in repos]
def get_revisions_without_bugs(phab: PhabricatorClient, revisions: dict) -> set[str]:
diff --git a/src/lando/ui/jinja2/stack/stack.html b/src/lando/ui/jinja2/stack/stack.html
index 076b638d..b61474da 100644
--- a/src/lando/ui/jinja2/stack/stack.html
+++ b/src/lando/ui/jinja2/stack/stack.html
@@ -129,7 +129,7 @@
Landing is blocked:
{% include "stack/partials/landing-preview.html" %}
diff --git a/src/lando/ui/legacy/forms.py b/src/lando/ui/legacy/forms.py
index 5b9a2290..14c0fb43 100644
--- a/src/lando/ui/legacy/forms.py
+++ b/src/lando/ui/legacy/forms.py
@@ -1,5 +1,8 @@
from django import forms
+from lando.api.legacy.uplift import get_uplift_repositories
+from lando.main.models import Repo
+
class TransplantRequestForm(forms.Form):
landing_path = forms.JSONField(widget=forms.widgets.HiddenInput)
@@ -12,8 +15,32 @@ class TransplantRequestForm(forms.Form):
class UpliftRequestForm(forms.Form):
"""Form used to request uplift of a stack."""
- revision_id = forms.RegexField(regex="D[0-9]+$")
- repository = forms.CharField()
+ revision_id = forms.RegexField(
+ regex="D[0-9]+$",
+ widget=forms.widgets.HiddenInput,
+ required=False,
+ )
+ repository = forms.ChoiceField(
+ widget=forms.Select(),
+ choices=((repo, repo) for repo in get_uplift_repositories()),
+ )
+
+ def clean_repository(self):
+ repo_name = self.cleaned_data["repository"]
+ all_repos = Repo.get_mapping()
+ repository = all_repos.get(repo_name)
+ if repository is None:
+ raise forms.ValidationError(
+ f"Repository {repo_name} is not a repository known to Lando. "
+ "Please select an uplift repository to create the uplift request."
+ )
+
+ if not repository.approval_required:
+ raise forms.ValidationError(
+ f"Repository {repo_name} is not an uplift repository. "
+ "Please select an uplift repository to create the uplift request."
+ )
+ return repository
class UserSettingsForm(forms.Form):
diff --git a/src/lando/ui/legacy/revisions.py b/src/lando/ui/legacy/revisions.py
index 24bf248a..40f94a92 100644
--- a/src/lando/ui/legacy/revisions.py
+++ b/src/lando/ui/legacy/revisions.py
@@ -10,7 +10,7 @@
from lando.main.auth import force_auth_refresh
from lando.ui.legacy.forms import (
TransplantRequestForm,
- # UpliftRequestForm,
+ UpliftRequestForm,
)
from lando.ui.legacy.stacks import Edge, draw_stack_graph, sort_stack_topological
from lando.ui.views import LandoView
@@ -21,6 +21,49 @@
# revisions.before_request(set_last_local_referrer)
+class Uplift(LandoView):
+ @force_auth_refresh
+ def post(self, request):
+ """Process the uplift request submission."""
+ uplift_request_form = UpliftRequestForm(request.POST)
+ errors = []
+
+ if not request.user.is_authenticated:
+ raise PermissionError()
+
+ if uplift_request_form.is_valid() and not errors:
+ revision_id = uplift_request_form.cleaned_data["revision_id"]
+ repository = uplift_request_form.cleaned_data["repository"]
+
+ response = legacy_api.uplift.create(
+ request,
+ data={
+ "revision_id": revision_id,
+ "repository": repository,
+ },
+ )
+
+ # Redirect to the tip revision's URL.
+ # TODO add js for auto-opening the uplift request Phabricator form.
+ # See https://bugzilla.mozilla.org/show_bug.cgi?id=1810257.
+ revision_id = response["tip_differential"]["revision_id"]
+ return redirect("revisions-page", revision_id=revision_id)
+
+ if uplift_request_form.errors:
+ errors += [
+ f"{field}: {', '.join(field_errors)}"
+ for field, field_errors in uplift_request_form.errors.items()
+ ]
+
+ for error in errors:
+ messages.add_message(request, messages.ERROR, error)
+
+ # Not ideal, but because we do not have access to the revision ID
+ # we will just redirect the user back to the referring page and
+ # they will see the flash messages.
+ return redirect(request.META.get("HTTP_REFERER"))
+
+
class Revision(LandoView):
def get(
self, request: HttpRequest, revision_id: int, *args, **kwargs
@@ -33,13 +76,8 @@ def get(
form = TransplantRequestForm()
errors = []
- # TODO - see bug 1915695.
- # uplift_request_form = UpliftRequestForm()
-
- # # Get the list of available uplift repos and populate the form with it.
- # uplift_request_form.repository.choices = get_uplift_repos(api)
- # uplift_request_form.revision_id.data = revision_id
- # END TODO.
+ uplift_request_form = UpliftRequestForm()
+ uplift_request_form.fields["revision_id"].initial = f"D{revision_id}"
# Build a mapping from phid to revision and identify
# the data for the revision used to load this page.
@@ -136,7 +174,7 @@ def get(
"form": form,
"flags": target_repo["commit_flags"] if target_repo else [],
"existing_flags": existing_flags,
- # "uplift_request_form": uplift_request_form,
+ "uplift_request_form": uplift_request_form,
}
return TemplateResponse(
@@ -152,14 +190,6 @@ def post(
form = TransplantRequestForm(request.POST)
errors = []
- # TODO - see bug 1915695.
- # uplift_request_form = UpliftRequestForm()
-
- # # Get the list of available uplift repos and populate the form with it.
- # uplift_request_form.repository.choices = get_uplift_repos(api)
- # uplift_request_form.revision_id.data = revision_id
- # END TODO.
-
if not request.user.is_authenticated:
errors.append("You must be logged in to request a landing")
diff --git a/src/lando/urls.py b/src/lando/urls.py
index d6c63b26..c3ec932d 100644
--- a/src/lando/urls.py
+++ b/src/lando/urls.py
@@ -31,6 +31,7 @@
path("", pages.Index.as_view()),
path("D/", revisions.Revision.as_view(), name="revisions-page"),
path("manage_api_key/", user_settings.manage_api_key, name="user-settings"),
+ path("uplift/", revisions.Uplift.as_view(), name="uplift-page"),
]
# "API" endpoints ported from legacy API app.