roundabout,
created on Tuesday, 12 November 2024, 17:29:59 (1731432599),
received on Tuesday, 12 November 2024, 17:30:01 (1731432601)
Author identity: vlad <vlad.muntoiu@gmail.com>
9861cba6a3c406e26c42efd7186a9546c482e607
app.py
@@ -1762,9 +1762,6 @@ def repository_prs(username, repository):
repository) >= 1 or pull_request.owner.username == flask.session.get("username")):
flask.abort(403)
if not get_permission_level(flask.session.get("username"), username, repository):
flask.abort(401)
repo_data = Repo.query.filter_by(route=f"/{username}/{repository}").first()
if pull_request:
@@ -1793,6 +1790,9 @@ def repository_prs_merge(username, repository):
pull_request = db.session.get(PullRequest, id)
if pull_request.state != 0:
flask.abort(400)
if pull_request:
result = celery_tasks.merge_heads.delay(
pull_request.head_route,
@@ -1801,11 +1801,12 @@ def repository_prs_merge(username, repository):
pull_request.base_branch,
pull_request.id,
simulate=True,
method=flask.request.form.get("method"), # like merge, fast-forward, rebase
username=flask.session.get("username")
)
task_result = worker.AsyncResult(result.id)
return flask.redirect(f"/task/{result.id}?pr-id={id}", 303) # should be 202 Accepted but we must use a redirect
return flask.redirect(f"/task/{result.id}?pr-id={id}?method={flask.request.form.get('method')}", 303) # should be 202 Accepted but we must use a redirect
# db.session.delete(pull_request)
# db.session.commit()
else:
celery_tasks.py
@@ -72,7 +72,7 @@ def send_notification(user_notification_id):
@shared_task(ignore_result=False)
def merge_heads(head_route, head_branch, base_route, base_branch, pr_id, simulate=True, username=None):
def merge_heads(head_route, head_branch, base_route, base_branch, pr_id, simulate=True, method="merge", username=None):
from models import Repo, Commit, PullRequest, User
server_repo_location = os.path.join(config.REPOS_PATH, base_route.lstrip("/"))
pull_request = db.session.get(PullRequest, pr_id)
@@ -86,14 +86,35 @@ def merge_heads(head_route, head_branch, base_route, base_branch, pr_id, simulat
if base_route == head_route:
common.git_command(server_repo_location, b"", "checkout", f"{base_branch}")
if simulate:
out, err, merge_exit = common.git_command(server_repo_location, b"", "merge", "--no-commit", "--no-ff", f"heads/{head_branch}",
return_err=True, return_exit=True)
# Undo the merge.
common.git_command(server_repo_location, b"", "merge", "--abort")
if method == "merge":
out, err, merge_exit = common.git_command(server_repo_location, b"", "merge", "--no-commit", "--no-ff", f"heads/{head_branch}",
return_err=True, return_exit=True)
# Undo the merge.
common.git_command(server_repo_location, b"", "merge", "--abort")
elif method == "fast-forward":
out, err, merge_exit = common.git_command(server_repo_location, b"", "merge-base", "--is-ancestor", f"heads/{base_branch}", f"heads/{head_branch}",
return_err=True, return_exit=True)
elif method == "rebase":
# To attempt a rebase dry run, switch to a detached head.
common_ancestor = common.git_command(server_repo_location, b"", "merge-base",
f"heads/{base_branch}",
f"heads/{head_branch}").strip().decode()
common.git_command(server_repo_location, b"", "checkout", "--detach", f"heads/{base_branch}")
out, err, merge_exit = common.git_command(server_repo_location, b"", "rebase",
"--onto", f"heads/{head_branch}",
common_ancestor, return_err=True,
return_exit=True)
# Undo the rebase.
common.git_command(server_repo_location, b"", "rebase", "--abort")
else:
out, err, merge_exit = common.git_command(server_repo_location, b"", "merge", f"heads/{head_branch}",
return_err=True, return_exit=True)
if method == "merge":
out, err, merge_exit = common.git_command(server_repo_location, b"", "merge", "--no-ff", f"heads/{head_branch}",
return_err=True, return_exit=True)
elif method == "fast-forward":
out, err, merge_exit = common.git_command(server_repo_location, b"", "merge", "--ff-only", f"heads/{head_branch}",
return_err=True, return_exit=True)
elif method == "rebase":
out, err, merge_exit = common.git_command(server_repo_location, b"", "rebase", f"heads/{head_branch}", return_err=True, return_exit=True)
pull_request.state = 1
@@ -131,23 +152,35 @@ def merge_heads(head_route, head_branch, base_route, base_branch, pr_id, simulat
err += part_err
if simulate:
part_out, part_err, merge_exit = common.git_command(server_repo_location, b"", "merge", "--allow-unrelated-histories",
"--no-commit", "--no-ff", f"NEW/{head_branch}", return_err=True, return_exit=True)
if method == "merge":
part_out, part_err, merge_exit = common.git_command(server_repo_location, b"", "merge", "--allow-unrelated-histories",
"--no-commit", "--no-ff", f"NEW/{head_branch}", return_err=True, return_exit=True)
# Undo the merge.
common.git_command(server_repo_location, b"", "merge", "--abort")
elif method == "fast-forward":
part_out, part_err, merge_exit = common.git_command(server_repo_location, b"", "merge-base", "--is-ancestor", f"heads/{base_branch}", f"NEW/{head_branch}",
return_err=True, return_exit=True)
elif method == "rebase":
# To attempt a rebase dry run, switch to a detached head.
common_ancestor = common.git_command(server_repo_location, b"", "merge-base",
f"heads/{base_branch}",
f"NEW/{head_branch}").strip().decode()
common.git_command(server_repo_location, b"", "checkout", "--detach", f"heads/{base_branch}")
part_out, part_err, merge_exit = common.git_command(server_repo_location, b"", "rebase",
"--onto", f"NEW/{head_branch}",
common_ancestor, return_err=True,
return_exit=True)
# Undo the rebase.
common.git_command(server_repo_location, b"", "rebase", "--abort")
else:
part_out, part_err, merge_exit = common.git_command(server_repo_location, b"", "merge", "--allow-unrelated-histories",
f"NEW/{head_branch}", return_err=True, return_exit=True)
if method == "merge":
part_out, part_err, merge_exit = common.git_command(server_repo_location, b"", "merge", "--allow-unrelated-histories",
"--no-ff", f"NEW/{head_branch}", return_err=True, return_exit=True)
elif method == "fast-forward":
part_out, part_err, merge_exit = common.git_command(server_repo_location, b"", "merge", "--ff-only", f"NEW/{head_branch}", return_err=True, return_exit=True)
elif method == "rebase":
part_out, part_err, merge_exit = common.git_command(server_repo_location, b"", "rebase", f"NEW/{head_branch}", return_err=True, return_exit=True)
diff, diff_exit = common.git_command(server_repo_location, b"", "diff", "--check", return_exit=True)
out += part_out
err += part_err
part_out, part_err = common.git_command(server_repo_location, b"", "remote", "rm", "NEW", return_err=True)
out += part_out
err += part_err
if simulate:
# Undo the merge.
common.git_command(server_repo_location, b"", "merge", "--abort")
else:
# Copy the commits rows from the head repo to the base repo
for commit in new_commits:
commit_data = Commit.query.filter_by(repo_name=head_route, sha=commit).first()
@@ -168,6 +201,12 @@ def merge_heads(head_route, head_branch, base_route, base_branch, pr_id, simulat
db.session.commit()
out += part_out
err += part_err
part_out, part_err = common.git_command(server_repo_location, b"", "remote", "rm", "NEW", return_err=True)
out += part_out
err += part_err
# Undo the identity change.
common.git_command(server_repo_location, b"", "config", "--unset", "user.email")
common.git_command(server_repo_location, b"", "config", "--unset", "user.name")
templates/repository/repo-prs.html
@@ -46,7 +46,7 @@
<section class="card-main flexible-space">
<h3>{{ pr.head_route }} ({{ pr.head_branch }})<br>{{ pr.base_route }} ({{ pr.base_branch }})</h3>
<p>{% trans %}Requested by{% endtrans %} <a href="/{{ pr.owner.username }}">{{ pr.owner.username }}</a> • {{ pr.timestamp | strftime("%A, %e %B %Y, %H:%M:%S") }}</p>
{% if logged_in_user == pr.owner.username or get_permission_level(logged_in_user, username, repository) >= 1 %}
{% if pr.state == 0 and (logged_in_user == pr.owner.username or get_permission_level(logged_in_user, username, repository)) %}
<form class="vbox" method="post">
<input type="hidden" name="id" value="{{ pr.id }}">
<label>
@@ -61,16 +61,26 @@
{% endif %}
</section>
<section>
<x-hbox>
<form action="delete" method="post">
<input type="hidden" name="id" value="{{ pr.id }}">
<button type="submit" class="button-flat">{% trans %}Deny{% endtrans %}</button>
</form>
<form action="merge" method="post">
<input type="hidden" name="id" value="{{ pr.id }}">
<button type="submit">{% trans %}Merge{% endtrans %}</button>
</form>
</x-hbox>
{% if pr.state == 0 and get_permission_level(logged_in_user, username, repository) %}
<x-hbox>
<form action="delete" method="post">
<input type="hidden" name="id" value="{{ pr.id }}">
<button type="submit" class="button-flat">{% trans %}Deny{% endtrans %}</button>
</form>
<form action="merge" method="post">
<input type="hidden" name="id" value="{{ pr.id }}">
<button type="submit" name="method" value="merge" class="button-flat">
{% trans %}Normal merge{% endtrans %}
</button>
<button type="submit" name="method" value="fast-forward" class="button-flat">
{% trans %}Fast-forward merge{% endtrans %}
</button>
<button type="submit" name="method" value="rebase" class="button-flat">
{% trans %}Rebase{% endtrans %}
</button>
</form>
</x-hbox>
{% endif %}
</section>
</article>
{% endfor %}
templates/task-monitor.html
@@ -82,7 +82,7 @@
{% endif %}
{% else %}
<h2>{% trans %}Merge simulation went well; continue?{% endtrans %}</h2>
<a href="{{ result.get()[5] }}/prs/{{ request.args.get('pr-id') }}/merge" class="button">{% trans %}Merge{% endtrans %}</a>
<a href="{{ result.get()[5] }}/prs/{{ request.args.get('pr-id') }}/merge?method={{ request.args.get('method') }}" class="button">{% trans %}Merge{% endtrans %}</a>
{% endif %}
{% endif %}
{% endif %}