mirror of
https://gitlab.archlinux.org/archlinux/aurweb.git
synced 2025-02-03 10:43:03 +01:00
change(rendercomment): converted to use aurweb.db ORM
- Added aurweb.util.git_search. - Decoupled away from rendercomment for easier testability. - Added aurweb.testing.git.GitRepository. - Added templates/testing/{PKGBUILD,SRCINFO}.j2. - Added aurweb.testing.git.GitRepository + `git` pytest fixture Signed-off-by: Kevin Morris <kevr@0cost.org>
This commit is contained in:
parent
4b0cb0721d
commit
2d0e09cd63
9 changed files with 398 additions and 195 deletions
|
@ -7,13 +7,11 @@ import markdown
|
|||
import pygit2
|
||||
|
||||
import aurweb.config
|
||||
import aurweb.db
|
||||
|
||||
from aurweb import logging
|
||||
from aurweb import db, logging, util
|
||||
from aurweb.models import PackageComment
|
||||
|
||||
logger = logging.get_logger(__name__)
|
||||
repo_path = aurweb.config.get('serve', 'repo-path')
|
||||
commit_uri = aurweb.config.get('options', 'commit_uri')
|
||||
|
||||
|
||||
class LinkifyExtension(markdown.extensions.Extension):
|
||||
|
@ -64,6 +62,7 @@ class GitCommitsInlineProcessor(markdown.inlinepatterns.InlineProcessor):
|
|||
"""
|
||||
|
||||
def __init__(self, md, head):
|
||||
repo_path = aurweb.config.get('serve', 'repo-path')
|
||||
self._repo = pygit2.Repository(repo_path)
|
||||
self._head = head
|
||||
super().__init__(r'\b([0-9a-f]{7,40})\b', md)
|
||||
|
@ -74,13 +73,9 @@ class GitCommitsInlineProcessor(markdown.inlinepatterns.InlineProcessor):
|
|||
# Unkwown OID; preserve the orginal text.
|
||||
return (None, None, None)
|
||||
|
||||
prefixlen = 12
|
||||
while prefixlen < 40:
|
||||
if oid[:prefixlen] in self._repo:
|
||||
break
|
||||
prefixlen += 1
|
||||
|
||||
el = markdown.util.etree.Element('a')
|
||||
commit_uri = aurweb.config.get("options", "commit_uri")
|
||||
prefixlen = util.git_search(self._repo, oid)
|
||||
el.set('href', commit_uri % (self._head, oid[:prefixlen]))
|
||||
el.text = markdown.util.AtomicString(oid[:prefixlen])
|
||||
return (el, m.start(0), m.end(0))
|
||||
|
@ -116,49 +111,41 @@ class HeadingExtension(markdown.extensions.Extension):
|
|||
md.treeprocessors.register(HeadingTreeprocessor(md), 'heading', 30)
|
||||
|
||||
|
||||
def get_comment(conn, commentid):
|
||||
cur = conn.execute('SELECT PackageComments.Comments, PackageBases.Name '
|
||||
'FROM PackageComments INNER JOIN PackageBases '
|
||||
'ON PackageBases.ID = PackageComments.PackageBaseID '
|
||||
'WHERE PackageComments.ID = ?', [commentid])
|
||||
return cur.fetchone()
|
||||
def save_rendered_comment(comment: PackageComment, html: str):
|
||||
with db.begin():
|
||||
comment.RenderedComment = html
|
||||
|
||||
|
||||
def save_rendered_comment(conn, commentid, html):
|
||||
conn.execute('UPDATE PackageComments SET RenderedComment = ? WHERE ID = ?',
|
||||
[html, commentid])
|
||||
def update_comment_render_fastapi(comment: PackageComment) -> None:
|
||||
update_comment_render(comment)
|
||||
|
||||
|
||||
def update_comment_render_fastapi(comment):
|
||||
conn = aurweb.db.ConnectionExecutor(
|
||||
aurweb.db.get_engine().raw_connection())
|
||||
update_comment_render(conn, comment.ID)
|
||||
aurweb.db.refresh(comment)
|
||||
def update_comment_render(comment: PackageComment) -> None:
|
||||
text = comment.Comments
|
||||
pkgbasename = comment.PackageBase.Name
|
||||
|
||||
|
||||
def update_comment_render(conn, commentid):
|
||||
text, pkgbase = get_comment(conn, commentid)
|
||||
html = markdown.markdown(text, extensions=[
|
||||
'fenced_code',
|
||||
LinkifyExtension(),
|
||||
FlysprayLinksExtension(),
|
||||
GitCommitsExtension(pkgbase),
|
||||
GitCommitsExtension(pkgbasename),
|
||||
HeadingExtension()
|
||||
])
|
||||
|
||||
allowed_tags = (bleach.sanitizer.ALLOWED_TAGS
|
||||
+ ['p', 'pre', 'h4', 'h5', 'h6', 'br', 'hr'])
|
||||
html = bleach.clean(html, tags=allowed_tags)
|
||||
save_rendered_comment(conn, commentid, html)
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
save_rendered_comment(comment, html)
|
||||
db.refresh(comment)
|
||||
|
||||
|
||||
def main():
|
||||
commentid = int(sys.argv[1])
|
||||
conn = aurweb.db.Connection()
|
||||
update_comment_render(conn, commentid)
|
||||
db.get_engine()
|
||||
comment_id = int(sys.argv[1])
|
||||
comment = db.query(PackageComment).filter(
|
||||
PackageComment.ID == comment_id
|
||||
).first()
|
||||
update_comment_render(comment)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
110
aurweb/testing/git.py
Normal file
110
aurweb/testing/git.py
Normal file
|
@ -0,0 +1,110 @@
|
|||
import os
|
||||
import shlex
|
||||
|
||||
from subprocess import PIPE, Popen
|
||||
from typing import Tuple
|
||||
|
||||
import py
|
||||
|
||||
from aurweb.models import Package
|
||||
from aurweb.templates import base_template
|
||||
from aurweb.testing.filelock import FileLock
|
||||
|
||||
|
||||
class GitRepository:
|
||||
"""
|
||||
A Git repository class to be used for testing.
|
||||
|
||||
Expects a `tmpdir` fixture on construction, which an 'aur.git'
|
||||
git repository will be created in. After this class is constructed,
|
||||
users can call GitRepository.exec for git repository operations.
|
||||
"""
|
||||
|
||||
def __init__(self, tmpdir: py.path.local):
|
||||
self.file_lock = FileLock(tmpdir, "aur.git")
|
||||
self.file_lock.lock(on_create=self._setup)
|
||||
|
||||
def _exec(self, cmdline: str, cwd: str) -> Tuple[int, str, str]:
|
||||
args = shlex.split(cmdline)
|
||||
proc = Popen(args, cwd=cwd, stdout=PIPE, stderr=PIPE)
|
||||
out, err = proc.communicate()
|
||||
return (proc.returncode, out.decode().strip(), err.decode().strip())
|
||||
|
||||
def _exec_repository(self, cmdline: str) -> Tuple[int, str, str]:
|
||||
return self._exec(cmdline, cwd=str(self.file_lock.path))
|
||||
|
||||
def exec(self, cmdline: str) -> Tuple[int, str, str]:
|
||||
return self._exec_repository(cmdline)
|
||||
|
||||
def _setup(self, path: str) -> None:
|
||||
"""
|
||||
Setup the git repository from scratch.
|
||||
|
||||
Create the `path` directory and run the INSTALL recommended
|
||||
git initialization commands inside of it. Additionally, install
|
||||
aurweb.git.update to {path}/hooks/update.
|
||||
|
||||
:param path: Repository path not yet created
|
||||
"""
|
||||
|
||||
os.makedirs(path)
|
||||
|
||||
commands = [
|
||||
"git init -q",
|
||||
"git config --local transfer.hideRefs '^refs/'",
|
||||
"git config --local --add transfer.hideRefs '!refs/'",
|
||||
"git config --local --add transfer.hideRefs '!HEAD'",
|
||||
"git config --local commit.gpgsign false",
|
||||
"git config --local user.name 'Test User'",
|
||||
"git config --local user.email 'test@example.org'",
|
||||
]
|
||||
for cmdline in commands:
|
||||
return_code, out, err = self.exec(cmdline)
|
||||
assert return_code == 0
|
||||
|
||||
# This is also done in the INSTALL script to give the `aur`
|
||||
# ssh user permissions on the repository. We don't need it
|
||||
# during testing, since our testing user will be controlling
|
||||
# the repository. It is left here as a note.
|
||||
# self.exec("chown -R aur .")
|
||||
|
||||
def commit(self, pkg: Package, message: str):
|
||||
"""
|
||||
Commit a Package record to the git repository.
|
||||
|
||||
This function generates a PKGBUILD and .SRCINFO based on
|
||||
`pkg`, then commits them to the repository with the
|
||||
`message` commit message.
|
||||
|
||||
:param pkg: Package instance
|
||||
:param message: Commit message
|
||||
:return: Output of `git rev-parse HEAD` after committing
|
||||
"""
|
||||
ref = f"refs/namespaces/{pkg.Name}/refs/heads/master"
|
||||
rc, out, err = self.exec(f"git checkout -q --orphan {ref}")
|
||||
assert rc == 0, f"{(rc, out, err)}"
|
||||
|
||||
# Path to aur.git repository.
|
||||
repo = os.path.join(self.file_lock.path)
|
||||
|
||||
licenses = [f"'{p.License.Name}'" for p in pkg.package_licenses]
|
||||
depends = [f"'{p.DepName}'" for p in pkg.package_dependencies]
|
||||
pkgbuild = base_template("testing/PKGBUILD.j2")
|
||||
pkgbuild_path = os.path.join(repo, "PKGBUILD")
|
||||
with open(pkgbuild_path, "w") as f:
|
||||
data = pkgbuild.render(pkg=pkg, licenses=licenses, depends=depends)
|
||||
f.write(data)
|
||||
|
||||
srcinfo = base_template("testing/SRCINFO.j2")
|
||||
srcinfo_path = os.path.join(repo, ".SRCINFO")
|
||||
with open(srcinfo_path, "w") as f:
|
||||
f.write(srcinfo.render(pkg=pkg))
|
||||
|
||||
rc, out, err = self.exec("git add PKGBUILD .SRCINFO")
|
||||
assert rc == 0, f"{(rc, out, err)}"
|
||||
|
||||
rc, out, err = self.exec(f"git commit -q -m '{message}'")
|
||||
assert rc == 0, f"{(rc, out, err)}"
|
||||
|
||||
# Return stdout of `git rev-parse HEAD`, which is the new commit hash.
|
||||
return self.exec("git rev-parse HEAD")[1]
|
|
@ -13,6 +13,7 @@ from urllib.parse import urlencode, urlparse
|
|||
from zoneinfo import ZoneInfo
|
||||
|
||||
import fastapi
|
||||
import pygit2
|
||||
|
||||
from email_validator import EmailNotValidError, EmailUndeliverableError, validate_email
|
||||
from jinja2 import pass_context
|
||||
|
@ -193,3 +194,19 @@ def file_hash(filepath: str, hash_function: Callable) -> str:
|
|||
with open(filepath, "rb") as f:
|
||||
hash_ = hash_function(f.read())
|
||||
return hash_.hexdigest()
|
||||
|
||||
|
||||
def git_search(repo: pygit2.Repository, commit_hash: str) -> int:
|
||||
"""
|
||||
Return the shortest prefix length matching `commit_hash` found.
|
||||
|
||||
:param repo: pygit2.Repository instance
|
||||
:param commit_hash: Full length commit hash
|
||||
:return: Shortest unique prefix length found
|
||||
"""
|
||||
prefixlen = 12
|
||||
while prefixlen < len(commit_hash):
|
||||
if commit_hash[:prefixlen] in repo:
|
||||
break
|
||||
prefixlen += 1
|
||||
return prefixlen
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue