提交 9e8a901e 编写于 作者: J Junio C Hamano

Merge branch 'mh/multimail'

An enhanced "post-receive" hook to send e-mail messages.

* mh/multimail:
  post-receive-email: deprecate script in favor of git-multimail
  git-multimail: an improved replacement for post-receive-email
此差异已折叠。
This copy of git-multimail is distributed as part of the "contrib"
section of the Git project as a convenience to Git users.
git-multimail is developed as an independent project at the following
website:
https://github.com/mhagger/git-multimail
The version in this directory was obtained from the upstream project
on 2013-07-14 and consists of the "git-multimail" subdirectory from
revision
1a5cb09c698a74d15a715a86b09ead5f56bf4b06
Please see the README file in this directory for information about how
to report bugs or contribute to git-multimail.
git-multimail is close to, but not exactly, a plug-in replacement for
the old Git project script contrib/hooks/post-receive-email. This
document describes the differences and explains how to configure
git-multimail to get behavior closest to that of post-receive-email.
If you are in a hurry
=====================
A script called migrate-mailhook-config is included with
git-multimail. If you run this script within a Git repository that is
configured to use post-receive-email, it will convert the
configuration settings into the approximate equivalent settings for
git-multimail. For more information, run
migrate-mailhook-config --help
Configuration differences
=========================
* The names of the config options for git-multimail are in namespace
"multimailhook.*" instead of "hooks.*". (Editorial comment:
post-receive-email should never have used such a generic top-level
namespace.)
* In emails about new annotated tags, post-receive-email includes a
shortlog of all changes since the previous annotated tag. To get
this behavior with git-multimail, you need to set
multimailhook.announceshortlog to true:
git config multimailhook.announceshortlog true
* multimailhook.commitlist -- This is a new configuration variable.
Recipients listed here will receive a separate email for each new
commit. However, if this variable is *not* set, it defaults to the
value of multimailhook.mailinglist. Therefore, if you *don't* want
the members of multimailhook.mailinglist to receive one email per
commit, then set this value to the empty string:
git config multimailhook.commitlist ''
* multimailhook.emailprefix -- If this value is not set, then the
subjects of generated emails are prefixed with the short name of the
repository enclosed in square brackets; e.g., "[myrepo]".
post-receive-email defaults to prefix "[SCM]" if this option is not
set. So if you were using the old default and want to retain it
(for example, to avoid having to change your email filters), set
this variable explicitly to the old value:
git config multimailhook.emailprefix "[SCM]"
* The "multimailhook.showrev" configuration option is not supported.
Its main use is obsoleted by the one-email-per-commit feature of
git-multimail.
Other differences
=================
This section describes other differences in the behavior of
git-multimail vs. post-receive-email. For full details, please refer
to the main README file:
* One email per commit. For each reference change, the script first
outputs one email summarizing the reference change (including
one-line summaries of the new commits), then it outputs a separate
email for each new commit that was introduced, including patches.
These one-email-per-commit emails go to the addresses listed in
multimailhook.commitlist. post-receive-email sends only one email
for each *reference* that is changed, no matter how many commits
were added to the reference.
* Better algorithm for detecting new commits. post-receive-email
processes one reference change at a time, which causes it to fail to
describe new commits that were included in multiple branches. For
example, if a single push adds the "*" commits in the diagram below,
then post-receive-email would never include the details of the two
commits that are common to "master" and "branch" in its
notifications.
o---o---o---*---*---* <-- master
\
*---* <-- branch
git-multimail analyzes all reference modifications to determine
which commits were not present before the change, therefore avoiding
that error.
* In reference change emails, git-multimail tells which commits have
been added to the reference vs. are entirely new to the repository,
and which commits that have been omitted from the reference
vs. entirely discarded from the repository.
* The environment in which Git is running can be configured via an
"Environment" abstraction.
* Built-in support for Gitolite-managed repositories.
* Instead of using full SHA1 object names in emails, git-multimail
mostly uses abbreviated SHA1s, plus one-line log message summaries
where appropriate.
* In the schematic diagrams that explain non-fast-forward commits,
git-multimail shows the names of the branches involved.
* The emails generated by git-multimail include the name of the Git
repository that was modified; this is convenient for recipients who
are monitoring multiple repositories.
* git-multimail allows the email "From" addresses to be configured.
* The recipients lists (multimailhook.mailinglist,
multimailhook.refchangelist, multimailhook.announcelist, and
multimailhook.commitlist) can be comma-separated values and/or
multivalued settings in the config file; e.g.,
[multimailhook]
mailinglist = mr.brown@example.com, mr.black@example.com
announcelist = Him <him@example.com>
announcelist = Jim <jim@example.com>
announcelist = pop@example.com
This might make it easier to maintain short recipients lists without
requiring full-fledged mailing list software.
* By default, git-multimail sets email "Reply-To" headers to reply to
the pusher (for reference updates) and to the author (for commit
notifications). By default, the pusher's email address is
constructed by appending "multimailhook.emaildomain" to the pusher's
username.
* The generated emails contain a configurable footer. By default, it
lists the name of the administrator who should be contacted to
unsubscribe from notification emails.
* New option multimailhook.emailmaxlinelength to limit the length of
lines in the main part of the email body. The default limit is 500
characters.
* New option multimailhook.emailstrictutf8 to ensure that the main
part of the email body is valid UTF-8. Invalid characters are
turned into the Unicode replacement character, U+FFFD. By default
this option is turned on.
* Written in Python. Easier to add new features.
此差异已折叠。
#! /usr/bin/env python2
"""Migrate a post-receive-email configuration to be usable with git_multimail.py.
See README.migrate-from-post-receive-email for more information.
"""
import sys
import optparse
from git_multimail import CommandError
from git_multimail import Config
from git_multimail import read_output
OLD_NAMES = [
'mailinglist',
'announcelist',
'envelopesender',
'emailprefix',
'showrev',
'emailmaxlines',
'diffopts',
]
NEW_NAMES = [
'environment',
'reponame',
'mailinglist',
'refchangelist',
'commitlist',
'announcelist',
'announceshortlog',
'envelopesender',
'administrator',
'emailprefix',
'emailmaxlines',
'diffopts',
'emaildomain',
]
INFO = """\
SUCCESS!
Your post-receive-email configuration has been converted to
git-multimail format. Please see README and
README.migrate-from-post-receive-email to learn about other
git-multimail configuration possibilities.
For example, git-multimail has the following new options with no
equivalent in post-receive-email. You might want to read about them
to see if they would be useful in your situation:
"""
def _check_old_config_exists(old):
"""Check that at least one old configuration value is set."""
for name in OLD_NAMES:
if old.has_key(name):
return True
return False
def _check_new_config_clear(new):
"""Check that none of the new configuration names are set."""
retval = True
for name in NEW_NAMES:
if new.has_key(name):
if retval:
sys.stderr.write('INFO: The following configuration values already exist:\n\n')
sys.stderr.write(' "%s.%s"\n' % (new.section, name))
retval = False
return retval
def erase_values(config, names):
for name in names:
if config.has_key(name):
try:
sys.stderr.write('...unsetting "%s.%s"\n' % (config.section, name))
config.unset_all(name)
except CommandError:
sys.stderr.write(
'\nWARNING: could not unset "%s.%s". '
'Perhaps it is not set at the --local level?\n\n'
% (config.section, name)
)
def is_section_empty(section, local):
"""Return True iff the specified configuration section is empty.
Iff local is True, use the --local option when invoking 'git
config'."""
if local:
local_option = ['--local']
else:
local_option = []
try:
read_output(
['git', 'config']
+ local_option
+ ['--get-regexp', '^%s\.' % (section,)]
)
except CommandError, e:
if e.retcode == 1:
# This means that no settings were found.
return True
else:
raise
else:
return False
def remove_section_if_empty(section):
"""If the specified configuration section is empty, delete it."""
try:
empty = is_section_empty(section, local=True)
except CommandError:
# Older versions of git do not support the --local option, so
# if the first attempt fails, try without --local.
try:
empty = is_section_empty(section, local=False)
except CommandError:
sys.stderr.write(
'\nINFO: If configuration section "%s.*" is empty, you might want '
'to delete it.\n\n'
% (section,)
)
return
if empty:
sys.stderr.write('...removing section "%s.*"\n' % (section,))
read_output(['git', 'config', '--remove-section', section])
else:
sys.stderr.write(
'\nINFO: Configuration section "%s.*" still has contents. '
'It will not be deleted.\n\n'
% (section,)
)
def migrate_config(strict=False, retain=False, overwrite=False):
old = Config('hooks')
new = Config('multimailhook')
if not _check_old_config_exists(old):
sys.exit(
'Your repository has no post-receive-email configuration. '
'Nothing to do.'
)
if not _check_new_config_clear(new):
if overwrite:
sys.stderr.write('\nWARNING: Erasing the above values...\n\n')
erase_values(new, NEW_NAMES)
else:
sys.exit(
'\nERROR: Refusing to overwrite existing values. Use the --overwrite\n'
'option to continue anyway.'
)
name = 'showrev'
if old.has_key(name):
msg = 'git-multimail does not support "%s.%s"' % (old.section, name,)
if strict:
sys.exit(
'ERROR: %s.\n'
'Please unset that value then try again, or run without --strict.'
% (msg,)
)
else:
sys.stderr.write('\nWARNING: %s (ignoring).\n\n' % (msg,))
for name in ['mailinglist', 'announcelist']:
if old.has_key(name):
sys.stderr.write(
'...copying "%s.%s" to "%s.%s"\n' % (old.section, name, new.section, name)
)
new.set_recipients(name, old.get_recipients(name))
if strict:
sys.stderr.write(
'...setting "%s.commitlist" to the empty string\n' % (new.section,)
)
new.set_recipients('commitlist', '')
sys.stderr.write(
'...setting "%s.announceshortlog" to "true"\n' % (new.section,)
)
new.set('announceshortlog', 'true')
for name in ['envelopesender', 'emailmaxlines', 'diffopts']:
if old.has_key(name):
sys.stderr.write(
'...copying "%s.%s" to "%s.%s"\n' % (old.section, name, new.section, name)
)
new.set(name, old.get(name))
name = 'emailprefix'
if old.has_key(name):
sys.stderr.write(
'...copying "%s.%s" to "%s.%s"\n' % (old.section, name, new.section, name)
)
new.set(name, old.get(name))
elif strict:
sys.stderr.write(
'...setting "%s.%s" to "[SCM]" to preserve old subject lines\n'
% (new.section, name)
)
new.set(name, '[SCM]')
if not retain:
erase_values(old, OLD_NAMES)
remove_section_if_empty(old.section)
sys.stderr.write(INFO)
for name in NEW_NAMES:
if name not in OLD_NAMES:
sys.stderr.write(' "%s.%s"\n' % (new.section, name,))
sys.stderr.write('\n')
def main(args):
parser = optparse.OptionParser(
description=__doc__,
usage='%prog [OPTIONS]',
)
parser.add_option(
'--strict', action='store_true', default=False,
help=(
'Slavishly configure git-multimail as closely as possible to '
'the post-receive-email configuration. Default is to turn '
'on some new features that have no equivalent in post-receive-email.'
),
)
parser.add_option(
'--retain', action='store_true', default=False,
help=(
'Retain the post-receive-email configuration values. '
'Default is to delete them after the new values are set.'
),
)
parser.add_option(
'--overwrite', action='store_true', default=False,
help=(
'Overwrite any existing git-multimail configuration settings. '
'Default is to abort if such settings already exist.'
),
)
(options, args) = parser.parse_args(args)
if args:
parser.error('Unexpected arguments: %s' % (' '.join(args),))
migrate_config(strict=options.strict, retain=options.retain, overwrite=options.overwrite)
main(sys.argv[1:])
#! /usr/bin/env python2
"""Example post-receive hook based on git-multimail.
This script is a simple example of a post-receive hook implemented
using git_multimail.py as a Python module. It is intended to be
customized before use; see the comments in the script to help you get
started.
It is possible to use git_multimail.py itself as a post-receive or
update hook, configured via git config settings and/or command-line
parameters. But for more flexibility, it can also be imported as a
Python module by a custom post-receive script as done here. The
latter has the following advantages:
* The tool's behavior can be customized using arbitrary Python code,
without having to edit git_multimail.py.
* Configuration settings can be read from other sources; for example,
user names and email addresses could be read from LDAP or from a
database. Or the settings can even be hardcoded in the importing
Python script, if this is preferred.
This script is a very basic example of how to use git_multimail.py as
a module. The comments below explain some of the points at which the
script's behavior could be changed or customized.
"""
import sys
import os
# If necessary, add the path to the directory containing
# git_multimail.py to the Python path as follows. (This is not
# necessary if git_multimail.py is in the same directory as this
# script):
#LIBDIR = 'path/to/directory/containing/module'
#sys.path.insert(0, LIBDIR)
import git_multimail
# It is possible to modify the output templates here; e.g.:
#git_multimail.FOOTER_TEMPLATE = """\
#
#-- \n\
#This email was generated by the wonderful git-multimail tool.
#"""
# Specify which "git config" section contains the configuration for
# git-multimail:
config = git_multimail.Config('multimailhook')
# Select the type of environment:
environment = git_multimail.GenericEnvironment(config=config)
#environment = git_multimail.GitoliteEnvironment(config=config)
# Choose the method of sending emails based on the git config:
mailer = git_multimail.choose_mailer(config, environment)
# Alternatively, you may hardcode the mailer using code like one of
# the following:
# Use "/usr/sbin/sendmail -t" to send emails. The envelopesender
# argument is optional:
#mailer = git_multimail.SendMailer(
# command=['/usr/sbin/sendmail', '-t'],
# envelopesender='git-repo@example.com',
# )
# Use Python's smtplib to send emails. Both arguments are required.
#mailer = git_multimail.SMTPMailer(
# envelopesender='git-repo@example.com',
# # The smtpserver argument can also include a port number; e.g.,
# # smtpserver='mail.example.com:25'
# smtpserver='mail.example.com',
# )
# OutputMailer is intended only for testing; it writes the emails to
# the specified file stream.
#mailer = git_multimail.OutputMailer(sys.stdout)
# Read changes from stdin and send notification emails:
git_multimail.run_as_post_receive_hook(environment, mailer)
...@@ -2,10 +2,19 @@ ...@@ -2,10 +2,19 @@
# #
# Copyright (c) 2007 Andy Parkins # Copyright (c) 2007 Andy Parkins
# #
# An example hook script to mail out commit update information. This hook # An example hook script to mail out commit update information.
# sends emails listing new revisions to the repository introduced by the #
# change being reported. The rule is that (for branch updates) each commit # NOTE: This script is no longer under active development. There
# will appear on one email and one email only. # is another script, git-multimail, which is more capable and
# configurable and is largely backwards-compatible with this script;
# please see "contrib/hooks/multimail/". For instructions on how to
# migrate from post-receive-email to git-multimail, please see
# "README.migrate-from-post-receive-email" in that directory.
#
# This hook sends emails listing new revisions to the repository
# introduced by the change being reported. The rule is that (for
# branch updates) each commit will appear on one email and one email
# only.
# #
# This hook is stored in the contrib/hooks directory. Your distribution # This hook is stored in the contrib/hooks directory. Your distribution
# will have put this somewhere standard. You should make this script # will have put this somewhere standard. You should make this script
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册