python-zulip-api/zulip/integrations/git/post-receive
Anders Kaseorg 34f5c4ef02 git: Fix git_repository_name.
Without universal_newlines=True or text=True, subprocess.check_output
returns bytes, not str, so it makes no sense to compare its return to
"true".  But upstream Git’s behavior only depends on the filename, not
whether the repository is bare; emulate this more closely.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
2021-08-24 21:01:05 -07:00

103 lines
3.3 KiB
Python
Executable file

#!/usr/bin/env python3
# Zulip notification post-receive hook.
#
# The "post-receive" script is run after receive-pack has accepted a pack
# and the repository has been updated. It is passed arguments in through
# stdin in the form
# <oldrev> <newrev> <refname>
# For example:
# aa453216d1b3e49e7f6f98441fa56946ddcd6a20 68f7abf4e6f922807889f52bc043ecd31b79f814 refs/heads/main
import os
import os.path
import subprocess
import sys
sys.path.insert(0, os.path.dirname(__file__))
import zulip_git_config as config
VERSION = "0.9"
if config.ZULIP_API_PATH is not None:
sys.path.append(config.ZULIP_API_PATH)
import zulip
client = zulip.Client(
email=config.ZULIP_USER,
site=config.ZULIP_SITE,
api_key=config.ZULIP_API_KEY,
client="ZulipGit/" + VERSION,
)
def git_repository_name() -> str:
path, name = os.path.split(os.getcwd())
if name == ".git":
name = os.path.basename(path)
return name[: -len(".git")] if name.endswith(".git") else name
def git_commit_range(oldrev: str, newrev: str) -> str:
log_cmd = ["git", "log", "--reverse", "--pretty=%aE %H %s", f"{oldrev}..{newrev}"]
commits = ""
for ln in subprocess.check_output(log_cmd, universal_newlines=True).splitlines():
author_email, commit_id, subject = ln.split(None, 2)
if hasattr(config, "format_commit_message"):
commits += config.format_commit_message(author_email, subject, commit_id)
else:
commits += f"!avatar({author_email}) {subject}\n"
return commits
def send_bot_message(oldrev: str, newrev: str, refname: str) -> None:
repo_name = git_repository_name()
branch = refname.replace("refs/heads/", "")
destination = config.commit_notice_destination(repo_name, branch, newrev)
if destination is None:
# Don't forward the notice anywhere
return
new_head = newrev[:12]
old_head = oldrev[:12]
if (
oldrev == "0000000000000000000000000000000000000000"
or newrev == "0000000000000000000000000000000000000000"
):
# New branch pushed or old branch removed
added = ""
removed = ""
else:
added = git_commit_range(oldrev, newrev)
removed = git_commit_range(newrev, oldrev)
if oldrev == "0000000000000000000000000000000000000000":
message = f"`{new_head}` was pushed to new branch `{branch}`"
elif newrev == "0000000000000000000000000000000000000000":
message = f"branch `{branch}` was removed (was `{old_head}`)"
elif removed:
message = f"`{new_head}` was pushed to `{branch}`, **REMOVING**:\n\n{removed}"
if added:
message += "\n**and adding**:\n\n" + added
message += "\n**A HISTORY REWRITE HAS OCCURRED!**"
message += "\n@everyone: Please check your local branches to deal with this."
elif added:
message = f"`{new_head}` was deployed to `{branch}` with:\n\n{added}"
else:
message = f"`{new_head}` was pushed to `{branch}`... but nothing changed?"
message_data = {
"type": "stream",
"to": destination["stream"],
"subject": destination["subject"],
"content": message,
}
client.send_message(message_data)
for ln in sys.stdin:
oldrev, newrev, refname = ln.strip().split()
send_bot_message(oldrev, newrev, refname)