Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions src/lando/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -326,3 +326,21 @@ def get(
# The StaleMetadataException error message is safe for user consumption.
return JsonResponse({"errors": [str(exc)]}, status=500)
return JsonResponse(warnings_and_blockers)


class PullRequestContentAPIView(PullRequestAPIView):
def put(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be good to add docstrings to this method and the class.

self, request: WSGIRequest, repo_name: str, pull_number: int
) -> JsonResponse:
class Form(forms.Form):
body = forms.CharField(required=False)
title = forms.CharField(max_length=256)

form = Form(json.loads(request.body))
if not form.is_valid():
return JsonResponse(form.errors, status=400)

result = self.client.update_pull_request_content(
self.pull_request.number, **form.cleaned_data
)
return JsonResponse(result, status=200)
48 changes: 44 additions & 4 deletions src/lando/static_src/legacy/js/components/Stack.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ $.fn.stack = function() {
// This should be cleaned up as part of bug 1995754.
var is_pull_request_page = Boolean($('button.post-landing-job').length);
if (is_pull_request_page) {
var pull_request_button = $('button.post-landing-job');
var pull_request_button = $('button.post-landing-job');

$('#acknowledge-warnings').on("click", function () {
if (this.checked) {
Expand All @@ -81,7 +81,7 @@ $.fn.stack = function() {
pull_request_button.prop("disabled", true);
pull_request_button.html("Acknowledge warnings to continue");
}
});
});

if (pull_request_button.data("anonymous") == 1) {
pull_request_button.prop("disabled", true);
Expand Down Expand Up @@ -198,6 +198,46 @@ $.fn.stack = function() {
}
});
});
};
});

$('button.save-pr').on('click', function(e) {
var body = document.getElementById('commit-body').value;
var title = document.getElementById('commit-title').value;

fetch(`/api/pulls/${repo_name}/${pull_number}`, {
method: 'PUT',
body: JSON.stringify({"body": body, "title": title}),
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'X-CSRFToken': csrf_token
}
}).then(async (response) => {
console.log(response);
if (response.status === 400) {
var result = await response.json();
if (result.title){
document.getElementById("commit-title-error").textContent = result.title;
document.getElementById("commit-title").classList.add("is-danger");
}
if (result.body){ //redundant right now since there isn't any manual checks for the message body
document.getElementById("commit-body-error").textContent = result.body;
document.getElementById("commit-body").classList.add("is-danger");
}
console.error("400:", result);
}
else if (response.status === 200) {
document.getElementById("commit-title-error").textContent = "";
document.getElementById("commit-body-error").textContent = "";
document.getElementById("commit-title").classList.remove("is-danger");
document.getElementById("commit-body").classList.remove("is-danger");
window.location.reload();
}
else{
console.error("error updating pull request:", response);
}
});
});
}
});
};

16 changes: 14 additions & 2 deletions src/lando/ui/jinja2/stack/pull_request.html
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,25 @@ <h1>
</tr>
<tr>
<th>Commit Title</th>
<td>{{ pull_request.title }}</td>
<td>
<textarea contenteditable="true" id="commit-title" class="textarea">{{ pull_request.title }}</textarea>
<p class="help is-danger" id="commit-title-error"></p>
</td>
</tr>
<tr>
<th>Commit Body</th>
<td>{{ pull_request.body }}</td>
<td>
<textarea contenteditable="true" id="commit-body" class="textarea">{{ pull_request.parsed_body }}</textarea>
<p class="help is-danger" id="commit-body-error"></p>
</td>
</tr>
</table>
<p>
<button class="button save-pr"
data-pull-number="{{ pull_request.number }}"
data-repo-name="{{ target_repo.name }}"
data-csrf-token="{{ csrf_token }}">Save Commit Message</button>
</p>
</div>
<h1>Landings</h1>
{% include "stack/partials/timeline.html" %}
Expand Down
6 changes: 6 additions & 0 deletions src/lando/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
LandingJobPullRequestAPIView,
LegacyDiffWarningView,
PullRequestChecksAPIView,
PullRequestContentAPIView,
git2hgCommitMapView,
hg2gitCommitMapView,
)
Expand Down Expand Up @@ -125,6 +126,11 @@
PullRequestChecksAPIView.as_view(),
name="api-pull-request-checks",
),
path(
"api/pulls/<str:repo_name>/<int:pull_number>",
PullRequestContentAPIView.as_view(),
name="api-pull-request-update-content",
),
]

# "API" endpoints ported from legacy API app.
Expand Down
28 changes: 26 additions & 2 deletions src/lando/utils/github.py
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To reduce chances of this PR getting blocked, we can take out the portions in this PR that were borrowed from #1073 and instead just keep the _patch and _patch methods. We can always re-add the delimiter functionality after that PR is more robust.

Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
logger = logging.getLogger(__name__)


SPECIAL_DELIMITER = "-" * 9


class GitHub:
"""Work with authentication to GitHub repositories."""

Expand Down Expand Up @@ -150,6 +153,11 @@ def post(self, path: str, *args, **kwargs) -> requests.Response:
url = f"{self.GITHUB_BASE_URL}/{path}"
return self.session.post(url, *args, **kwargs)

def patch(self, path: str, *args, **kwargs) -> requests.Response:
"""Send a PATCH request to the GitHub API with given args and kwargs."""
url = f"{self.GITHUB_BASE_URL}/{path}"
return self.session.patch(url, *args, **kwargs)


class GitHubAPIClient:
"""A convenience client that provides various methods to interact with the GitHub API."""
Expand Down Expand Up @@ -230,6 +238,10 @@ def _post(self, path: str, *args, **kwargs):
result = self._api.post(path, *args, **kwargs)
return result.json()

def _patch(self, path: str, *args, **kwargs):
result = self._api.patch(path, *args, **kwargs)
return result.json()

def build_pull_request(self, pull_number: int) -> "PullRequest":
"""Build a PullRequest object.

Expand Down Expand Up @@ -370,6 +382,15 @@ def add_comment_to_pull_request(self, pull_number: int, comment: str) -> dict:
json={"body": comment},
)

def update_pull_request_content(
self, pull_number: int, body: str, title: str
) -> dict:
"""Update the pull request description with provided body and title."""
return self._patch(
f"{self.repo_base_url}/issues/{pull_number}",
json={"body": body, "title": title},
)

@classmethod
def convert_timestamp_from_github(cls, timestamp: str) -> str:
timestamp_datetime = datetime.fromisoformat(timestamp)
Expand Down Expand Up @@ -451,6 +472,9 @@ def __init__(self, client: GitHubAPIClient, data: dict):
self.diff_url = data["diff_url"]
self.patch_url = data["patch_url"]
self.body = data["body"] # description
self.parsed_body = (
self.body.split(SPECIAL_DELIMITER)[-1].strip() if self.body else ""
)
self.is_draft = data["draft"]
self.comments_url = data["comments_url"]
self.commits_url = data["commits_url"]
Expand Down Expand Up @@ -608,8 +632,8 @@ def commit_message(self) -> str:

lines = [self.title, ""]

if self.body:
lines += [self.body, ""]
if self.parsed_body:
lines += [self.parsed_body, ""]

lines.append(f"Pull request: {self.html_url}")

Expand Down
Loading