Skip to content

Commit 6c48e2b

Browse files
committed
api.views: add try push handover functionality (bug 2002566)
- add functionality that adds try_task_config.json file - update landing worker to process handover jobs - add PullRequestTryLintAPIView - add LandingJob.handover_repo field and migrations - add Repo.is_try helper method
1 parent 8a0723b commit 6c48e2b

File tree

6 files changed

+120
-0
lines changed

6 files changed

+120
-0
lines changed

src/lando/api/legacy/workers/landing_worker.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import configparser
2+
import json
23
import logging
34
import subprocess
45
from pathlib import Path
@@ -168,6 +169,19 @@ def run_job(self, job: LandingJob) -> bool:
168169

169170
return True
170171

172+
def add_try_task_config(self, scm: AbstractSCM):
173+
with (Path(scm.path) / "try_task_config.json").open("x") as f:
174+
content = json.dumps(
175+
{
176+
"parameters": {
177+
"optimize_target_tasks": True,
178+
"target_tasks_method": "codereview",
179+
},
180+
"version": 2,
181+
}
182+
)
183+
f.write(content)
184+
171185
def convert_patches_to_diff(self, scm: AbstractSCM, job: LandingJob):
172186
"""Generate a unified diff from multiple patches stored in a revision."""
173187
# NOTE: this only applies to git patches that are downloaded from GitHub
@@ -215,10 +229,31 @@ def apply_patch(revision: Revision):
215229

216230
self.update_repo(repo, job, scm, job.target_commit_hash)
217231

232+
if job.is_pull_request_job and job.handover_repo and job.handover_repo.is_try:
233+
self.add_try_task_config(scm)
234+
self.convert_patches_to_diff(scm, job)
235+
job.target_repo = job.handover_repo
236+
job.handover_repo = None
237+
job.save()
238+
job.revisions.update(pull_number=None)
239+
message = "Job deferred to try repo."
240+
job.transition_status(JobAction.DEFER, message=message)
241+
raise TemporaryFailureException(message)
242+
218243
if job.is_pull_request_job:
244+
if job.handover_repo and job.handover_repo.is_try:
245+
self.add_try_task_config(scm)
219246
self.convert_patches_to_diff(scm, job)
220247
self.update_repo(repo, job, scm, job.target_commit_hash)
221248

249+
try:
250+
try_repo = Repo.objects.get(name="try")
251+
except Repo.DoesNotExist:
252+
pass
253+
else:
254+
if job.target_repo == try_repo:
255+
self.add_try_task_config(job)
256+
222257
# Run through the patches one by one and try to apply them.
223258
logger.debug(
224259
f"About to land {job.revisions.count()} revisions: {job.revisions.all()} ..."

src/lando/api/views.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,3 +287,42 @@ def get(self, request: WSGIRequest, repo_name: str, number: int) -> JsonResponse
287287
target_repo, pull_request, request
288288
)
289289
return JsonResponse(warnings_and_blockers)
290+
291+
292+
class PullRequestTryLintAPIView(APIView):
293+
@method_decorator(require_authenticated_user)
294+
def post(
295+
self, request: WSGIRequest, repo_name: str, pull_number: int
296+
) -> JsonResponse:
297+
try:
298+
try_repo = Repo.objects.get(name="try")
299+
except Repo.DoesNotExist:
300+
return JsonResponse({"errors": ["Try repo does not exist"]}, 500)
301+
302+
target_repo = Repo.objects.get(name=repo_name)
303+
client = GitHubAPIClient(target_repo.url)
304+
ldap_username = request.user.email
305+
pull_request = client.build_pull_request(pull_number)
306+
307+
job = LandingJob.objects.create(
308+
target_repo=target_repo,
309+
handover_repo=try_repo,
310+
requester_email=ldap_username,
311+
)
312+
author_name, author_email = pull_request.author
313+
patch_data = {
314+
"author_name": author_name,
315+
"author_email": author_email,
316+
"commit_message": pull_request.commit_message,
317+
"timestamp": int(datetime.now().timestamp()),
318+
}
319+
revision = Revision.objects.create(
320+
pull_number=pull_request.number,
321+
patches=pull_request.patch,
322+
patch_data=patch_data,
323+
)
324+
add_revisions_to_job([revision], job)
325+
job.status = JobStatus.SUBMITTED
326+
job.save()
327+
328+
return JsonResponse({"id": job.id}, status=201)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Generated by Django 5.2.8 on 2025-12-05 19:40
2+
3+
import django.db.models.deletion
4+
from django.db import migrations, models
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
("main", "0037_repo_pr_enabled"),
11+
]
12+
13+
operations = [
14+
migrations.AddField(
15+
model_name="landingjob",
16+
name="handover_repo",
17+
field=models.ForeignKey(
18+
blank=True,
19+
null=True,
20+
on_delete=django.db.models.deletion.SET_NULL,
21+
related_name="handover_jobs",
22+
to="main.repo",
23+
),
24+
),
25+
]

src/lando/main/models/landing_job.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,17 @@ class LandingJob(BaseJob):
4646
Revision, through="RevisionLandingJob", related_name="landing_jobs"
4747
)
4848

49+
# Reference to the handover repo. A handover repo is a repo that a landing
50+
# job is handed over to after being processed in a previous state. If this value
51+
# is set, the job will be processed twice, but pushed once.
52+
handover_repo = models.ForeignKey(
53+
Repo,
54+
on_delete=models.SET_NULL,
55+
null=True,
56+
blank=True,
57+
related_name="handover_jobs",
58+
)
59+
4960
@property
5061
def is_pull_request_job(self) -> bool:
5162
"""Return True if all revisions in the landing job have a pull_number set."""

src/lando/main/models/repo.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,10 @@ class HooksChoices(models.TextChoices):
9797
def path(self) -> str:
9898
return str(self.system_path) or self.get_system_path()
9999

100+
@property
101+
def is_try(self) -> bool:
102+
return self.name == "try"
103+
100104
# TODO: help text for fields below.
101105
name = models.CharField(max_length=255, unique=True)
102106
default_branch = models.CharField(max_length=255, default="", blank=True)

src/lando/urls.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
LandingJobPullRequestAPIView,
2424
LegacyDiffWarningView,
2525
PullRequestChecksAPIView,
26+
PullRequestTryLintAPIView,
2627
git2hgCommitMapView,
2728
hg2gitCommitMapView,
2829
)
@@ -103,6 +104,11 @@
103104
LandingJobPullRequestAPIView.as_view(),
104105
name="api-landing-job-pull-request",
105106
),
107+
path(
108+
"api/pulls/<str:repo_name>/<int:pull_number>/try_jobs",
109+
PullRequestTryLintAPIView.as_view(),
110+
name="api-try-job-pull-request",
111+
),
106112
path(
107113
"api/pulls/<str:repo_name>/<int:number>/checks",
108114
PullRequestChecksAPIView.as_view(),

0 commit comments

Comments
 (0)