~edwargix/git.sr.ht

963825d10776e24bd1d1d5921093e7189f166660 — Drew DeVault 5 years ago ffb94a4
Attach annotations to a specific commit sha

See git.sr.ht#267

When a new commit is pushed which updates some blobs, but not others,
cross-references between them will be broken.

We could technically associate this with the top-level tree sha, but
this would be wrong for subtrees and it's not obvious how to avoid this.
Since one commit is guaranteed to be associated with a toplevel tree,
attaching it to the commit solves this without much compromise.
4 files changed, 29 insertions(+), 8 deletions(-)

M gitsrht/blueprints/api.py
M gitsrht/blueprints/repo.py
M gitsrht/templates/blob.html
M scss/main.scss
M gitsrht/blueprints/api.py => gitsrht/blueprints/api.py +21 -4
@@ 200,15 200,32 @@ def repo_tree_GET(username, reponame, ref, path):
            abort(404)
        return tree_to_dict(tree)

@data.route("/api/repos/<reponame>/annotate", methods=["PUT"])
@data.route("/api/<username>/repos/<reponame>/annotate", methods=["PUT"])
# TODO: remove fallback routes
@data.route("/api/repos/<reponame>/annotate", methods=["PUT"],
        defaults={"username": None, "commit": "master"})
@data.route("/api/<username>/repos/<reponame>/annotate", methods=["PUT"],
        defaults={"commit": "master"})
@data.route("/api/repos/<reponame>/<commit>/annotate", methods=["PUT"],
        defaults={"username": None})
@data.route("/api/<username>/repos/<reponame>/<commit>/annotate", methods=["PUT"])
@oauth("repo:write")
def repo_annotate_PUT(username, reponame):
def repo_annotate_PUT(username, reponame, commit):
    user = get_user(username)
    repo = get_repo(user, reponame, needs=UserAccess.manage)

    valid = Validation(request)

    with GitRepository(repo.path) as git_repo:
        try:
            commit = git_repo.revparse_single(commit)
        except KeyError:
            abort(404)
        except ValueError:
            abort(404)
        if not isinstance(commit, pygit2.Commit):
            abort(400)
        commit = commit.id.hex

    nblobs = 0
    for oid, annotations in valid.source.items():
        valid.expect(isinstance(oid, str), "blob keys must be strings")


@@ 220,7 237,7 @@ def repo_annotate_PUT(username, reponame):
            validate_annotation(valid, anno)
        if not valid.ok:
            return valid.response
        redis.set(f"git.sr.ht:git:annotations:{repo.id}:{oid}",
        redis.set(f"git.sr.ht:git:annotations:{repo.id}:{oid}:{commit}",
                json.dumps(annotations))
        # Invalidate rendered markup cache
        redis.delete(f"git.sr.ht:git:highlight:{oid}")

M gitsrht/blueprints/repo.py => gitsrht/blueprints/repo.py +5 -3
@@ 52,9 52,10 @@ def get_readme(repo, tip, link_prefix=None):
    return get_formatted_readme("git.sr.ht:git", file_finder, content_getter,
            link_prefix=link_prefix)

def _highlight_file(repo, ref, name, data, blob_id):
def _highlight_file(repo, ref, name, data, blob_id, commit_id):
    def get_annos():
        annotations = redis.get(f"git.sr.ht:git:annotations:{repo.id}:{blob_id}")
        annotations = redis.get("git.sr.ht:git:annotations:" +
            f"{repo.id}:{blob_id}:{commit_id}")
        if annotations:
            return json.loads(annotations.decode())
        return None


@@ 195,6 196,7 @@ def tree(owner, repo, ref, path):
        commit, ref, path = lookup_ref(git_repo, ref, path)
        if isinstance(commit, pygit2.Tag):
            commit = git_repo.get(commit.target)
        orig_commit = commit

        tree = commit.tree
        if not tree:


@@ 225,7 227,7 @@ def tree(owner, repo, ref, path):
                force_source = "view-source" in request.args
                return render_template("blob.html", view="blob",
                        owner=owner, repo=repo, ref=ref, path=path, entry=entry,
                        blob=blob, data=data, commit=commit,
                        blob=blob, data=data, commit=orig_commit,
                        highlight_file=_highlight_file,
                        editorconfig=editorconfig,
                        markdown=markdown, force_source=force_source)

M gitsrht/templates/blob.html => gitsrht/templates/blob.html +2 -1
@@ 101,7 101,8 @@ pre, body {
        id="L{{loop.index}}"
        >{{loop.index}}</a>{% if not loop.last %}
{% endif %}{% endfor %}</pre>
      {{ highlight_file(repo, ref, entry.name, data, blob.id.hex) }}
      {{ highlight_file(repo, ref, entry.name,
        data, blob.id.hex, commit.id.hex) }}
    </div>
    {% else %}
    <div class="col-md-12">

M scss/main.scss => scss/main.scss +1 -0
@@ 182,6 182,7 @@ img {
    color: inherit;
    background: lighten($primary, 45);
    border-bottom: 1px dotted $gray-800;
    text-decoration: none;

    &:hover {
      text-decoration: none;