roundabout,
created on Sunday, 18 February 2024, 18:07:13 (1708279633),
received on Wednesday, 31 July 2024, 06:54:41 (1722408881)
Author identity: vlad <vlad.muntoiu@gmail.com>
1b7e00a0fb514171984c96c5bc62ad9a7f623874
app.py
@@ -63,7 +63,7 @@ def default():
"user_object": user_object, "Notification": Notification, "unread": UserNotification.query.filter_by(user_username=username).filter( UserNotification.attention_level > 0).count(),UserNotification.attention_level > 0).count(),"config": config, "Markup": Markup, }
@@ -128,7 +128,7 @@ def notifications():
flask.abort(401) if flask.request.method == "GET": return flask.render_template("notifications.html", notifications=UserNotification.query.filter_by( user_username=flask.session.get("username")))user_username=flask.session.get("username")))@app.route("/accounts/", methods=["GET", "POST"])
@@ -173,7 +173,7 @@ def login():
if username in config.RESERVED_NAMES: flask.flash( Markup( f"<iconify-icon icon='mdi:account-error'></iconify-icon>Sorry, {username} is a system path"),f"<iconify-icon icon='mdi:account-error'></iconify-icon>Sorry, {username} is a system path"),category="error") return flask.render_template("login.html")
@@ -181,7 +181,7 @@ def login():
if user_check: flask.flash( Markup( f"<iconify-icon icon='mdi:account-error'></iconify-icon>The username {username} is taken"),f"<iconify-icon icon='mdi:account-error'></iconify-icon>The username {username} is taken"),category="error") return flask.render_template("login.html")
@@ -574,7 +574,7 @@ def repository_forum_topic(username, repository, id):
@repositories.route("/<username>/<repository>/forum/new", methods=["POST", "GET"]) def repository_forum_new(username, repository): if not (get_visibility(username, repository) or get_permission_level(flask.session.get("username"), username, repository) is not None):repository) is not None):flask.abort(403) serverRepoLocation = os.path.join(config.REPOS_PATH, username, repository)
@@ -597,8 +597,8 @@ def repository_forum_new(username, repository):
db.session.commit() return flask.redirect( flask.url_for(".repository_forum_thread", username=username, repository=repository, post_id=post.number),code=303)flask.url_for(".repository_forum_thread", username=username, repository=repository, post_id=post.number), code=303)@repositories.route("/<username>/<repository>/forum/<int:post_id>")
@@ -667,7 +667,8 @@ def repository_forum_reply(username, repository, post_id):
db.session.commit() return flask.redirect( flask.url_for(".repository_forum_thread", username=username, repository=repository, post_id=post_id), code=303)flask.url_for(".repository_forum_thread", username=username, repository=repository, post_id=post_id), code=303)@repositories.route("/<username>/<repository>/forum/<int:post_id>/voteup", defaults={"score": 1})
@@ -943,28 +944,29 @@ def repository_prs(username, repository):
head = flask.request.form.get("head") head_route = flask.request.form.get("headroute") base = flask.request.form.get("base") base_route = flask.request.form.get("baseroute")if not head and base and head_route and base_route:if not head and base and head_route:return flask.redirect(".", 400) head_repo = git.Repo(os.path.join(server_repo_location, head_route.lstrip("/")))base_repo = git.Repo(os.path.join(server_repo_location, base_route.lstrip("/")))head_repo = git.Repo(os.path.join(config.REPOS_PATH, head_route.lstrip("/"))) base_repo = git.Repo(server_repo_location) print(head_repo)if head not in head_repo or base not in base_repo:if head not in head_repo.branches or base not in base_repo.branches:flask.flash(Markup( "<iconify-icon icon='mdi:error'></iconify-icon>Bad branch name"), category="error") return flask.redirect(".", 400)return flask.redirect(".", 303)head_data = db.session.get(Repo, head_repo)if head_data.visibility != 1:head_data = db.session.get(Repo, head_route) if not head_data.visibility:flask.flash(Markup( "<iconify-icon icon='mdi:error'></iconify-icon>Head can't be restricted"), category="error") return flask.redirect(".", 400)return flask.redirect(".", 303) pull_request = PullRequest(repo_data, head, head_data, base, db.session.get(User, flask.session["username"]))pull_request = PullRequest(repo_data, head, repo_data, base, db.session.get(User, flask.session["username"]))db.session.add(pull_request) db.session.commit()
@@ -984,25 +986,48 @@ def repository_prs_merge(username, repository):
pull_request = db.session.get(PullRequest, id) if pull_request: if pull_request.base != pull_request.head:flask.abort(400)result = celery_tasks.merge_heads.delay( pull_request.head_route, pull_request.head_branch, pull_request.base_route, pull_request.base_branch, simulate=True) task_result = worker.AsyncResult(result.id) flask.flash(Markup(f"Merging PR in task <a href='/task/{result.id}'>{result.id}</a>"), f"task {result.id}")db.session.delete(pull_request)db.session.commit()return flask.redirect(f"/task/{result.id}?pr-id={id}", 303) # db.session.delete(pull_request) # db.session.commit()else: flask.abort(400) return flask.redirect(".", 303)@repositories.route("/<username>/<repository>/prs/<int:id>/merge") def repository_prs_merge_stage_two(username, repository, id): if not get_permission_level(flask.session.get("username"), username, repository): flask.abort(401) server_repo_location = os.path.join(config.REPOS_PATH, username, repository) repo_data = Repo.query.filter_by(route=f"/{username}/{repository}").first() repo = git.Repo(server_repo_location) pull_request = db.session.get(PullRequest, id) if pull_request: result = celery_tasks.merge_heads.delay( pull_request.head_route, pull_request.head_branch, pull_request.base_route, pull_request.base_branch, simulate=False ) task_result = worker.AsyncResult(result.id) return flask.redirect(f"/task/{result.id}?pr-id={id}", 303) # db.session.delete(pull_request) # db.session.commit() else: flask.abort(400)@app.route("/task/<task_id>")
celery_tasks.py
@@ -33,21 +33,50 @@ def send_notification(notification_id, users, level):
@shared_task(ignore_result=False) def merge_heads(head_route, head_branch, base_route, base_branch):def merge_heads(head_route, head_branch, base_route, base_branch, simulate=True):server_repo_location = os.path.join(config.REPOS_PATH, base_route.lstrip("/")) if not os.path.isdir(server_repo_location): raise FileNotFoundError(f"Repo {server_repo_location} not found, cannot merge.") if base_route == head_route: git_command(server_repo_location, b"", "checkout", f"{base_branch}") out, err = git_command(server_repo_location, b"", "merge", "--no-ff", f"heads/{head_branch}", return_err=True)if simulate: out, err = git_command(server_repo_location, b"", "merge", "--no-commit", "--no-ff", f"heads/{head_branch}", return_err=True)return out, err# Undo the merge. git_command(server_repo_location, b"", "merge", "--abort") else: out, err = git_command(server_repo_location, b"", "merge", f"heads/{head_branch}", return_err=True) return "merge_simulator" if simulate else "merge", out, err, head_route, head_branch, base_route, base_branchremote_url = os.path.join(config.BASE_DOMAIN, "git", base_route.lstrip("/")) git_command(server_repo_location, b"", "remote", "add", "NEW", remote_url)git_command(server_repo_location, b"", "remote", "update")git_command(server_repo_location, b"", "checkout", f"{base_branch}")git_command(server_repo_location, b"", "merge", "--allow-unrelated-histories", f"NEW/{head_branch}")git_command(server_repo_location, b"", "remote", "rm", "NEW")out, err = b"", b"" part_out, part_err = git_command(server_repo_location, b"", "remote", "add", "NEW", remote_url, return_err=True) out += part_out err += part_err part_out, part_err = git_command(server_repo_location, b"", "remote", "update", return_err=True) out += part_out err += part_err part_out, part_err = git_command(server_repo_location, b"", "checkout", f"{base_branch}", return_err=True) out += part_out err += part_err if simulate: part_out, part_err = git_command(server_repo_location, b"", "merge", "--allow-unrelated-histories", "--no-commit", "--no-ff", f"NEW/{head_branch}", return_err=True) else: part_out, part_err = git_command(server_repo_location, b"", "merge", "--allow-unrelated-histories", f"NEW/{head_branch}", return_err=True) out += part_out err += part_err part_out, part_err = git_command(server_repo_location, b"", "remote", "rm", "NEW", return_err=True) out += part_out err += part_err if simulate: # Undo the merge. git_command(server_repo_location, b"", "merge", "--abort") return "merge_simulator" if simulate else "merge", out, err, head_route, head_branch, base_route, base_branch
jinja_utils.py
@@ -15,3 +15,8 @@ def strftime(value: datetime, syntax: str):
@app.template_filter("unixtime") def strftime(value: datetime): return round(value.timestamp()) @app.template_filter("decode") def decode(value: bytes, codec: str = "UTF-8", errors: str = "strict"): return value.decode(codec, errors)
misc_utils.py
@@ -11,7 +11,7 @@ def git_command(repo, data, *args, return_err=False):
command = ["git", *args] proc = subprocess.Popen(" ".join(command), cwd=repo, env=env, shell=True, stdout=subprocess.PIPE,proc = subprocess.Popen(" ".join(command), cwd=repo, env=env, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE,stdin=subprocess.PIPE) if data:
templates/favourites.html
@@ -12,7 +12,7 @@
{% for favourite in favourites %} <article class="card card-horizontal"> <section class="card-main flexible-space"> <h3><a href="{{ favourite.repoRoute }}">{{ favourite.repo.owner.username }}/{{ favourite.repo.name }}</a></h3><h3><a href="{{ favourite.repo.route }}">{{ favourite.repo.owner.username }}/{{ favourite.repo.name }}</a></h3></section> </article> {% endfor %}
templates/task-monitor.html
@@ -7,7 +7,75 @@
{% endblock %} {% block content %} <x-frame style="--width: 896px;" class="flexible-space"> <h1>Task results</h1><pre>{{ result.get() }}</pre><x-hbox class="box-center"> <h1>Task results</h1> <div class="flexible-space"></div> {% if result.ready() %} <iconify-icon icon="mdi:check" style="font-size: 2em; color: var(--color-success);"></iconify-icon> Done {% else %} <iconify-icon icon="material-symbols:autorenew" style="animation: rotate 1000ms linear infinite; font-size: 2em; color: var(--color-info);"></iconify-icon> Running... {% endif %} </x-hbox> {% if result.get()[0] == "merge_simulator" %} {% if result.get()[1] %} <h2>Info</h2> <pre aria-busy="true" aria-describedby="task-progress">{{ result.get()[1] | decode }}</pre> {% endif %} {% if result.get()[2] %} <h2>Errors</h2> <pre aria-busy="true" aria-describedby="task-progress">{{ result.get()[2] | decode }}</pre> {% endif %} {% if result.get()[1] or result.get()[2] and not result.get()[2].decode().startswith("Automatic merge went well") %} <h2>Cannot merge your branches :/</h2> <p> Since we can't help you with this yet, you'll need to resolve the merge conflicts on your own computer. </p> <p> In a shell inside your repository execute: </p> {% if result.get()[3] != result.get()[5] %} <pre> <span class="decorative-dollar">git remote add UPSTREAM {{ result.get()[3] }}</span> <span class="decorative-dollar">git remote update</span> <span class="decorative-dollar">git checkout {{ result.get()[6] }}</span> <span class="decorative-dollar">git merge --allow-unrelated-histories UPSTREAM/{{ result.get()[4] }}</span></pre> <p> Then fix your conflicts, merge, and finally, run: </p> <pre> <span class="decorative-dollar">git remote rm UPSTREAM</span></pre> <p> and push the changes. </p> {% else %} <pre> <span class="decorative-dollar">git checkout {{ result.get()[6] }}</span> <span class="decorative-dollar">git merge {{ result.get()[4] }}</span></pre> <p> Resolve your conflicts and merge, then push. </p> {% endif %} {% else %} <h2>Merge simulation went well; continue?</h2> <a href="{{ result.get()[5] }}/prs/{{ request.args.get('pr-id') }}/merge" class="button">Merge</a> {% endif %} {% endif %}</x-frame> <style> @keyframes rotate { 0% { transform: rotate(0); } 100% { transform: rotate(1turn); } } .decorative-dollar::before { content: "$ "; } </style>{% endblock %}