sendemail-validate.sample 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. #!/usr/bin/env python3
  2. # Copyright (C) 2020 Agilent Technologies, Inc.
  3. # Author: Chris Laplante <chris.laplante@agilent.com>
  4. # This sendemail-validate hook injects 'From: ' header lines into outgoing
  5. # emails sent via 'git send-email', to ensure that accurate commit authorship
  6. # information is present. It was created because some email servers
  7. # (notably Microsoft Exchange / Office 360) seem to butcher outgoing patches,
  8. # resulting in incorrect authorship.
  9. # Current limitations:
  10. # 1. Assumes one per patch per email
  11. # 2. Minimal error checking
  12. #
  13. # Installation:
  14. # 1. Copy to .git/hooks/sendemail-validate
  15. # 2. chmod +x .git/hooks/sendemail-validate
  16. import enum
  17. import re
  18. import subprocess
  19. import sys
  20. class Subject(enum.IntEnum):
  21. NOT_SEEN = 0
  22. CONSUMING = 1
  23. SEEN = 2
  24. def make_from_line():
  25. cmd = ["git", "var", "GIT_COMMITTER_IDENT"]
  26. proc = subprocess.run(cmd, check=True, stdout=subprocess.PIPE, universal_newlines=True)
  27. regex = re.compile(r"^(.*>).*$")
  28. match = regex.match(proc.stdout)
  29. assert match is not None
  30. return "From: {0}".format(match.group(1))
  31. def main():
  32. email = sys.argv[1]
  33. with open(email, "r") as f:
  34. email_lines = f.read().split("\n")
  35. subject_seen = Subject.NOT_SEEN
  36. first_body_line = None
  37. for i, line in enumerate(email_lines):
  38. if (subject_seen == Subject.NOT_SEEN) and line.startswith("Subject: "):
  39. subject_seen = Subject.CONSUMING
  40. continue
  41. if subject_seen == Subject.CONSUMING:
  42. if not line.strip():
  43. subject_seen = Subject.SEEN
  44. continue
  45. if subject_seen == Subject.SEEN:
  46. first_body_line = i
  47. break
  48. assert subject_seen == Subject.SEEN
  49. assert first_body_line is not None
  50. from_line = make_from_line()
  51. # Only add FROM line if it is not already there
  52. if email_lines[first_body_line] != from_line:
  53. email_lines.insert(first_body_line, from_line)
  54. email_lines.insert(first_body_line + 1, "")
  55. with open(email, "w") as f:
  56. f.write("\n".join(email_lines))
  57. return 0
  58. if __name__ == "__main__":
  59. sys.exit(main())