deleted file mode 100644
--- a/.hgignore
+++ /dev/null
@@ -1,5 +0,0 @@
-syntax: glob
-
-*~
-*.pyc
-*.pyo
deleted file mode 100644
--- a/COPYING
+++ /dev/null
@@ -1,339 +0,0 @@
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Lesser General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) year name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- <signature of Ty Coon>, 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Lesser General
-Public License instead of this License.
new file mode 100644
--- /dev/null
+++ b/README
@@ -0,0 +1,11 @@
+THIS REPOSITORY AND ITS FULL HISTORY HAS BEEN MIGRATED.
+
+The new location is:
+
+https://hg.mozilla.org/hgcustom/version-control-tools/
+
+You can find the content of this repository under the hghooks/
+directory in that repository. The initial commit to this
+repository (e01e14e32151) is changeset e11fee681380 in
+that repository. The final commit (the parent of this commit)
+(52f75a0ae929) is changeset 1f927bcba52c.
deleted file mode 100644
--- a/convert-pushlog-db.py
+++ /dev/null
@@ -1,173 +0,0 @@
-# Copyright (C) 2010 Mozilla Foundation
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-# This script imports data from the older flat-file pushlog format,
-# and the newer sqlite pushlog format into a newer sqlite schema.
-#
-# Unfortunately, when changing between the older format and the db,
-# the semantics changed somewhat. The older format used to record the
-# *HEAD* revision as of a push, but the db records the *first* changeset
-# in a group of pushed changes. To make life simpler, the new schema
-# will record all changesets for a push, but we need to migrate the old data
-# over.
-# To do so, we grab all logged pushes from the old log and the db,
-# and then for each logged push, if it is in the old log, then it's a head,
-# so store all changes since the previous push with this push. Otherwise,
-# it's a 'first changeset', so store all changes up until the next push
-# with this push. At the end we'll have one entry in the new pushlog
-# table for every push, and one entry per-changeset in the changesets
-# table, mapped back to the pushlog table.
-
-try:
- import sqlite3 as sqlite
-except ImportError:
- from pysqlite2 import dbapi2 as sqlite
-
-import sys
-import os.path
-import re
-from datetime import datetime
-import time
-from calendar import timegm
-from rfc822 import parsedate_tz, mktime_tz
-from mercurial import ui, hg
-from mercurial.node import hex
-
-reader = re.compile(r'^"([a-f0-9]{40})"\t"([^\t]*)"\t"([^\t]*)"$')
-def readlog(logfile):
- """Read a pushlog and yield (node, user, date) for each line. Returns
- all the entries in chronological order. |date| is a timestamp."""
- try:
- fd = open(logfile)
- except IOError:
- return []
- entries = []
- for line in fd:
- (node, user, date) = reader.match(line).group(1, 2, 3)
- entries.append((node, user, mktime_tz(parsedate_tz(date))))
- fd.close()
- return entries
-
-def readpushdb(pushdb):
- """Read a pushlog db and yield (node, user, date) for each line. Returns
- all the entries in chronological order. |date| is a timestamp."""
- try:
- conn = sqlite.connect(pushdb)
- entries = []
- res = conn.execute("SELECT node, user, date FROM pushlog ORDER BY date ASC")
- for (node, user, date) in res:
- entries.append((node, user, timegm(time.strptime(date, "%Y-%m-%dT%H:%M:%SZ"))))
- return entries
- except:
- return []
-
-def nodeindb(pushdb, node):
- return pushdb.execute("SELECT COUNT(*) from changesets WHERE node = ?", (node,)) == 1
-
-if len(sys.argv) != 2:
- print >>sys.stderr, "Must specify a repository as the only parameter (/path/to/repo/)"
- sys.exit(1)
-
-### Main entrypoint
-
-repo_path = os.path.abspath(sys.argv[1])
-if not os.path.exists(repo_path):
- print >>sys.stderr, "Must specify a repository as the only parameter (/path/to/repo/)"
- sys.exit(1)
-
-try:
- repo = hg.repository(ui.ui(), repo_path)
-except:
- print >>sys.stderr, "Must specify a repository as the only parameter (/path/to/repo/)"
- sys.exit(1)
-
-# we need to read both the old text pushlog
-pushlog = os.path.join(repo_path, ".hg", "pushlog")
-# ... and the newer pushlog db
-oldpushdb = pushlog + ".db"
-# and we're going to migrate them both to a new schema
-pushdb = pushlog + "2.db"
-
-# Open or create our new db
-conn = sqlite.connect(pushdb)
-conn.execute("CREATE TABLE IF NOT EXISTS changesets (pushid INTEGER, rev INTEGER, node text)")
-conn.execute("CREATE TABLE IF NOT EXISTS pushlog (id INTEGER PRIMARY KEY AUTOINCREMENT, user TEXT, date INTEGER)")
-conn.execute("CREATE UNIQUE INDEX IF NOT EXISTS changeset_node ON changesets (node)")
-conn.execute("CREATE UNIQUE INDEX IF NOT EXISTS changeset_rev ON changesets (rev)")
-conn.execute("CREATE INDEX IF NOT EXISTS pushlog_date ON pushlog (date)")
-conn.execute("CREATE INDEX IF NOT EXISTS pushlog_user ON pushlog (user)")
-
-# Read all entries from both pushlogs
-flatlogentries = readlog(pushlog)
-flatnodes = dict()
-# dict for easy lookup of nodes
-for (node, user, date) in flatlogentries:
- flatnodes[node] = 1
-logentries = readpushdb(oldpushdb)
-if len(logentries) == 0:
- # just in case someone is importing from an old flatfile log
- logentries = flatlogentries
-
-# sort by revision #, just in case we have two pushes with the same date
-logentries = [(node, repo.changectx(node), user, date) for (node,user,date) in logentries]
-logentries.sort(lambda a,b: cmp(a[1].rev(),b[1].rev()))
-
-# start at the beginning
-lastrev = -1
-next = 0
-for (node, ctx, user, date) in logentries:
- next += 1
- if nodeindb(conn, node):
- # already in the database, move along
- lastrev = ctx.rev()
- continue
- res = conn.execute("INSERT INTO pushlog (user, date) VALUES(?,?)",
- (user, date))
- pushid = res.lastrowid
- # insert this change first
- conn.execute("INSERT INTO changesets (pushid,rev,node) VALUES(?,?,?)",
- (pushid, ctx.rev(), node))
- if node in flatnodes:
- # this was a HEAD revision, see if any other changes were pushed
- # along with it
- if lastrev != ctx.rev() - 1:
- for i in range(lastrev+1, ctx.rev()):
- c = repo.changectx(i)
- conn.execute("INSERT INTO changesets (pushid,rev,node) VALUES(?,?,?)",
- (pushid, c.rev(), hex(c.node())))
- lastrev = ctx.rev()
- else:
- # this was the first change in a set of changes pushed, see
- # if any other changes were pushed along with it
- if next < len(logentries):
- nextctx = repo.changectx(logentries[next][0])
- if ctx.rev() + 1 != nextctx.rev():
- for i in range(ctx.rev()+1, nextctx.rev()):
- c = repo.changectx(i)
- conn.execute("INSERT INTO changesets (pushid,rev,node) VALUES(?,?,?)",
- (pushid, c.rev(), hex(c.node())))
- lastrev = c.rev()
- else: # end of the list, see if we're missing any changes to tip
- if not 'tip' in ctx.tags():
- tip = repo.changectx('tip')
- # we want everything up to and including tip
- for i in range(ctx.rev()+1, tip.rev()+1):
- c = repo.changectx(i)
- conn.execute("INSERT INTO changesets (pushid,rev,node) VALUES(?,?,?)",
- (pushid, c.rev(), hex(c.node())))
- lastrev = c.rev()
-
-conn.commit()
deleted file mode 100644
--- a/example-hgrc
+++ /dev/null
@@ -1,7 +0,0 @@
-# hooks are run in the order in which they appear:
-# any hooks which can veto an action (require-singlehead) should be run before
-# hooks which make permanent logs (record-changeset-info)
-
-[hooks]
-pretxnchangegroup.singlehead = python:mozhghooks.single_head_per_branch.hook
-pretxnchangegroup.linearhistory = python:mozhghooks.pushlog.log
deleted file mode 100755
--- a/hg_require_single_head
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/bin/sh
-
-if test $(hg heads -t --template 'Test_Head\n' | grep -c "^Test_Head") != "1"; then
- printf "You may not push multiple heads to this repository.\n" 1>&2;
- exit 1;
-fi
deleted file mode 100644
--- a/mozhghooks/commit-message.py
+++ /dev/null
@@ -1,94 +0,0 @@
-#!/usr/bin/python
-# Copyright (C) 2011 Mozilla Foundation
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-import re
-from mercurial.node import hex
-
-goodMessage = [re.compile(x, re.I) for x in [
- r'bug\s+\#?[0-9]+',
- r'b=[0-9]+',
- r'no bug',
-
- r'^(back(ing|ed)?\s+out|backout).*(\s+|\:)[0-9a-f]{12}',
- r'^(revert(ed|ing)?).*(\s+|\:)[0-9a-f]{12}',
- r'^add(ed|ing)? tag'
-]]
-
-def isGoodMessage(c):
- def message(fmt):
- print "\n\n************************** ERROR ****************************"
- print fmt.format(rev = hex(c.node())[:12])
- print c.user()
- print c.description()
- print "*************************************************************\n\n"
-
- desc = c.description()
- if c.user() in ["ffxbld", "seabld", "tbirdbld", "cltbld",
- "Gaia Pushbot <release+gaiajson@mozilla.com>",
- "B2G Bumper Bot <release+b2gbumper@mozilla.com>"]:
- return True
-
- if "try: " in desc:
- message("Rev {rev} uses try syntax. (Did you mean to push to Try instead?)")
- return False
-
- for r in goodMessage:
- if r.search(desc):
- return True
-
- dlower = desc.lower()
- if dlower.startswith("merge") or dlower.startswith("merging") or dlower.startswith("automated merge"):
- if len(c.parents()) == 2:
- return True
- else:
- message("Rev {rev} claims to be a merge, but it has only one parent.")
- return False
-
- if dlower.startswith("back") or dlower.startswith("revert"):
- # Purposely ambiguous: it's ok to say "backed out rev N" or "reverted to rev N-1"
- message("Backout rev {rev} needs a bug number or a rev id.")
- else:
- message("Rev {rev} needs a bug number.")
-
- return False
-
-def hook(ui, repo, node, hooktype, **kwargs):
- # All changesets from node to "tip" inclusive are part of this push.
- rev = repo.changectx(node).rev()
- tip = repo.changectx("tip").rev()
- rejecting = False
-
- for i in reversed(xrange(rev, tip + 1)):
- c = repo.changectx(i)
-
- if "IGNORE BAD COMMIT MESSAGES" in c.description():
- # Ignore commit messages for all earlier revs in this push.
- break
-
- if not isGoodMessage(c):
- # Keep looping so the pusher sees all commits they need to fix.
- rejecting = True
-
- if not rejecting:
- return 0
-
- # We want to allow using this hook locally
- if hooktype == "pretxnchangegroup":
- return 1
-
- print "This changeset would have been rejected!"
- return 0 # to fail not warn change to 1
deleted file mode 100644
--- a/mozhghooks/lockfiles.py
+++ /dev/null
@@ -1,45 +0,0 @@
-#!/usr/bin/python
-# Copyright (C) 2011 Mozilla Foundation
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-from os import open, close, read, unlink, O_CREAT, O_EXCL
-from time import sleep
-
-def getlock(fname, verbose=False):
- maxtries=3
- lockf="%s.lck" % fname
- fd = False
- for i in range(0,maxtries):
- try:
- fd = open(lockf, O_CREAT|O_EXCL)
- if verbose:
- print "Locked %s" % fname
- return fd
- except OSError:
- tries=maxtries-i
- if verbose:
- print "Could not lock %s" % fname
- print " Will try %i more times" % tries
- sleep(1)
- return fd
-
-def unlock(fname, fd, verbose=False):
- if verbose:
- print "Unlocking %s" % fname
- lockf = "%s.lck" % fname
- close(fd)
- unlink(lockf)
-
deleted file mode 100644
--- a/mozhghooks/mirror-example.yaml
+++ /dev/null
@@ -1,18 +0,0 @@
-# Daemon configuration
-daemon:
- ssh-id: /etc/mercurial/ssh/id_rsa
- watch-dir: /dev/shm/hg_pushes
- maxchildren: 3
-
-# A wildcard setting, for hosts that should get all repo changes.
-# XXX Not currently implemented.
-all:
- mirrors:
- - hg-backups.mozilla.org
-
-# For each repository, a list of mirrors. Repo is given relative
-# to the hgweb url root.
-/mozilla-central:
- mirrors:
- - mirror1.build.scl1.mozilla.org
- - mirror2.build.scl1.mozilla.org
deleted file mode 100755
--- a/mozhghooks/mirror-pull
+++ /dev/null
@@ -1,95 +0,0 @@
-#!/bin/sh
-
-die() {
- echo "$1" 1>&2
- exit ${2:-1}
-}
-
-usage() {
- echo "USAGE"
- echo " $0 [-r source_repo_root] [-t target_directory] <repository>"
- echo
-}
-
-TEMP=`getopt --options hr:t:l: --long help,root:,target:lock-retries: \
- -n 'mirror-pull' -- "$@"`
-if [ $? != 0 ]; then
- die "getopt barfed"
-fi
-
-eval set -- "$TEMP"
-
-# defaults:
-REPO_ROOT=http://hg.mozilla.org
-REPO_TARGET=/repo/hg/mozilla
-LOCK_RETRIES=15 # every 8 seconds for 2 minutes
-
-while true; do
- case "$1" in
- -r|--root)
- REPO_ROOT="$2" ; shift 2
- ;;
- -t|--target)
- REPO_TARGET="$2" ; shift 2
- ;;
- -l|--lock-retries)
- LOCK_RETRIES="$2" ; shift 2
- ;;
- -h|--help)
- usage
- exit 0
- ;;
- --)
- shift ; break
- ;;
- *)
- die "I don't know what happened."
- ;;
- esac
-done
-
-if [ -n "$SSH_ORIGINAL_COMMAND" ]; then
- # We're running under ssh; the repository is given in the third field
- repo=`echo $SSH_ORIGINAL_COMMAND | cut -d ' ' -f 3`
-else
- repo="$1"
-fi
-
-repo=`echo "$repo" | sed 's#[^-\._/[:alnum:]]##g'`
-test -z "$repo" && die "need a repo to clone, relative to /repo/hg/mozilla"
-
-GLOBAL_HG_OPTS="--config hooks.pretxnchangegroup.z_linearhistory= --config hooks.pretxnchangegroup.z_loghistory="
-
-name=`echo $repo | sed 's#^/*##'`
-src=${REPO_ROOT}/$name
-
-cd $REPO_TARGET || die "$REPO_TARGET does not exist, cannot create repositories there"
-
-exit_code=0
-if [ -d "$name" ]; then
- echo "$name already exists, pulling"
- lockf="${PWD}/${name}.lck"
- lockfile -r $LOCK_RETRIES $lockf || die "Could not lock destination"
- cd $name
- hg pull $GLOBAL_HG_OPTS
- exit_code=$?
- rm -f $lockf
-elif [ \! -e $name ]; then
- mkdir -p `dirname $name`
- echo "$name does not yet exist, cloning"
- lockf="${PWD}/${name}.lck" || die "Could not lock destination"
- lockfile -r $LOCK_RETRIES $lockf
- hg clone $GLOBAL_HG_OPTS -U -v "$src" $name
- exit_code=$?
- rm -f $lockf
-else
- die "WTF is $REPO_TARGET/$name"
-fi
-
-exit $exit_code
-
-# Local variables:
-# mode: shell-script
-# tab-width: 4
-# indent-tabs-mode: nil
-# end:
deleted file mode 100755
--- a/mozhghooks/mirror_daemon.py
+++ /dev/null
@@ -1,212 +0,0 @@
-#!/usr/bin/python
-# Copyright (C) 2011 Mozilla Foundation
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-# 02110-1301, USA.
-
-import random
-import os
-from lockfiles import getlock, unlock
-from subprocess import Popen, PIPE, STDOUT
-from time import sleep
-import urllib
-import shlex
-import yaml
-import signal
-
-random.seed()
-# Set by signal handlers:
-exit_requested = False
-
-class MirrorJob:
- def __init__(self, host, path, config, fh, verbose=False):
- self.host = host
- self.path = path
- self.config = config
- self.verbose = verbose
- self.child = None
- self.command = self.make_command()
-
- # Given a host and path to clone, return the command used to trigger a
- # pull.
- def make_command(self):
- ssh_id = get_config_key(self.config, ['daemon', 'ssh-id'])
- if ssh_id:
- id_str = "-i%s" % ssh_id
- else:
- id_str = ""
- return "/usr/bin/ssh -n %s %s hg pull %s" % (id_str, self.host, self.path)
-
- # Spawn a child process for the given command
- def spawn_child(self):
- self.child = Popen(shlex.split(self.command), stdout=PIPE, stderr=STDOUT)
- if self.verbose:
- print "Spawned [%s] as pid %i" % (self.command, self.child.pid)
-
-# Spawn subprocesses for each of the given commands, up to
-# max_children. Returns two lists of MirrorJob objects, one
-# containing the running jobs, and one containing jobs that
-# were not spawned for some reason.
-def spawn_children(commands, running_jobs, max_children, verbose=False):
- procs = running_jobs
- skipped_jobs = []
- # while len(procs) < max_children and len(commands) > 0:
- for i in range(0, len(commands)):
- if(len(procs) >= max_children or
- check_dup_jobs(commands[i], running_jobs)):
- skipped_jobs.append(commands[i])
- else:
- commands[i].spawn_child()
- procs.append(commands[i])
- if verbose:
- print "Spawned %i processes, %i pending" % ( len(procs), len(skipped_jobs) )
- return (procs, skipped_jobs)
-
-# Check to see if a running job already exists for the
-# given host/repo pair. Returns boolean
-def check_dup_jobs(job, running_jobs):
- for cur in running_jobs:
- if(job.host == cur.host and
- job.path == cur.path):
- return True
- return False
-
-# check each child process, gather any output,
-def reap_children(jobs, verbose=False):
- if verbose:
- print "in reap_children, nchildren = %i" % len(jobs)
- for job in jobs:
- output = None
- rcode = job.child.poll()
- if(rcode != None):
- output = job.child.communicate()
- if(rcode == 0):
- print "Successfully pushed %s to %s" % (job.path, job.host)
- else:
- print "ERROR: Push of %s to %s returned %i" % (job.path, job.host, rcode)
- if verbose:
- if output:
- print "Output: %s" % output[0]
- jobs.remove(job)
- return jobs
-
-# Different repositories might get mirrored to different hosts. For a
-# given repository, return a list of hosts that should receive push
-# notifications.
-def get_hosts_for_repo(repo, config):
- hosts = get_config_key(config, [repo, 'mirrors'])
- if hosts:
- return hosts
- else:
- return []
-
-# Look for repositories that have been updated. Return a list of
-# commands to run to notify the appropriate mirrors that they should
-# update.
-def get_more_commands(directory, config, verbose=False):
- cmnds = []
- if verbose:
- print "Looking for files in %s" % directory
- dirh = os.listdir(directory)
- for f in dirh:
- fullpath = "%s/%s" % (directory, f)
- lck = getlock(fullpath, verbose)
- if lck:
- fh = file(fullpath, 'r')
- os.unlink(fullpath)
- unlock(fullpath, lck, verbose)
- for host in get_hosts_for_repo(urllib.unquote(f), config):
- cmnds.append(MirrorJob(host,
- urllib.unquote(f),
- config,
- fh))
- if verbose:
- print "Appended a command to the queue. ",
- print "qlen: %i" % len(cmnds)
- fh.close()
- else:
- print "Couldn't lock %s" % fullpath
- return cmnds
-
-# Read the config file. Returns a dictionary object, which may be empty
-def read_config(configfile):
- try:
- f = file(configfile)
- except IOError, e:
- print "WARNING: mirror config %s: %s" % (configfile, e)
- return {}
- y = yaml.load(f)
- f.close()
- if y == None:
- y = {}
- return y
-
-# get the config value specified by the given path array.
-# Returns the requested value or None if it's not present.
-def get_config_key(config, path):
- try:
- if len(path) == 0:
- return config
- current = path[0]
- del path[0]
- return get_config_key(config[current], path)
- except KeyError:
- return None
-
-def main():
- global exit_requested
- running_jobs = []
- pending_jobs = []
- configfile = "/etc/mercurial/repo-mirrors.yaml"
- cfg = read_config(configfile)
-
- # Read some global values from the config file, filling in
- # some sane-ish defaults for missing values.
- verbose = get_config_key(cfg, ['daemon', 'verbose'])
- dir = get_config_key(cfg, ['daemon', 'watch-dir'])
- if not dir:
- dir = "/dev/shm/hg_pushes"
- maxchildren = get_config_key(cfg, ['daemon', 'maxchildren'])
- if not maxchildren:
- maxchildren = 3
-
- def sighandler(signum, frame):
- print "Caught signal %i" % signum
- global exit_requested
- exit_requested = True
- if(len(running_jobs) > 0 or len(pending_jobs) > 0):
- print "WARNING: There are %i running jobs and %i queued jobs" % (len(running_jobs),
- len(pending_jobs))
- print "WARNING: To ensure a clean exit, will terminate after the queue is emptied"
-
- signal.signal(signal.SIGTERM, sighandler)
-
- while True:
- if not exit_requested:
- pending_jobs = pending_jobs + get_more_commands(dir, cfg, verbose)
- running_jobs = reap_children(running_jobs, verbose)
- (running_jobs, pending_jobs) = spawn_children(pending_jobs, running_jobs,
- maxchildren - len(running_jobs),
- verbose)
- if(exit_requested and
- len(running_jobs) == 0 and
- len(pending_jobs) == 0):
- break
- sleep(1)
- print "Exiting..."
-
-if __name__ == "__main__":
- main()
-
deleted file mode 100755
--- a/mozhghooks/prevent_broken_csets.py
+++ /dev/null
@@ -1,193 +0,0 @@
-#!/usr/bin/python
-# Copyright (C) 2013 Mozilla Foundation
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-'''This hook detects csets which hit hg bug 3833 [1] and break our hg blame.
-
-An example of one such bad commit is dad25c17ccc7 in mozilla-central.
-
-This hook should be used as a pre-commit hook on all trees except try.
-
-[1] http://bz.selenic.com/show_bug.cgi?id=3833.
-'''
-
-from __future__ import print_function
-import os
-import sys
-import traceback
-import textwrap
-from mercurial import ui, scmutil, cmdutil
-from mercurial.node import hex, short, nullid
-
-magicwords = 'IGNORE BROKEN CHANGESETS'
-
-def dedent_and_fill(s):
- r'''This is like textwrap.fill(textwrap.dedent(s)) except it respects
- paragraphs in the text. That is, " foo\n\n bar" is rendered as
- "foo\n\nbar", instead of "foo bar".
-
- This function also adds a blank line to the beginning of the input.
-
- '''
- s = textwrap.dedent(s)
-
- paragraphs = ['']
- current_paragraph = []
- for line in s.split('\n'):
- if line.strip():
- current_paragraph.append(line)
- elif current_paragraph:
- paragraphs.append(' '.join(current_paragraph))
- paragraphs.append('')
- current_paragraph = []
- if current_paragraph:
- paragraphs.append(' '.join(current_paragraph))
-
- return '\n'.join([textwrap.fill(p) for p in paragraphs])
-
-class BrokenCsetException(Exception):
- def __init__(self, cset):
- self.cset = cset
-
- def __str__(self):
- return 'Broken changeset: %s' % str(self.cset)
-
-def hook(ui, repo, hooktype, node, **kwargs):
- # We don't want to apply this hook to try or user repos. (repo.root seems
- # to be a normalized, absolute path, but there's no harm in being sure.)
- repo_path = os.path.normpath(os.path.abspath(repo.root))
- if repo_path == '/repo/hg/mozilla/try' or \
- repo_path.startswith('/repo/hg/mozilla/users'):
- return 0
-
- if repo.changectx('tip').description().find(magicwords) != -1:
- print(dedent_and_fill('''\
- Not checking this push for broken changesets because the tip cset
- contains %s. I hope you mean it!
- ''' % magicwords))
- return 0
-
- try:
- check_for_broken_csets(repo, node)
- except BrokenCsetException as e:
- print(dedent_and_fill('''\
- Broken changeset detected: %s!
-
- Our pre-commit hook detected a broken changeset in your push: %s.
- This changeset was likely produced by a version of hg older than
- 2.5. We're rejecting your push because this cset may break hg
- blame [1].
-
- Please upgrade to hg 2.5.1 or newer (2.5 contains known bugs),
- qimport your changes, then qpop, qpush, and qfinish them. You
- might do:
-
- $ hg qimport --rev 'outgoing()'
- $ hg qpop -a && hg qpush -a && hg qfinish -a
-
- If this doesn't solve the problem, or if you're sure that these
- commits were generated using hg 2.5 or newer, please ask someone in
- #it, or file a bug.
-
- You can work around this hook by putting "%s" in your topmost
- changeset, but please don't use this lightly.
-
- [1] https://bugzilla.mozilla.org/show_bug.cgi?id=843081
- ''' %
- (e.cset, e.cset, magicwords)))
-
- # Reject the push.
- return 1
- except Exception:
- print(dedent_and_fill('''\
- WARNING: The prevent_broken_csets pre-commit hook encountered an
- unexpected error. We're going to allow your push to go through,
- but please ping someone in #it or file a bug in
-
- mozilla.org :: Server Operations: Developer Services
-
- so that the right people are informed of this issue. Thanks!
- '''))
- traceback.print_exc(file=sys.stdout)
-
- # Accept the push
- return 0
-
-def check_for_broken_csets(repo, push_root):
- '''Check for broken changesets. If we find one, we raise a
- BrokenCsetException. Otherwise we return without error.
-
- '''
- push_root_node = repo[push_root]
-
- # Gather all the leaf nodes in this push. There should be at least one; I
- # don't know what it means to push without any leaves!
- leaves = []
- for change_id in xrange(push_root_node.rev(), len(repo)):
- n = repo[change_id]
- if not n.children():
- leaves.append(n)
-
- if not leaves:
- print(dedent_and_fill('''\
- WARNING: No leaf nodes in this push? This is probably a bug
- in the commit hook. Please ask someone in #it about this, or
- file a bug in
-
- mozilla.org :: Server Operations: Developer Services.
-
- In the meantime, we won't reject your push.'''))
- return
-
- # For each leaf, gather the set of files modified between the leaf and the
- # parent(s) of the base commit.
- modified_files = set()
- for leaf_node in leaves:
- for p in push_root_node.parents():
- modified_files.update(repo.status(node1=p, node2=leaf_node)[0])
-
- # Check each of these files' debugindex entries.
- for filename in modified_files:
- check_debugindex(repo, filename, push_root_node.rev())
-
-def check_debugindex(repo, filename, min_rev):
- '''Check hg's debugindex for filename for bad csets. A cset is bad if both parents
- are null and if it comes from this push (i.e., linkrev >= min_rev).
-
- If we find a bad changeset, we throw a BrokenCsetException.
-
- '''
- # I don't entirely understand what this does, but it's similar to the
- # debugindex command in hg's commands.py. See also
- # http://bz.selenic.com/show_bug.cgi?id=3833#c20
-
- r = cmdutil.openrevlog(repo, 'debugindex', filename,
- {'changelog': False, 'manifest': False})
- for i in r:
- node = r.node(i)
- linkrev = repo[r.linkrev(i)]
- if linkrev.rev() < min_rev:
- continue
- try:
- parents = r.parents(node)
- except Exception:
- parents = (nullid, nullid)
-
- # If this file has no parents, check whether the relevant rev modified
- # the file (as opposed to, for example, adding it). If the rev did
- # modify the file, then this is a bad changeset.
- if parents == (nullid, nullid) and \
- filename in repo.status(node1=linkrev.p1(), node2=linkrev)[0]:
- raise BrokenCsetException(linkrev)
deleted file mode 100644
--- a/mozhghooks/prevent_case_only_renames.py
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/usr/bin/python
-# Copyright (C) 2011 Mozilla Foundation
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-"""
-This hook is designed to prevent renames that only change the case of a file.
-"""
-from mercurial.node import hex, short
-
-def hook(ui, repo, node, hooktype, **kwargs):
- # All changesets from node to "tip" inclusive are part of this push.
- rev = repo.changectx(node).rev()
- tip = repo.changectx("tip").rev()
- rejecting = False
-
- for i in range(rev, tip + 1):
- ctx = repo.changectx(i)
- for f in ctx:
- fctx = ctx.filectx(f)
- r = fctx.renamed()
- if not r:
- continue
- if f.lower() == r[0].lower():
- rejecting = True
- print "\n\n************************** ERROR ****************************"
- print "File rename in changeset %s only changes file case! (%s to %s)" % (short(hex(ctx.node())), r[0], f)
- print "*************************************************************\n\n"
- return 1 if rejecting else 0
deleted file mode 100644
--- a/mozhghooks/prevent_unlabelled_australis_changes.py
+++ /dev/null
@@ -1,64 +0,0 @@
-#!/usr/bin/python
-# Copyright (C) 2012 Mozilla Foundation
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-"""
-This hook prevents changes from being made to Australis-related files,
-unless the commit message contains "australis" or an override string.
-"""
-from mercurial.node import short
-
-
-def printError(c):
- print "\n\n************************** ERROR ****************************"
- print "Changeset %s appears to make australis changes, but does" % short(c.node())
- print "not contain \"australis\" in the commit message! (See bug 943486)"
- print " -> \"%s\"" % c.description()
- print "*************************************************************"
-
-
-def hook(ui, repo, node, hooktype, **kwargs):
- changesets = list(repo.changelog.revs(repo[node].rev()))
- rejecting = False
-
- # All changesets in this push, starting at tip (so the override works).
- # Note: Unless the override was used, we do not break the outer loop, so
- # that the pusher can see all of the commits that need fixing in one go.
- for i in reversed(changesets):
- c = repo.changectx(i)
-
- desc = c.description()
-
- if "OVERRIDE HOOK" in desc:
- # Skip all earlier commits in this push.
- break
-
- if "australis" in desc.lower():
- # This commit is labelled correctly, proceed to the next.
- continue
-
- if len(c.parents()) > 1:
- # Skip merge changesets
- continue
-
- for file in c.files():
- if ((file.startswith("browser/themes/") and "devtools" not in file) or
- file.startswith("browser/components/customizableui/")):
- # Australis-related files found.
- rejecting = True
- printError(c)
- break
-
- return 1 if rejecting else 0
deleted file mode 100755
--- a/mozhghooks/prevent_uuid_changes.py
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/usr/bin/python
-# Copyright (C) 2012 Mozilla Foundation
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-"""
-This hook is to prevent changes to IID or UUID in pushes to trees where such changes could cause critical issues (eg: beta, release).
-"""
-
-import re
-
-def hook(ui, repo, hooktype, node, **kwargs):
- error = ""
- bc = False
- # Loop through each changeset being added to the repository
- for change_id in xrange(repo[node].rev(), len(repo)):
- # Loop through each file for the current changeset
- for file in repo[change_id].files():
- # Only Check IDL Files
- if file.endswith('.idl'):
- bc = True
- if not re.search('ba\S*=', repo.changectx('tip').description().lower()):
- error += "IDL file %s altered in this changeset" % file
- # Check if an error occured in any of the files that were changed
- if error != "":
- print "\n\n************************** ERROR ****************************"
- ui.warn("\n\r*** " + error + "***\n\r")
- print "\n\rChanges to IDL files in this repo require you to provide binary change approval in your top comment in the form of ba=... (or, more accurately, ba\\S*=...)\n\rThis is to ensure that UUID changes (or method changes missing corresponding UUID change) are caught early, before release.\n\r"
- print "*************************************************************\n\n"
- # Reject the changesets
- return 1
- else:
- if bc:
- print "You've signaled approval for the binary change(s) in your push, thanks for the extra caution."
- # Accept the changesets
- return 0
deleted file mode 100755
--- a/mozhghooks/prevent_webidl_changes.py
+++ /dev/null
@@ -1,111 +0,0 @@
-#!/usr/bin/python
-# Copyright (C) 2012 Mozilla Foundation
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-"""
-This hook is to prevent changes to .webidl files in pushes without proper DOM peer review.
-"""
-
-import re
-from mercurial.node import short
-from mercurial import util
-
-backoutMessage = [re.compile(x) for x in [
- r'^(back(ing|ed)?\s+out|backout)',
- r'^(revert(ed|ing)?)'
-]]
-
-def isBackout(message):
- for r in backoutMessage:
- if r.search(message):
- return True
- return False
-
-def hook(ui, repo, hooktype, node, **kwargs):
- DOM_peers = [
- 'jst', # Johnny Stenback
- 'peterv', # Peter Van der Beken
- 'bz', 'bzbarsky', # Boris Zbarsky
- 'sicking', 'jonas', # Jonas Sicking
- 'smaug', # Olli Pettay
- 'bent', # Ben Turner
- 'mounir', # Mounir Lamouri
- 'khuey', # Kyle Huey
- 'jlebar', # Justin Lebar
- 'hsivonen', # Henri Sivonen
- 'mrbkap', # Blake Kaplan
- 'bholley', # Bobby Holley
- ]
- DOM_authors = [
- 'jst@mozilla.com', # Johnny Stenback
- 'peterv@propagandism.org', # Peter Van der Beken
- 'bzbarsky@mit.edu', # Boris Zbarsky
- 'jonas@sicking.cc', # Jonas Sicking
- 'olli.pettay@helsinki.fi', # Olli Pettay
- 'bent.mozilla@gmail.com', # Ben Turner
- 'mounir@lamouri.fr', # Mounir Lamouri
- 'khuey@kylehuey.com', # Kyle Huey
- 'justin.lebar@gmail.com', # Justin Lebar
- 'hsivonen@hsivonen.fi', # Henri Sivonen
- 'mrbkap@gmail.com', # Blake Kaplan
- ]
- error = ""
- webidlReviewed = False
- changesets = list(repo.changelog.revs(repo[node].rev()))
- if 'a=release' in repo.changectx(changesets[-1]).description().lower():
- # Accept the entire push for code uplifts.
- return 0
- # Loop through each changeset being added to the repository
- for i in reversed(changesets):
- c = repo.changectx(i)
-
- if len(c.parents()) > 1:
- # Skip merge changesets
- continue
-
- # Loop through each file for the current changeset
- for file in c.files():
- # Only Check WebIDL Files
- if file.endswith('.webidl'):
- message = c.description().lower()
- email = util.email(c.user())
- def search():
- matches = re.findall('\Ws?r\s*=\s*(\w+(?:,\w+)*)', message)
- for match in matches:
- for reviewer in match.split(','):
- if reviewer in DOM_peers:
- return True
- # We allow DOM peers to commit changes to WebIDL files without any review
- # requirements assuming that they have looked at the changes they're committing.
- for peer in DOM_authors:
- if peer == email:
- return True
- return False
- webidlReviewed = search()
- if not webidlReviewed and not isBackout(message):
- error += "WebIDL file %s altered in changeset %s without DOM peer review\n" % (file, short(c.node()))
- # Check if an error occured in any of the files that were changed
- if error != "":
- print "\n\n************************** ERROR ****************************"
- ui.warn("\n" + error + "\n")
- print "\n\rChanges to WebIDL files in this repo require review from a DOM peer in the form of r=...\n\rThis is to ensure that we behave responsibly with exposing new Web APIs. We appreciate your understanding..\n\r"
- print "*************************************************************\n\n"
- # Reject the changesets
- return 1
- else:
- if webidlReviewed:
- print "You've received proper review from a DOM peer on your WebIDL change(s) in your push, thanks for paying enough attention."
- # Accept the changesets
- return 0
deleted file mode 100644
--- a/mozhghooks/push_printurls.py
+++ /dev/null
@@ -1,129 +0,0 @@
-#!/usr/bin/python
-import os.path
-from mercurial.node import short
-
-hgNameToRevURL = {
- # Gecko trunk / integration branches
- 'b2g-inbound': 'integration/b2g-inbound/',
- 'build-system': 'projects/build-system',
- 'fx-team': 'integration/fx-team/',
- 'mozilla-central': 'mozilla-central/',
- 'mozilla-inbound': 'integration/mozilla-inbound/',
- 'services-central': 'services/services-central/',
- # Gecko release branches
- 'mozilla-aurora': 'releases/mozilla-aurora/',
- 'mozilla-beta': 'releases/mozilla-beta/',
- 'mozilla-release': 'releases/mozilla-release/',
- 'mozilla-esr24': 'releases/mozilla-esr24/',
- 'mozilla-esr31': 'releases/mozilla-esr31/',
- # Gecko B2G branches
- 'mozilla-b2g32_v2_0': 'releases/mozilla-b2g32_v2_0/',
- 'mozilla-b2g30_v1_4': 'releases/mozilla-b2g30_v1_4/',
- 'mozilla-b2g28_v1_3': 'releases/mozilla-b2g28_v1_3/',
- 'mozilla-b2g28_v1_3t': 'releases/mozilla-b2g28_v1_3t/',
- # Thunderbird branches
- 'comm-central': 'comm-central/',
- 'comm-aurora': 'releases/comm-aurora/',
- 'comm-beta': 'releases/comm-beta/',
- 'comm-release': 'releases/comm-release/',
- 'comm-esr24': 'releases/comm-esr24/',
- 'comm-esr31': 'releases/comm-esr31/',
- # Try repos
- 'try': 'try/',
- 'try-comm-central': 'try-comm-central/',
-}
-
-# Project branches that are in active use
-hgNameToRevURL.update({
- 'alder': 'projects/alder/',
- 'ash': 'projects/ash/',
- 'birch': 'projects/birch/',
- 'cedar': 'projects/cedar/',
- 'cypress': 'projects/cypress/',
- 'date': 'projects/date/',
- 'elm': 'projects/elm/',
- 'fig': 'projects/fig/',
- 'gum': 'projects/gum/',
- 'holly': 'projects/holly/',
- 'jamun': 'projects/jamun/',
- 'larch': 'projects/larch/',
- 'maple': 'projects/maple/',
- 'oak': 'projects/oak/',
- 'pine': 'projects/pine/',
-})
-
-# QA repos
-hgNameToRevURL.update({
- 'mozmill-tests': 'qa/mozmill-tests/',
- 'testcase-data': 'qa/testcase-data/',
-})
-
-# RelEng repos
-hgNameToRevURL.update({
- 'autoland': 'build/autoland/',
- 'braindump': 'build/braindump/',
- 'buildapi': 'build/buildapi/',
- 'buildbot': 'build/buildbot/',
- 'buildbot-configs': 'build/buildbot-configs/',
- 'buildbotcustom': 'build/buildbotcustom/',
- 'cloud-tools': 'build/cloud-tools/',
- 'compare-locales': 'build/compare-locales/',
- 'fork-hg-git': 'build/fork-hg-git/',
- 'hghooks': 'hgcustom/hghooks/',
- 'mozharness': 'build/mozharness/',
- 'mozpool': 'build/mozpool/',
- 'opsi-package-sources': 'build/opsi-package-sources/',
- 'partner-repacks': 'build/partner-repacks/',
- 'preproduction': 'build/preproduction/',
- 'puppet': 'build/puppet/',
- 'puppet-manifests': 'build/puppet-manifests/',
- 'rpm-sources': 'build/rpm-sources/',
- 'talos': 'build/talos/',
- 'tbpl': 'webtools/tbpl/',
- 'tools': 'build/tools/',
- 'twisted': 'build/twisted/',
-})
-
-def hook(ui, repo, node, hooktype, **kwargs):
- repo_name = os.path.basename(repo.root)
- if repo_name not in hgNameToRevURL:
- return 0
-
- # All changesets from node to "tip" inclusive are part of this push.
- rev = repo.changectx(node).rev()
- tip = repo.changectx('tip').rev()
-
- # For try, print out a TBPL url rather than the pushlog
- if repo_name == 'try':
- tip_node = short(repo.changectx(tip).node())
- print 'You can view the progress of your build at the following URL:'
- print ' https://tbpl.mozilla.org/?tree=Try&rev=%s' % tip_node
- print 'Alternatively, view them on Treeherder (experimental):'
- print ' https://treeherder.mozilla.org/ui/#/jobs?repo=try&revision=%s' % tip_node
- return 0
-
- # For try-comm-central, print out a TBPL url rather than the pushlog
- if repo_name == 'try-comm-central':
- tip_node = short(repo.changectx(tip).node())
- print 'You can view the progress of your build at the following URL:'
- print ' https://tbpl.mozilla.org/?tree=Thunderbird-Try&rev=%s' % tip_node
- print 'Alternatively, view them on Treeherder (experimental):'
- print ' https://treeherder.mozilla.org/ui/#/jobs?repo=thunderbird-try&revision=%s' % tip_node
- return 0
-
- num_changes = tip + 1 - rev
- url = 'https://hg.mozilla.org/' + hgNameToRevURL[repo_name]
-
- if num_changes <= 10:
- plural = 's' if num_changes > 1 else ''
- print 'You can view your change%s at the following URL%s:' % (plural, plural)
-
- for i in xrange(rev, tip + 1):
- node = short(repo.changectx(i).node())
- print ' %srev/%s' % (url, node)
- else:
- tip_node = short(repo.changectx(tip).node())
- print 'You can view the pushlog for your changes at the following URL:'
- print ' %spushloghtml?changeset=%s' % (url, tip_node)
-
- return 0
deleted file mode 100644
--- a/mozhghooks/push_repo.py
+++ /dev/null
@@ -1,60 +0,0 @@
-#!/usr/bin/python
-# Copyright (C) 2011 Mozilla Foundation
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-# 02110-1301, USA.
-
-import sys
-sys.path.append('/repo/hg/libraries/mozhghoooks')
-
-from optparse import OptionParser
-from mirror_daemon import *
-from time import sleep
-
-configfile = "/etc/mercurial/repo-mirrors.yaml"
-cfg = read_config(configfile)
-
-parser = OptionParser()
-parser.add_option("-r", "--repo", dest="repo",
- help="Repository path, relative to http://hg.m.o",
- metavar="REPO")
-parser.add_option("-H", "--host", dest="tgt_host",
- help="username@host to push to", metavar="USER@HOST")
-(options, args) = parser.parse_args()
-
-repo = options.repo
-host = options.tgt_host
-
-if not repo or not host:
- parser.print_help()
- sys.exit(1)
-
-# Read some global values from the config file, filling in
-# some sane-ish defaults for missing values.
-verbose = get_config_key(cfg, ['daemon', 'verbose'])
-maxchildren = 1
-
-job = MirrorJob(host, repo, cfg, None, True)
-job.spawn_child()
-
-while True:
- rcode = job.child.poll()
- if rcode != None:
- output = job.child.communicate()
- print "Job finished with code %i. Output follows:" % rcode
- print output[0]
- break
- else:
- sleep(1)
deleted file mode 100644
--- a/mozhghooks/pushlog.py
+++ /dev/null
@@ -1,86 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright (C) 2010 Mozilla Foundation
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-# This script implements a Mercurial hook to log the date and time when
-# changesets are pushed into a repository, and the user that pushed them.
-#
-# run `python setup.py install` to install the module in the proper place,
-# and then modify the repository's hgrc as per example-hgrc.
-
-from mercurial import demandimport
-
-demandimport.disable()
-try:
- import sqlite3 as sqlite
-except ImportError:
- from pysqlite2 import dbapi2 as sqlite
-demandimport.enable()
-
-import time
-import os
-import os.path
-import stat
-from mercurial.node import hex
-
-def createpushdb(conn):
- conn.execute("CREATE TABLE IF NOT EXISTS changesets (pushid INTEGER, rev INTEGER, node text)")
- conn.execute("CREATE TABLE IF NOT EXISTS pushlog (id INTEGER PRIMARY KEY AUTOINCREMENT, user TEXT, date INTEGER)")
- conn.execute("CREATE UNIQUE INDEX IF NOT EXISTS changeset_node ON changesets (node)")
- conn.execute("CREATE UNIQUE INDEX IF NOT EXISTS changeset_rev ON changesets (rev)")
- conn.execute("CREATE INDEX IF NOT EXISTS changeset_pushid ON changesets (pushid)")
- conn.execute("CREATE INDEX IF NOT EXISTS pushlog_date ON pushlog (date)")
- conn.execute("CREATE INDEX IF NOT EXISTS pushlog_user ON pushlog (user)")
- conn.commit()
-
-def schemaexists(conn):
- return 1 == conn.execute("SELECT COUNT(*) FROM SQLITE_MASTER WHERE name='pushlog'").fetchone()[0]
-
-def log(ui, repo, node, **kwargs):
- pushdb = os.path.join(repo.path, 'pushlog2.db')
- createdb = False
- if not os.path.exists(pushdb):
- createdb = True
- conn = sqlite.connect(pushdb)
- if not createdb and not schemaexists(conn):
- createdb = True
- if createdb:
- createpushdb(conn)
- st = os.stat(pushdb)
- os.chmod(pushdb, st.st_mode | stat.S_IWGRP)
- t = int(time.time())
- retval = 1
- print "Trying to insert into pushlog."
- print "Please do not interrupt..."
- try:
- res = conn.execute("INSERT INTO pushlog (user, date) values(?,?)",
- (os.environ['USER'], t))
- pushid = res.lastrowid
- # all changesets from node to 'tip' inclusive are part of this push
- rev = repo.changectx(node).rev()
- tip = repo.changectx('tip').rev()
- for i in range(rev, tip+1):
- ctx = repo.changectx(i)
- conn.execute("INSERT INTO changesets (pushid,rev,node) VALUES(?,?,?)",
- (pushid, ctx.rev(), hex(ctx.node())))
- conn.commit()
- retval = 0
- print "Inserted into the pushlog db successfully."
- except sqlite.OperationalError:
- print "Pushlog database is locked. Please retry your push."
- conn.close()
- return retval
deleted file mode 100644
--- a/mozhghooks/signal-mirrors.py
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/usr/bin/python
-
-# Copyright (C) 2011 Mozilla Foundation
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-import os
-import time
-from mercurial import hg, ui, commands, node
-import re
-import urllib
-from lockfiles import getlock, unlock
-
-repo_toplevel="/repo/hg/mozilla"
-workdir="/dev/shm/hg_pushes"
-
-def hook(ui, repo, **kwargs):
- if not os.path.isdir(workdir):
- os.mkdir(workdir)
- # mode 0777 is unfortunate, but we don't have a more appropriate
- # group at this time...
- os.chmod(workdir, 0777)
- repo_name = os.path.basename(repo.root)
- url_path = re.sub('^%s' % repo_toplevel, '', repo.root)
- # Escape '/' characters in url path, so we can store this
- # info in a filename:
- escaped_path = urllib.quote(url_path, '')
- outfile = "%s/%s" % (workdir, escaped_path)
- lockfd = getlock(outfile)
- if lockfd:
- ui.debug("Writing mirror trigger to %s\n" % outfile)
- outf = file(outfile, "w")
- if(outf):
- print >> outf, kwargs['node']
- outf.close()
- else:
- print "Oh no, I couldn't open %s" % outfile
- else:
- print "Crap. Couldn't lock %s" % outfile
- unlock(outfile, lockfd)
deleted file mode 100755
--- a/mozhghooks/single_head_per_branch.py
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright (C) 2010 Mozilla Foundation
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-def hook(ui, repo, **kwargs):
- for b in repo.branchtags():
- if len(repo.branchheads(b)) > 1:
- print "\n\n************************** ERROR ****************************"
- print "Two heads detected on branch '%s'" % b
- print "Only one head per branch is allowed!"
- print "*************************************************************\n\n"
- return 1
- return 0
deleted file mode 100644
--- a/mozhghooks/treeclosure.py
+++ /dev/null
@@ -1,66 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright (C) 2012 Mozilla Foundation
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-from urllib2 import urlopen
-import os.path
-import re
-import json
-
-magicwords = "CLOSED TREE"
-
-treestatus_base_url = "https://treestatus.mozilla.org"
-
-def printError(message):
- print "\n\n************************** ERROR ****************************"
- print message
- print "*************************************************************\n\n"
-
-def hook(ui, repo, **kwargs):
- name = os.path.basename(repo.root)
- url = "%s/%s?format=json" % (treestatus_base_url, name)
- try:
- u = urlopen(url)
- data = json.load(u)
- if data['status'] == 'closed':
- print "Tree %s is CLOSED! (%s) - %s" % (name, url, data['reason'])
-
- # Block the push unless they know the magic words
- if repo.changectx('tip').description().find(magicwords) == -1:
- printError("To push despite the closed tree, include \"%s\" in your push comment" % magicwords)
- return 1
-
- print "But you included the magic words. Hope you had permission!"
- return 0
- elif data['status'] == 'approval required':
- # Block the push unless they have approval or are backing out
- dlower = repo.changectx('tip').description().lower()
- if re.search('a\S*=', dlower) or dlower.startswith('back') or dlower.startswith('revert'):
- return 0
-
- printError("Pushing to an APPROVAL REQUIRED tree requires your top changeset comment to include: a=... (or, more accurately, a\\S*=...)")
- return 1
-
- except (ValueError, IOError), (err):
- # fail closed if treestatus is down, unless the magic words have been used
- printError("Error accessing %s :\n"
- "%s\n"
- "Unable to check if the tree is open - treating as if CLOSED.\n"
- "To push regardless, include \"%s\" in your push comment." % (url, err, magicwords))
- if repo.changectx('tip').description().find(magicwords) == -1:
- return 1
- return 0
deleted file mode 100644
--- a/mozhghooks/treeclosure_comm_central.py
+++ /dev/null
@@ -1,136 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright (C) 2013 Mozilla Foundation
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-from urllib2 import urlopen
-import os.path
-import re
-import json
-
-# Array of which directories SeaMonkey exclusively controls in comm-central
-seamonkeyOwns = [
- 'suite'
-]
-# Array of which directories Instantbird exclusively controls in comm-central
-instantbirdOwns = [
- 'im'
-]
-# Everything else is assumed to be controlled by Thunderbird.
-
-magicwords = "CLOSED TREE"
-
-treestatus_base_url = "https://treestatus.mozilla.org"
-
-def printError(message):
- print "\n\n************************** ERROR ****************************"
- print message
- print "*************************************************************\n\n"
-
-# This function actually does the checking to see if a tree is closed or set
-# to approval required.
-def checkJsonTreeState(repo, repoName, appName):
- name = os.path.basename(repo.root)
- url = "%s/%s-%s?format=json" % (treestatus_base_url, name, appName)
- try:
- u = urlopen(url)
- data = json.load(u)
-
- if data['status'] == 'closed':
- # The tree is closed
-
- # Tell the pusher
- print "Tree %s %s is CLOSED!" % (appName.capitalize(), name)
- print repo.changectx('tip').description()
-
- # Block the push if no magic words
- if repo.changectx('tip').description().find(magicwords) == -1:
- printError("To push despite the closed tree, include \"%s\" in your push comment" % magicwords)
- return 1
-
- # Otherwise let them push
- print "But you included the magic words. Hope you had permission!"
- return 0
-
- elif data['status'] == 'approval required':
- # The tree needs approval
-
- # If they've specified an approval or are backing out, let them push
- dlower = repo.changectx('tip').description().lower()
- if re.search('a\S*=', dlower) or dlower.startswith('back') or dlower.startswith('revert'):
- return 0
-
- # Otherwise tell them about the rule
- printError("Pushing to an APPROVAL REQUIRED tree requires your top changeset comment to include: a=... (or, more accurately, a\\S*=...)")
- return 1
-
- except (ValueError, IOError), (err):
- # fail closed if treestatus is down, unless the magic words have been used
- printError("Error accessing %s :\n"
- "%s\n"
- "Unable to check if the tree is open - treating as if CLOSED.\n"
- "To push regardless, include \"%s\" in your push comment." % (url, err, magicwords))
- if repo.changectx('tip').description().find(magicwords) == -1:
- return 1
-
- # By default the tree is open
- return 0
-
-
-def isOwned(changedFile, ownerArray):
- for dir in ownerArray:
- if os.path.commonprefix([changedFile, dir]) == dir:
- return True
-
- return False
-
-def hook(ui, repo, node, **kwargs):
- try:
- # First find out which trees are affected
- apps = { 'thunderbird' : False,
- 'seamonkey' : False }
-
- # all changesets from node to 'tip' inclusive are part of this push
- rev = repo.changectx(node).rev()
- tip = repo.changectx('tip').rev()
- for i in range(rev, tip+1):
- ctx = repo.changectx(i)
- for changedFile in ctx.files():
- if isOwned(changedFile, seamonkeyOwns):
- apps['seamonkey'] = True
- elif isOwned(changedFile, instantbirdOwns):
- pass # ignore Instantbird for tree closure reasons
- else:
- apps['thunderbird'] = True
-
- repoName = os.path.basename(repo.root)
- status = 0
-
- for app in apps:
- if apps[app]:
- status = checkJsonTreeState(repo, repoName, app)
- if status == 1:
- return 1
-
- return status;
-
- except IOError, (err):
- #TODO: Below obsolete?
- # fail open, I guess. no sense making hg unavailable
- # if the wiki is down
- print "IOError: %s" % err
- pass
- return 0
deleted file mode 100755
--- a/mozhghooks/try_mandatory.py
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/usr/bin/env python
-
-chooserUrl = 'http://trychooser.pub.build.mozilla.org/'
-infoUrl = 'https://wiki.mozilla.org/Build:TryChooser'
-
-def printError(message):
- print "\n\n************************** ERROR ****************************"
- print message
- print "*************************************************************\n\n"
-
-def hook(ui, repo, **kwargs):
- # Block the push unless they use the try_syntax
- # 'try: ' is enough to activate try_parser and get the default set
- comment = repo.changectx('tip').description()
- info = { 'chooserUrl': chooserUrl, 'infoUrl': infoUrl }
- if "try: " not in comment:
- printError("""To push to try you must use try syntax in the push comment of the *last* change
-See %(chooserUrl)s to build your syntax
-For assistance using the syntax, see %(infoUrl)s.
-Thank you for helping to reduce CPU cyles by asking for exactly what you need.""" % info)
- return 1
- elif "-p none" in comment:
- printError("""Your try syntax contains '-p none', which would not trigger any jobs.
-Please try try again. If you *intended* to push without triggering
-any jobs, use -p any_invalid_syntax. For assistance with try server
-syntax, see %(infoUrl)s.""" % info)
- return 1
- else:
- print """Looks like you used try syntax, going ahead with the push.
-If you don't get what you expected, check %(chooserUrl)s
-for help with building your trychooser request.
-Thanks for helping save resources, you're the best!""" % info
- return 0
deleted file mode 100644
--- a/mozhghooks/whitelist_qa.py
+++ /dev/null
@@ -1,42 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright (C) 2010 Mozilla Foundation
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
-# USA.
-
-# This script implements a whitelist containing people from the QA team (plus
-# Dustin)
-#
-# run `python setup.py install` to install the module in the proper place,
-# and then modify the repository's hgrc as per example-hgrc.
-
-import os
-
-ALLOWED_USERS = set([
- 'dmitchell@mozilla.com',
- 'hskupin@mozilla.com',
-])
-
-
-def hook(ui, repo, node=None, **kwargs):
- rev = repo[node].rev()
- tip = repo['tip'].rev()
- branches = set(repo.changectx(i).branch() for i in range(rev, tip + 1))
- if 'production' in branches and os.environ['USER'] not in ALLOWED_USERS:
- print "** you (%s) are not allowed to push to the production branch" \
- % (os.environ['USER'],)
- return 1
- return 0
deleted file mode 100644
--- a/mozhghooks/whitelist_releng.py
+++ /dev/null
@@ -1,62 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright (C) 2010 Mozilla Foundation
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
-# USA.
-
-# This script implements a whitelist containing people from the releng and
-# relops teams.
-#
-# run `python setup.py install` to install the module in the proper place,
-# and then modify the repository's hgrc as per example-hgrc.
-
-import os
-
-ALLOWED_USERS = set([
- 'Callek@gmail.com',
- 'arich@mozilla.com',
- 'armenzg@mozilla.com',
- 'asasaki@mozilla.com',
- 'bhearsum@mozilla.com',
- 'catlee@mozilla.com',
- 'coop@mozilla.com',
- 'dmitchell@mozilla.com',
- 'hwine@mozilla.com',
- 'jlund@mozilla.com',
- 'jozeller@mozilla.com',
- 'jwatkins@mozilla.com',
- 'jwood@mozilla.com',
- 'kmoir@mozilla.com',
- 'mcornmesser@mozilla.com',
- 'mgervasini@mozilla.com',
- 'mshal@mozilla.com',
- 'nthomas@mozilla.com',
- 'pmoore@mozilla.com',
- 'qfortier@mozilla.com',
- 'raliiev@mozilla.com',
- 'sbruno@mozilla.com',
-])
-
-
-def hook(ui, repo, node=None, **kwargs):
- rev = repo[node].rev()
- tip = repo['tip'].rev()
- branches = set(repo.changectx(i).branch() for i in range(rev, tip + 1))
- if 'production' in branches and os.environ['USER'] not in ALLOWED_USERS:
- print "** you (%s) are not allowed to push to the production branch" \
- % (os.environ['USER'],)
- return 1
- return 0
deleted file mode 100755
--- a/runtests.py
+++ /dev/null
@@ -1,1003 +0,0 @@
-#!/usr/bin/env python
-
-from __future__ import with_statement
-import unittest
-from mercurial import ui, hg, commands, util
-from mercurial.commands import add, clone, commit, init, push, rename, remove, update, merge
-from mercurial.node import hex, short
-from tempfile import mkdtemp, mkstemp
-import shutil
-import os, stat
-from os.path import join, exists
-import sqlite3 as sqlite
-from getpass import getuser
-from time import time
-import urllib2
-from StringIO import StringIO
-
-def addHook(repodir, hook):
- with open(join(repodir, '.hg', 'hgrc'), 'w') as f:
- f.write("""[hooks]
-pretxnchangegroup.z_linearhistory = python:mozhghooks.%s
-""" % hook)
-
-def appendFile(filename, content):
- try:
- os.makedirs(os.path.dirname(filename))
- except:
- pass
- with open(filename, 'a') as f:
- f.write(content)
-
-def removeFromFile(filename, content):
- try:
- os.makedirs(os.path.dirname(filename))
- except:
- pass
- newlines = []
- with open(filename, 'r') as f:
- lines = f.readlines()
- for line in lines:
- if line != content:
- newlines.append(line)
- with open(filename, 'a') as f:
- f.write(''.join(newlines))
-
-def editFile(filename, original, updated):
- try:
- os.makedirs(os.path.dirname(filename))
- except:
- pass
- newlines = []
- with open(filename, 'r') as f:
- lines = f.readlines()
- for line in lines:
- if line == original:
- newlines.append(updated)
- else:
- newlines.append(line)
- with open(filename, 'a') as f:
- f.write(''.join(newlines))
-
-def getPushesFromDB(repo):
- conn = sqlite.connect(join(repo.root, '.hg', 'pushlog2.db'))
- res = conn.execute("SELECT id, user, date, rev, node from pushlog INNER JOIN changesets on pushlog.id = changesets.pushid ORDER BY id")
- s = set()
- pushes = []
- for row in res.fetchall():
- if row[0] not in s:
- pushes.append({'id':row[0],
- 'user':row[1],
- 'date':row[2],
- 'changes':[]})
- s.add(row[0])
- pushes[-1]['changes'].append({'rev':row[3], 'node':row[4]})
- return pushes
-
-class TestPushlogHook(unittest.TestCase):
- def setUp(self):
- self.ui = ui.ui()
- self.ui.quiet = True
- self.ui.verbose = False
- self.repodir = mkdtemp(prefix="hg-test")
- init(self.ui, dest=self.repodir)
- addHook(self.repodir, "pushlog.log")
- self.repo = hg.repository(self.ui, self.repodir)
- self.clonedir = mkdtemp(prefix="hg-test")
- clone(self.ui, self.repo, self.clonedir)
- self.clonerepo = hg.repository(self.ui, self.clonedir)
-
- def tearDown(self):
- shutil.rmtree(self.repodir)
- shutil.rmtree(self.clonedir)
-
- def testBasic(self):
- """Push one changeset, sanity check all the data."""
- u = self.ui
- appendFile(join(self.clonedir, "testfile"), "checkin 1")
- add(u, self.clonerepo, join(self.clonedir, "testfile"))
- commit(u, self.clonerepo, message="checkin 1 bug 12345")
- start = time()
- push(u, self.clonerepo, dest=self.repodir)
- end = time()
- p = getPushesFromDB(self.repo)
- self.assertEqual(len(p), 1)
- self.assertEqual(len(p[0]['changes']), 1)
- self.assertEqual(p[0]['user'], getuser())
- # tough to assert exactly
- self.assert_(p[0]['date'] >= int(start))
- self.assert_(p[0]['date'] <= int(end))
- c = p[0]['changes'][0]
- tip = self.clonerepo.changectx('tip')
- self.assertEqual(c['rev'], tip.rev())
- self.assertEqual(c['node'], hex(tip.node()))
-
- def testTwoPushes(self):
- """Push two changesets in two pushes, sanity check all the data."""
- u = self.ui
- appendFile(join(self.clonedir, "testfile"), "checkin 1")
- add(u, self.clonerepo, join(self.clonedir, "testfile"))
- commit(u, self.clonerepo, message="checkin 1 bug 12345")
- push(u, self.clonerepo, dest=self.repodir)
-
- appendFile(join(self.clonedir, "testfile"), "checkin 2")
- commit(u, self.clonerepo, message="checkin 2 bug 23456")
- push(u, self.clonerepo, dest=self.repodir)
-
- pushes = getPushesFromDB(self.repo)
- self.assertEqual(len(pushes), 2)
- self.assert_(all(len(p['changes']) == 1 for p in pushes))
- self.assert_(all(p['user'] == getuser() for p in pushes))
- self.assert_(pushes[0]['date'] <= pushes[1]['date'])
- self.assert_(pushes[0]['changes'][0]['rev'] <= pushes[1]['changes'][0]['rev'])
- # check that all the node/rev pairs we recorded match what hg thinks
- self.assert_(all(self.clonerepo.changectx(c['node']).rev() == c['rev'] for p in pushes for c in p['changes']))
-
- def testTwoChangesOnePush(self):
- """Push two changesets in one push, sanity check all the data."""
- u = self.ui
- appendFile(join(self.clonedir, "testfile"), "checkin 1")
- add(u, self.clonerepo, join(self.clonedir, "testfile"))
- commit(u, self.clonerepo, message="checkin 1 bug 12345")
- appendFile(join(self.clonedir, "testfile"), "checkin 2")
- commit(u, self.clonerepo, message="checkin 2 bug 23456")
- start = time()
- push(u, self.clonerepo, dest=self.repodir)
- end = time()
-
- pushes = getPushesFromDB(self.repo)
- self.assertEqual(len(pushes), 1)
- p = pushes[0]
- self.assertEqual(len(p['changes']), 2)
- self.assertEqual(p['user'], getuser())
- self.assert_(p['date'] >= int(start))
- self.assert_(p['date'] <= int(end))
- self.assert_(p['changes'][0]['rev'] <= p['changes'][1]['rev'])
- # check that all the node/rev pairs we recorded match what hg thinks
- self.assert_(all(self.clonerepo.changectx(c['node']).rev() == c['rev'] for c in p['changes']))
-
- def testPushlogPermissions(self):
- """Check that the pushlog db is group writable after pushing."""
- u = self.ui
- appendFile(join(self.clonedir, "testfile"), "checkin 1")
- add(u, self.clonerepo, join(self.clonedir, "testfile"))
- commit(u, self.clonerepo, message="checkin 1 bug 12345")
- push(u, self.clonerepo, dest=self.repodir)
-
- st = os.stat(join(self.repodir, ".hg", "pushlog2.db"))
- self.assertEqual(st.st_mode & stat.S_IWGRP, stat.S_IWGRP)
-
- def testEmptyDB(self):
- """bug 466149 - Check that pushing to a db without a schema succeeds."""
- u = self.ui
- # empty the db file
- with open(join(self.repodir, ".hg", "pushlog2.db"), 'w') as f:
- pass
- appendFile(join(self.clonedir, "testfile"), "checkin 1")
- add(u, self.clonerepo, join(self.clonedir, "testfile"))
- commit(u, self.clonerepo, message="checkin 1 bug 12345")
- push(u, self.clonerepo, dest=self.repodir)
-
- p = getPushesFromDB(self.repo)
- self.assertEqual(len(p), 1)
- self.assertEqual(len(p[0]['changes']), 1)
-
- def testDBLocking(self):
- """bug 508863 - Lock the DB and try to push, check that the error doesn't suck so much."""
- u = self.ui
- appendFile(join(self.clonedir, "testfile"), "checkin 1")
- add(u, self.clonerepo, join(self.clonedir, "testfile"))
- commit(u, self.clonerepo, message="checkin 1 bug 12345")
- push(u, self.clonerepo, dest=self.repodir)
-
- # open the repo and insert something to lock it
- conn = sqlite.connect(join(self.repo.root, '.hg', 'pushlog2.db'))
- conn.execute("INSERT INTO pushlog (user, date) VALUES('user', 0)")
-
- appendFile(join(self.clonedir, "testfile"), "checkin 2")
- commit(u, self.clonerepo, message="checkin 2 bug 23456")
- sawError = False
- #TODO: would be nice if we could lower the timeout
- self.assertRaises(util.Abort, push, u, self.clonerepo, dest=self.repodir)
- conn.commit()
- # this one should succeed
- push(u, self.clonerepo, dest=self.repodir)
- conn.close()
-
-class ClosureHookTestHelpers:
- """A mixin that provides a director class so we can intercept urlopen and
- change the result for our tests."""
- def setUp(self):
- # add a urllib OpenerDirector so we can intercept urlopen
- class MyDirector:
- expected = []
- opened = 0
- def open(self, url, data=None, timeout=None):
- expectedURL, sendData = self.expected.pop()
- """
- If this is ever changed so that more than one url are allowed, then
- the comm-central tests must be re-evaluated as they currently rely
- on it.
- """
- if expectedURL != url:
- raise Exception("Incorrect URL, got %s expected %s!" % (url, expectedURL))
- self.opened += 1
- return StringIO(sendData)
- def expect(self, url, data):
- """
- Indicate that the next url opened should be |url|, and should return
- |data| as its contents.
- """
- self.expected.append((url, data))
- self.director = MyDirector()
- urllib2.install_opener(self.director)
-
- def tearDown(self):
- urllib2.install_opener(urllib2.OpenerDirector())
-
- def redirect(self, url, data):
- self.director.expect(url, data)
-
-class TestTreeClosureHook(ClosureHookTestHelpers, unittest.TestCase):
- def setUp(self):
- self.ui = ui.ui()
- self.ui.quiet = True
- self.ui.verbose = False
- self.repodirbase = mkdtemp(prefix="hg-test")
- #XXX: sucks, but tests can rename it if they'd like to test something else
- self.repodir = join(self.repodirbase, "mozilla-central")
- init(self.ui, dest=self.repodir)
- addHook(self.repodir, "treeclosure.hook")
- self.repo = hg.repository(self.ui, self.repodir)
- self.clonedir = mkdtemp(prefix="hg-test")
- clone(self.ui, self.repo, self.clonedir)
- self.clonerepo = hg.repository(self.ui, self.clonedir)
- ClosureHookTestHelpers.setUp(self)
-
- def tearDown(self):
- shutil.rmtree(self.repodirbase)
- shutil.rmtree(self.clonedir)
- ClosureHookTestHelpers.tearDown(self)
-
- def testOpen(self):
- """Pushing to an OPEN tree should succeed."""
- self.redirect("https://treestatus.mozilla.org/mozilla-central?format=json",
- '{"status": "open", "reason": null}')
-
- # pushing something should now succeed
- u = self.ui
- appendFile(join(self.clonedir, "testfile"), "checkin 1")
- add(u, self.clonerepo, join(self.clonedir, "testfile"))
- commit(u, self.clonerepo, message="checkin 1")
- push(u, self.clonerepo, dest=self.repodir)
- self.assertEqual(self.director.opened, 1)
-
- def testClosed(self):
- """Pushing to a CLOSED tree should fail."""
- self.redirect("https://treestatus.mozilla.org/mozilla-central?format=json",
- '{"status": "closed", "reason": "splines won\'t reticulate"}')
- # pushing something should now fail
- u = self.ui
- appendFile(join(self.clonedir, "testfile"), "checkin 1")
- add(u, self.clonerepo, join(self.clonedir, "testfile"))
- commit(u, self.clonerepo, message="checkin 1")
- self.assertRaises(util.Abort, push, u, self.clonerepo, dest=self.repodir)
- self.assertEqual(self.director.opened, 1)
-
- def testClosedMagicWords(self):
- """
- Pushing to a CLOSED tree with 'CLOSED TREE' in the commit message
- should succeed.
- """
- self.redirect("https://treestatus.mozilla.org/mozilla-central?format=json",
- '{"status": "closed", "reason": "too many widgets"}')
- u = self.ui
- appendFile(join(self.clonedir, "testfile"), "checkin 1")
- add(u, self.clonerepo, join(self.clonedir, "testfile"))
- commit(u, self.clonerepo, message="checkin 1 CLOSED TREE")
- push(u, self.clonerepo, dest=self.repodir)
- self.assertEqual(self.director.opened, 1)
-
- def testClosedMagicWordsTip(self):
- """
- Pushing multiple changesets to a CLOSED tree with 'CLOSED TREE'
- in the commit message of the tip changeset should succeed.
- """
- self.redirect("https://treestatus.mozilla.org/mozilla-central?format=json",
- '{"status": "closed", "reason": "the end of the world as we know it"}')
- u = self.ui
- appendFile(join(self.clonedir, "testfile"), "checkin 1")
- add(u, self.clonerepo, join(self.clonedir, "testfile"))
- commit(u, self.clonerepo, message="checkin 1")
- appendFile(join(self.clonedir, "testfile"), "checkin 2")
- commit(u, self.clonerepo, message="checkin 2 CLOSED TREE")
-
- push(u, self.clonerepo, dest=self.repodir)
- self.assertEqual(self.director.opened, 1)
-
- def testApprovalRequired(self):
- """Pushing to an APPROVAL REQUIRED tree should fail."""
- self.redirect("https://treestatus.mozilla.org/mozilla-central?format=json",
- '{"status": "approval required", "reason": "be verrrry careful"}')
- # pushing something should now fail
- u = self.ui
- appendFile(join(self.clonedir, "testfile"), "checkin 1")
- add(u, self.clonerepo, join(self.clonedir, "testfile"))
- commit(u, self.clonerepo, message="checkin 1")
- self.assertRaises(util.Abort, push, u, self.clonerepo, dest=self.repodir)
- self.assertEqual(self.director.opened, 1)
-
- def testApprovalRequiredMagicWords(self):
- """
- Pushing to an APPROVAL REQUIRED tree with a=foo
- in the commit message should succeed.
- """
- self.redirect("https://treestatus.mozilla.org/mozilla-central?format=json",
- '{"status": "approval required", "reason": "trees are fragile"}')
- u = self.ui
- appendFile(join(self.clonedir, "testfile"), "checkin 1")
- add(u, self.clonerepo, join(self.clonedir, "testfile"))
- commit(u, self.clonerepo, message="checkin 1 a=someone")
- push(u, self.clonerepo, dest=self.repodir)
- self.assertEqual(self.director.opened, 1)
-
- # also check that approval of the form a1.2=foo works
- self.redirect("https://treestatus.mozilla.org/mozilla-central?format=json",
- '{"status": "approval required", "reason": "like they\'re made of glass"}')
- appendFile(join(self.clonedir, "testfile"), "checkin 2")
- commit(u, self.clonerepo, message="checkin 2 a1.2=someone")
- push(u, self.clonerepo, dest=self.repodir)
- self.assertEqual(self.director.opened, 2)
-
- def testApprovalRequiredMagicWordsTip(self):
- """
- Pushing to an APPROVAL REQUIRED tree with a=foo
- in the commit message of the tip changeset should succeed.
- """
- self.redirect("https://treestatus.mozilla.org/mozilla-central?format=json",
- '{"status": "approval required", "reason": "stained glass"}')
- u = self.ui
- appendFile(join(self.clonedir, "testfile"), "checkin 1")
- add(u, self.clonerepo, join(self.clonedir, "testfile"))
- commit(u, self.clonerepo, message="checkin 1")
- appendFile(join(self.clonedir, "testfile"), "checkin 1")
- commit(u, self.clonerepo, message="checkin 2 a=someone")
-
- push(u, self.clonerepo, dest=self.repodir)
- self.assertEqual(self.director.opened, 1)
-
-class TestTreeCommCentralClosureHook(ClosureHookTestHelpers, unittest.TestCase):
- def setUp(self):
- self.ui = ui.ui()
- self.ui.quiet = True
- self.ui.verbose = False
- self.repodirbase = mkdtemp(prefix="hg-test")
- #XXX: sucks, but tests can rename it if they'd like to test something else
- self.repodir = join(self.repodirbase, "comm-central")
- init(self.ui, dest=self.repodir)
- addHook(self.repodir, "treeclosure_comm_central.hook")
- self.repo = hg.repository(self.ui, self.repodir)
- self.clonedir = mkdtemp(prefix="hg-test")
- clone(self.ui, self.repo, self.clonedir)
- self.clonerepo = hg.repository(self.ui, self.clonedir)
- ClosureHookTestHelpers.setUp(self)
-
- def tearDown(self):
- shutil.rmtree(self.repodirbase)
- shutil.rmtree(self.clonedir)
- ClosureHookTestHelpers.tearDown(self)
-
- def actualTestCCOpen(self, treeName, fileInfo):
- """Pushing to an OPEN CC tree should succeed."""
- # If this tests attempts to pull something that isn't treeName, then the
- # re-director should fail for us. Hence we know that the hook is only
- # pulling the predefined tree and nothing else.
- self.redirect("https://treestatus.mozilla.org/comm-central-" + treeName.lower() + "?format=json",
- '{"status": "open", "reason": null}')
-
- # pushing something should now succeed
- u = self.ui
-
- fileName = fileInfo.pop()
- fileLoc = self.clonedir
- for dir in fileInfo:
- fileLoc = join(fileLoc, dir)
- os.mkdir(fileLoc)
-
- fileLoc = join(fileLoc, fileName)
-
- appendFile(fileLoc, "checkin 1")
- add(u, self.clonerepo, fileLoc)
- commit(u, self.clonerepo, message="checkin 1")
- push(u, self.clonerepo, dest=self.repodir)
- self.assertEqual(self.director.opened, 1)
-
-
- def testCCOpenThunderbird(self):
- self.actualTestCCOpen("Thunderbird", ["testfile"])
-
- def testCCOpenSeaMonkey(self):
- self.actualTestCCOpen("SeaMonkey", ["suite", "build", "test"])
-
- def testCCOpenCalendar(self):
- # Calendar is now built alongside Thunderbird
- self.actualTestCCOpen("Thunderbird", ["calendar", "app", "test"])
-
- def actualTestCCClosed(self, treeName, fileInfo):
- """Pushing to a CLOSED CC tree should fail."""
- # If this tests attempts to pull something that isn't treeName, then the
- # re-director should fail for us. Hence we know that the hook is only
- # pulling the predefined tree and nothing else.
- self.redirect("https://treestatus.mozilla.org/comm-central-" + treeName.lower() + "?format=json",
- '{"status": "closed", "reason": null}')
-
- # pushing something should now fail
- u = self.ui
-
- fileName = fileInfo.pop()
- fileLoc = self.clonedir
- for dir in fileInfo:
- fileLoc = join(fileLoc, dir)
- os.mkdir(fileLoc)
-
- fileLoc = join(fileLoc, fileName)
-
- appendFile(fileLoc, "checkin 1")
- add(u, self.clonerepo, fileLoc)
- commit(u, self.clonerepo, message="checkin 1")
- self.assertRaises(util.Abort, push, u, self.clonerepo, dest=self.repodir)
- self.assertEqual(self.director.opened, 1)
-
- def testCCClosedThunderbird(self):
- self.actualTestCCClosed("Thunderbird", ["testfile"])
-
- def testCCClosedSeaMonkey(self):
- self.actualTestCCClosed("SeaMonkey", ["suite", "build", "test"])
-
- def testCCClosedCalendar(self):
- # Calendar is now built alongside Thunderbird
- self.actualTestCCClosed("Thunderbird", ["calendar", "app", "test"])
-
- # In theory adding CLOSED TREE is the same code-path for all projects,
- # so just checking for one project
- def testCCClosedThunderbirdMagicWords(self):
- """
- Pushing to a CLOSED Thunderbird tree with 'CLOSED TREE' in the commit message
- should succeed.
- """
- self.redirect("https://treestatus.mozilla.org/comm-central-thunderbird?format=json",
- '{"status": "closed", "reason": null}')
- u = self.ui
- appendFile(join(self.clonedir, "testfile"), "checkin 1")
- add(u, self.clonerepo, join(self.clonedir, "testfile"))
- commit(u, self.clonerepo, message="checkin 1 CLOSED TREE")
- push(u, self.clonerepo, dest=self.repodir)
- self.assertEqual(self.director.opened, 1)
-
- # In theory adding CLOSED TREE is the same code-path for all projects,
- # so just checking for one project
- def testCCClosedThunderbirdMagicWordsTip(self):
- """
- Pushing multiple changesets to a CLOSED Thunderbird tree with 'CLOSED TREE'
- in the commit message of the tip changeset should succeed.
- """
- self.redirect("https://treestatus.mozilla.org/comm-central-thunderbird?format=json",
- '{"status": "closed", "reason": null}')
- u = self.ui
- appendFile(join(self.clonedir, "testfile"), "checkin 1")
- add(u, self.clonerepo, join(self.clonedir, "testfile"))
- commit(u, self.clonerepo, message="checkin 1")
- appendFile(join(self.clonedir, "testfile"), "checkin 2")
- commit(u, self.clonerepo, message="checkin 2 CLOSED TREE")
-
- push(u, self.clonerepo, dest=self.repodir)
- self.assertEqual(self.director.opened, 1)
-
- def testCCApprovalRequired(self):
- """Pushing to an APPROVAL REQUIRED tree should fail."""
- self.redirect("https://treestatus.mozilla.org/comm-central-thunderbird?format=json",
- '{"status": "approval required", "reason": null}')
- # pushing something should now fail
- u = self.ui
- appendFile(join(self.clonedir, "testfile"), "checkin 1")
- add(u, self.clonerepo, join(self.clonedir, "testfile"))
- commit(u, self.clonerepo, message="checkin 1")
- self.assertRaises(util.Abort, push, u, self.clonerepo, dest=self.repodir)
- self.assertEqual(self.director.opened, 1)
-
- def testCCApprovalRequiredMagicWords(self):
- """
- Pushing to an APPROVAL REQUIRED tree with a=foo
- in the commit message should succeed.
- """
- self.redirect("https://treestatus.mozilla.org/comm-central-thunderbird?format=json",
- '{"status": "approval required", "reason": null}')
- u = self.ui
- appendFile(join(self.clonedir, "testfile"), "checkin 1")
- add(u, self.clonerepo, join(self.clonedir, "testfile"))
- commit(u, self.clonerepo, message="checkin 1 a=someone")
- push(u, self.clonerepo, dest=self.repodir)
- self.assertEqual(self.director.opened, 1)
-
- # also check that approval of the form a1.2=foo works
- self.redirect("https://treestatus.mozilla.org/comm-central-thunderbird?format=json",
- '{"status": "approval required", "reason": null}')
- appendFile(join(self.clonedir, "testfile"), "checkin 2")
- commit(u, self.clonerepo, message="checkin 2 a1.2=someone")
- push(u, self.clonerepo, dest=self.repodir)
- self.assertEqual(self.director.opened, 2)
-
- def testCCApprovalRequiredMagicWordsTip(self):
- """
- Pushing to an APPROVAL REQUIRED tree with a=foo
- in the commit message of the tip changeset should succeed.
- """
- self.redirect("https://treestatus.mozilla.org/comm-central-thunderbird?format=json",
- '{"status": "approval required", "reason": null}')
- u = self.ui
- appendFile(join(self.clonedir, "testfile"), "checkin 1")
- add(u, self.clonerepo, join(self.clonedir, "testfile"))
- commit(u, self.clonerepo, message="checkin 1")
- appendFile(join(self.clonedir, "testfile"), "checkin 1")
- commit(u, self.clonerepo, message="checkin 2 a=someone")
-
- push(u, self.clonerepo, dest=self.repodir)
- self.assertEqual(self.director.opened, 1)
-
-class TestTryMandatoryHook(ClosureHookTestHelpers, unittest.TestCase):
- def setUp(self):
- self.ui = ui.ui()
- self.ui.quiet = True
- self.ui.verbose = False
- self.repodir = mkdtemp(prefix="hg-test")
- init(self.ui, dest=self.repodir)
- addHook(self.repodir, "try_mandatory.hook")
- self.repo = hg.repository(self.ui, self.repodir)
- self.clonedir = mkdtemp(prefix="hg-test")
- clone(self.ui, self.repo, self.clonedir)
- self.clonerepo = hg.repository(self.ui, self.clonedir)
- ClosureHookTestHelpers.setUp(self)
-
- def tearDown(self):
- shutil.rmtree(self.repodir)
- shutil.rmtree(self.clonedir)
- ClosureHookTestHelpers.tearDown(self)
-
- def testWithoutTrySyntax(self):
- """Push one changeset, without using the try syntax should error."""
- u = self.ui
- appendFile(join(self.clonedir, "testfile"), "checkin 1")
- add(u, self.clonerepo, join(self.clonedir, "testfile"))
- commit(u, self.clonerepo, message="checkin 1 bug 12345")
- self.assertRaises(util.Abort, push, u, self.clonerepo, dest=self.repodir)
-
- def testWithTrySyntax(self):
- """Push one changeset, with using the try syntax should succeed."""
- u = self.ui
- appendFile(join(self.clonedir, "testfile"), "checkin 1")
- add(u, self.clonerepo, join(self.clonedir, "testfile"))
- commit(u, self.clonerepo, message="checkin 1 try: -b do -p all")
- result = push(u, self.clonerepo, dest=self.repodir)
- self.assertEqual(result, 0)
-
-class TestCommitMessageHook(unittest.TestCase):
- def setUp(self):
- self.ui = ui.ui()
- self.ui.quiet = True
- self.ui.verbose = False
- self.repodir = mkdtemp(prefix="hg-TestCommitMessageHook")
- init(self.ui, dest=self.repodir)
- addHook(self.repodir, "commit-message.hook")
- self.repo = hg.repository(self.ui, self.repodir)
- self.clonedir = mkdtemp(prefix="hg-test")
- clone(self.ui, self.repo, self.clonedir)
- self.clonerepo = hg.repository(self.ui, self.clonedir)
-
- def tearDown(self):
- shutil.rmtree(self.repodir)
- shutil.rmtree(self.clonedir)
-
- def testWithBug(self):
- """ Every test should have bug # like "Bug 111", "Bug #111" or "b=111". """
-
- ui = self.ui
- messages = [
- "Bug 603517 - Enable mochitest to optionally run in loops without restarting the browser r=ctalbert",
- "Bug #123456 - add test",
- "b=630117, rename typed array slice() -> subset(); r=jwalden, a=block"
- "ARM assembler tweaks. (b=588021, r=cdleary)"
- ]
-
- appendFile(join(self.clonedir, "testfile"), "checkin 1")
- add(ui, self.clonerepo, join(self.clonedir, "testfile"))
- for message in messages:
- commit(ui, self.clonerepo, message=message)
-
- result = push(ui, self.clonerepo, dest=self.repodir)
- self.assertEqual(result, 0)
-
- def testBackout(self):
- """ Test different ways of spelling backout (and revert). """
-
- ui = self.ui
- messages = [
- "Backed out changeset 593d94e9492e",
- "Backout changesets 9e4ab3907b29, 3abc0dbbf710 due to m-oth permaorange",
- "Backout of 35a679df430b due to bustage",
- "backout 68941:5b8ade677818", # including the local numeric ID is silly but harmless
-
- # we do not have a lot of reverts "hg log | grep revert" without a bug #
- "Revert to changeset a87ee7550f6a due to incomplete backout"
- ]
-
- appendFile(join(self.clonedir, "testfile"), "checkin 1")
- add(ui, self.clonerepo, join(self.clonedir, "testfile"))
- for message in messages:
- commit(ui, self.clonerepo, message=message)
- result = push(ui, self.clonerepo, dest=self.repodir)
- self.assertEqual(result, 0)
-
- def testSpecial(self):
- """ Test some special stuff like "no bug", "add tag" or "update nanojit-import-rev stamp". """
-
- ui = self.ui
- messages = [
- "Added tag AURORA_BASE_20110412 for changeset a95d42642281",
- "Fix typo in comment within nsFrame.cpp (no bug) rs=dbaron DONTBUILD",
- "Fix ARM assert (no bug, r=cdleary).",
- "Backout 3b59c196aaf9 - no bug # in commit message"
- ]
-
- appendFile(join(self.clonedir, "testfile"), "checkin 1")
- add(ui, self.clonerepo, join(self.clonedir, "testfile"))
- for message in messages:
- commit(ui, self.clonerepo, message=message)
- result = push(ui, self.clonerepo, dest=self.repodir)
- self.assertEqual(result, 0)
-
- bad = [
- "Mass revert m-i to the last known good state",
- "update revision of Add-on SDK tests to latest tip; test-only",
- "Fix stupid bug in foo::bar()",
- "First line does not have a bug number\n\nbug 123456",
- "imported patch phishingfixes",
- "imported patch 441197-1",
- "Back out Dao's push because of build bustage",
- "Bump mozilla-central version numbers for the next release on a CLOSED TREE.",
- "Bump Sync version to 1.9.0. r=me",
- "checkin 1 try: -b do -p all"
- ]
-
- def testShouldFail(self):
- """ Some commit messages that should explicitly not pass anymore. """
-
- ui = self.ui
-
- appendFile(join(self.clonedir, "testfile"), "checkin 1")
- add(ui, self.clonerepo, join(self.clonedir, "testfile"))
-
- for message in self.bad:
- appendFile(join(self.clonedir, "testfile"), "checkin 1")
- commit(ui, self.clonerepo, message=message)
- print message
- self.assertRaises(util.Abort, push, ui, self.clonerepo, dest=self.repodir)
-
- def testIgnore(self):
- """ Test that IGNORE BAD COMMIT MESSAGES works """
- ui = self.ui
-
- appendFile(join(self.clonedir, "testfile"), "checkin 1")
- add(ui, self.clonerepo, join(self.clonedir, "testfile"))
-
- for message in self.bad:
- appendFile(join(self.clonedir, "testfile"), "checkin 1")
- commit(ui, self.clonerepo, message=message)
-
- appendFile(join(self.clonedir, "testfile"), "checkin 1")
- commit(ui, self.clonerepo, message="IGNORE BAD COMMIT MESSAGES")
-
- result = push(ui, self.clonerepo, dest=self.repodir)
- self.assertEqual(result, 0)
-
-class TestCaseOnlyRenameHook(unittest.TestCase):
- def setUp(self):
- self.ui = ui.ui()
- self.ui.quiet = True
- self.ui.verbose = False
- self.repodir = mkdtemp(prefix="hg-TestCaseOnlyRenameHook")
- init(self.ui, dest=self.repodir)
- addHook(self.repodir, "prevent_case_only_renames.hook")
- self.repo = hg.repository(self.ui, self.repodir)
- self.clonedir = mkdtemp(prefix="hg-test")
- clone(self.ui, self.repo, self.clonedir)
- self.clonerepo = hg.repository(self.ui, self.clonedir)
-
- def tearDown(self):
- shutil.rmtree(self.repodir)
- shutil.rmtree(self.clonedir)
-
- def testTipShouldFail(self):
- """ Test that a case-only rename in tip should fail. """
-
- ui = self.ui
-
- appendFile(join(self.clonedir, "testfile"), "checkin 1")
- add(ui, self.clonerepo, join(self.clonedir, "testfile"))
- commit(ui, self.clonerepo, message="checkin 1")
- rename(ui, self.clonerepo,
- join(self.clonedir, "testfile"),
- join(self.clonedir, "TESTFILE"));
- commit(ui, self.clonerepo, message="checkin 2")
- self.assertRaises(util.Abort, push, ui, self.clonerepo, dest=self.repodir)
-
- def testTipDirRenameShouldFail(self):
- """ Test that a case-only directory rename in tip should fail. """
-
- # Disable the test on case insensitive filesystems
- tmphandle, tmppath = mkstemp()
- if exists(tmppath.upper()):
- return
-
- ui = self.ui
-
- appendFile(join(self.clonedir, "testdir/testfile"), "checkin 1")
- add(ui, self.clonerepo, join(self.clonedir, "testdir/testfile"))
- commit(ui, self.clonerepo, message="checkin 1")
- rename(ui, self.clonerepo,
- join(self.clonedir, "testdir/testfile"),
- join(self.clonedir, "TESTDIR/testfile"));
- commit(ui, self.clonerepo, message="checkin 2")
- self.assertRaises(util.Abort, push, ui, self.clonerepo, dest=self.repodir)
-
- def testPreviousShouldFail(self):
- """ Test that a case-only rename that's not tip should fail. """
-
- ui = self.ui
-
- appendFile(join(self.clonedir, "testfile"), "checkin 1")
- add(ui, self.clonerepo, join(self.clonedir, "testfile"))
- commit(ui, self.clonerepo, message="checkin 1")
-
- rename(ui, self.clonerepo,
- join(self.clonedir, "testfile"),
- join(self.clonedir, "TESTFILE"));
- commit(ui, self.clonerepo, message="checkin 2")
-
- appendFile(join(self.clonedir, "TESTFILE"), "checkin 3")
- commit(ui, self.clonerepo, message="checkin 3")
-
- self.assertRaises(util.Abort, push, ui, self.clonerepo, dest=self.repodir)
-
-class TestPreventUUIDHook(unittest.TestCase):
- def setUp(self):
- self.ui = ui.ui()
- self.ui.quiet = True
- self.ui.verbose = False
- self.repodir = mkdtemp(prefix="hg-TestPreventUUIDHook")
- init(self.ui, dest=self.repodir)
- addHook(self.repodir, "prevent_uuid_changes.hook")
- self.repo = hg.repository(self.ui, self.repodir)
- self.clonedir = mkdtemp(prefix="hg-test")
- clone(self.ui, self.repo, self.clonedir)
- self.clonerepo = hg.repository(self.ui, self.clonedir)
- # Create a pre-existing repo with a file that contains UUID
- appendFile(join(self.clonedir, "original.idl"), "uuid(abc123)")
- add(self.ui, self.clonerepo, join(self.clonedir, "original.idl"))
- commit(self.ui, self.clonerepo, message="original repo commit ba=me")
- push(self.ui, self.clonerepo, dest=self.repodir)
- print "===== In method", self._testMethodName, " ======="
-
- def tearDown(self):
- shutil.rmtree(self.repodir)
- shutil.rmtree(self.clonedir)
-
- def testUUIDEditExistingShouldFail(self):
- """ Test that editing .idl file with 'uuid(' and no 'ba=' should fail """
- u = self.ui
- editFile(join(self.clonedir, "original.idl"), "uuid(abc123)", "uuid(def456)")
- commit(u, self.clonerepo, message="checkin 1 bug 12345")
- self.assertRaises(util.Abort, push, u, self.clonerepo, dest=self.repodir)
-
- def testUUIDEditExistingShouldPass(self):
- """ Test that editing .idl file with 'uuid(' with ba=... should pass """
- u = self.ui
- editFile(join(self.clonedir, "original.idl"), "uuid(abc123)", "uuid(def456)")
- commit(u, self.clonerepo, message="checkin 1 bug 12345 ba=me")
- result = push(u, self.clonerepo, dest=self.repodir)
- self.assertEqual(result, 0)
-
- def testUUIDMultiplePushShouldFail(self):
- """ Test that adding .idl file with uuid with other files and no 'ba=' should fail """
- u = self.ui
- appendFile(join(self.clonedir, "testfile1.idl"), "uuid(something here)")
- add(u, self.clonerepo, join(self.clonedir, "testfile1.idl"))
- commit(u, self.clonerepo, message="checkin 1 bug 12345")
- appendFile(join(self.clonedir, "testfile2.txt"), "checkin2")
- add(u, self.clonerepo, join(self.clonedir, "testfile2.txt"))
- commit(u, self.clonerepo, message="checkin 2 bug 12345")
- self.assertRaises(util.Abort, push, u, self.clonerepo, dest=self.repodir)
-
- def testUUIDMultiplePushShouldPass(self):
- """ Test that changeset with 'uuid(' change in .idl should pass if 'ba=...' is in the push comment """
- u = self.ui
- appendFile(join(self.clonedir, "testfile3.idl"), "uuid(something here)")
- add(u, self.clonerepo, join(self.clonedir, "testfile3.idl"))
- commit(u, self.clonerepo, message="checkin 3 bug 12345")
- appendFile(join(self.clonedir, "testfile2.txt"), "checkin2")
- add(u, self.clonerepo, join(self.clonedir, "testfile2.txt"))
- commit(u, self.clonerepo, message="checkin 2 bug 12345 ba=approver")
- result = push(u, self.clonerepo, dest=self.repodir)
- self.assertEqual(result, 0)
-
- def testUUIDNonIDLShouldPass(self):
- """ Test that changeset with 'uuid(' change in a file not ending in .idl should pass """
- u = self.ui
- appendFile(join(self.clonedir, "testfile1.txt"), "uuid(something here)")
- add(u, self.clonerepo, join(self.clonedir, "testfile1.txt"))
- commit(u, self.clonerepo, message="checkin 1 bug 12345")
- result = push(u, self.clonerepo, dest=self.repodir)
- self.assertEqual(result, 0)
-
- def testUUIDRemoveUUIDNoApprovalShouldFail(self):
- """ Test that changeset with 'uuid(' removed from file ending in .idl should fail """
- u = self.ui
- appendFile(join(self.clonedir, "original.idl"), "line of text")
- removeFromFile(join(self.clonedir, "original.idl"), "uuid(abc123)")
- commit(u, self.clonerepo, message="checkin removed uuid bug 12345")
- self.assertRaises(util.Abort, push, u, self.clonerepo, dest=self.repodir)
-
- def testUUIDRemoveUUIDWithApprovalShouldPass(self):
- """ Test that changeset with 'uuid(' removed from file ending in .idl should pass with ba=... """
- u = self.ui
- appendFile(join(self.clonedir, "original.idl"), "line of text")
- removeFromFile(join(self.clonedir, "original.idl"), "uuid(abc123)")
- commit(u, self.clonerepo, message="checkin removed uuid bug 12345 ba=me")
- result = push(u, self.clonerepo, dest=self.repodir)
- self.assertEqual(result, 0)
-
- def testUUIDDeletedIDLApproveShouldPass(self):
- """ Test that changeset with .idl file removed should pass with ba= approval """
- u = self.ui
- remove(u, self.clonerepo, join(self.clonedir, "original.idl"))
- commit(u, self.clonerepo, message="checkin 2 removed idl file ba=approver")
- result = push(u, self.clonerepo, dest=self.repodir)
- self.assertEqual(result, 0)
-
- def testUUIDDeletedIDLNoApproveShouldFail(self):
- """ Test that changeset with .idl file removed should fail without approval"""
- u = self.ui
- remove(u, self.clonerepo, join(self.clonedir, "original.idl"))
- commit(u, self.clonerepo, message="checkin 2 removed idl file ")
- self.assertRaises(util.Abort, push, u, self.clonerepo, dest=self.repodir)
-
-class TestPreventWebIDLHook(unittest.TestCase):
- def setUp(self):
- self.ui = ui.ui()
- self.ui.quiet = True
- self.ui.verbose = False
- self.repodir = mkdtemp(prefix="hg-TestPreventWebIDLHook")
- init(self.ui, dest=self.repodir)
- addHook(self.repodir, "prevent_webidl_changes.hook")
- self.repo = hg.repository(self.ui, self.repodir)
- self.clonedir = mkdtemp(prefix="hg-test")
- clone(self.ui, self.repo, self.clonedir)
- self.clonerepo = hg.repository(self.ui, self.clonedir)
- # Create a pre-existing repo with a file that contains UUID
- appendFile(join(self.clonedir, "original.webidl"), "interface Foo{};")
- add(self.ui, self.clonerepo, join(self.clonedir, "original.webidl"))
- appendFile(join(self.clonedir, "dummy"), "foo")
- add(self.ui, self.clonerepo, join(self.clonedir, "dummy"))
- commit(self.ui, self.clonerepo, message="original repo commit r=jst")
- push(self.ui, self.clonerepo, dest=self.repodir)
-
- def tearDown(self):
- shutil.rmtree(self.repodir)
- shutil.rmtree(self.clonedir)
-
- def testWebIDLEditWithoutReviewShouldFail(self):
- """ Test that editing .webidl file without review should fail """
- u = self.ui
- editFile(join(self.clonedir, "original.webidl"), "interface Foo{};", "interface Bar{};")
- commit(u, self.clonerepo, message="checkin 1 bug 12345")
- self.assertRaises(util.Abort, push, u, self.clonerepo, dest=self.repodir)
-
- def testWebIDLEditWithoutProperReviewShouldFail(self):
- """ Test that editing .webidl file without proper DOM peer review should fail """
- u = self.ui
- editFile(join(self.clonedir, "original.webidl"), "interface Foo{};", "interface Bar{};")
- commit(u, self.clonerepo, message="checkin 1 bug 12345; r=foobar")
- self.assertRaises(util.Abort, push, u, self.clonerepo, dest=self.repodir)
-
- def testWebIDLEditWithoutReviewFromDOMPeerShouldPass(self):
- """ Test that editing .webidl file by DOM peers without review should pass """
- u = self.ui
- editFile(join(self.clonedir, "original.webidl"), "interface Foo{};", "interface Bar{};")
- commit(u, self.clonerepo, message="checkin 1 bug 12345", user="Johnny Stenback <jst@mozilla.com>")
- result = push(u, self.clonerepo, dest=self.repodir)
- self.assertEqual(result, 0)
-
- def testWebIDLEditWithoutProperReviewInReleaseMergeShouldPass(self):
- """ Test that editing .webidl file without proper DOM peer review when doing a code uplift should pass """
- u = self.ui
- editFile(join(self.clonedir, "original.webidl"), "interface Foo{};", "interface Bar{};")
- commit(u, self.clonerepo, message="checkin 1 bug 12345; r=foobar")
- appendFile(join(self.clonedir, "dummy"), "foo")
- add(u, self.clonerepo, join(self.clonedir, "dummy"))
- commit(u, self.clonerepo, message="Doing the code uplift, a=release")
- result = push(u, self.clonerepo, dest=self.repodir)
- self.assertEqual(result, 0)
-
- def testWebIDLEditWithoutProperReviewInNonReleaseMergeButWithAEqualsReleaseShouldFail(self):
- """ Test that editing .webidl file without proper DOM peer review when doing a code uplift should pass """
- u = self.ui
- appendFile(join(self.clonedir, "dummy"), "foo")
- add(u, self.clonerepo, join(self.clonedir, "dummy"))
- commit(u, self.clonerepo, message="Doing the code uplift, a=release")
- editFile(join(self.clonedir, "original.webidl"), "interface Foo{};", "interface Bar{};")
- commit(u, self.clonerepo, message="checkin 1 bug 12345; r=foobar")
- self.assertRaises(util.Abort, push, u, self.clonerepo, dest=self.repodir)
-
- def testWebIDLEditWithProperReviewShouldPass(self):
- """ Test that editing .webidl file with proper DOM peer review should pass """
- u = self.ui
- editFile(join(self.clonedir, "original.webidl"), "interface Foo{};", "interface Bar{};")
- commit(u, self.clonerepo, message="checkin 1 bug 12345; r=foobar,jst")
- result = push(u, self.clonerepo, dest=self.repodir)
- self.assertEqual(result, 0)
- editFile(join(self.clonedir, "original.webidl"), "interface Bar{};", "interface Baz{};")
- commit(u, self.clonerepo, message="checkin 1 bug 67890; r=foobar r=jst")
- result = push(u, self.clonerepo, dest=self.repodir)
- self.assertEqual(result, 0)
- editFile(join(self.clonedir, "original.webidl"), "interface Baz{};", "interface Bizarre{};")
- commit(u, self.clonerepo, message="checkin 1 bug 123456; r=foobar r=lumpy,jst")
- result = push(u, self.clonerepo, dest=self.repodir)
- editFile(join(self.clonedir, "original.webidl"), "interface Bizarre{};", "interface Bar{};")
- commit(u, self.clonerepo, message="checkin 1 bug 123450; sr=foobar,jst")
- result = push(u, self.clonerepo, dest=self.repodir)
- self.assertEqual(result, 0)
- editFile(join(self.clonedir, "original.webidl"), "interface Bar{};", "interface Baz{};")
- commit(u, self.clonerepo, message="checkin 1 bug 678900; sr=foobar sr=jst")
- result = push(u, self.clonerepo, dest=self.repodir)
- self.assertEqual(result, 0)
- editFile(join(self.clonedir, "original.webidl"), "interface Baz{};", "interface Bizarre{};")
- commit(u, self.clonerepo, message="checkin 1 bug 1234560; sr=foobar sr=lumpy,jst")
- result = push(u, self.clonerepo, dest=self.repodir)
- self.assertEqual(result, 0)
-
- def testWebIDLEditWithProperReviewDuringMergeShouldPass(self):
- """ Test that editing .webidl file with proper DOM peer review should pass """
- u = self.ui
- parentrev = short(self.clonerepo.changectx('tip').node())
- editFile(join(self.clonedir, "original.webidl"), "interface Foo{};", "interface Bar{};")
- commit(u, self.clonerepo, message="checkin 1 bug 12345; r=foobar,jst")
- update(u, self.clonerepo, rev=parentrev)
- editFile(join(self.clonedir, "dummy"), "foo", "bar")
- commit(u, self.clonerepo, message="dummy")
- merge(u, self.clonerepo)
- commit(u, self.clonerepo, message="merge")
- result = push(u, self.clonerepo, dest=self.repodir)
- self.assertEqual(result, 0)
-
- def testWebIDLEditsInBackoutsWithoutProperReviewShouldPass(self):
- """ Test that editing .webidl file without proper DOM peer review in backouts should pass """
- u = self.ui
- # Copied from testBackout above.
- messages = [
- "Backed out changeset 593d94e9492e",
- "Backout changesets 9e4ab3907b29, 3abc0dbbf710 due to m-oth permaorange",
- "Backout of 35a679df430b due to bustage",
- "backout 68941:5b8ade677818", # including the local numeric ID is silly but harmless
- # we do not have a lot of reverts "hg log | grep revert" without a bug #
- "Revert to changeset a87ee7550f6a due to incomplete backout",
- "Backed out 7 changesets (bug 824717) for bustage."
- ]
- for message in messages:
- name = "new%d.webidl" % len(message)
- appendFile(join(self.clonedir, name), "interface Test{};")
- add(u, self.clonerepo, join(self.clonedir, name))
- commit(u, self.clonerepo, message=message)
- result = push(u, self.clonerepo, dest=self.repodir)
- self.assertEqual(result, 0)
-
-if __name__ == '__main__':
- unittest.main()
deleted file mode 100644
--- a/setup.py
+++ /dev/null
@@ -1,12 +0,0 @@
-# This is a distutils setup script for the mozhghooks module.
-# Install the module by running `python setup.py install`
-
-from distutils.core import setup
-
-setup(name="Mozilla Hg Hooks",
- version='0.1',
- description="Mozilla-specific hooks for Mercurial VCS",
- author="Ted Mielczarek",
- author_email="ted.mielczarek@gmail.com",
- packages=["mozhghooks"]
-)
deleted file mode 100755
--- a/tamarin-hook.py
+++ /dev/null
@@ -1,109 +0,0 @@
-#! /usr/bin/python
-# ***** BEGIN LICENSE BLOCK *****
-# Version: MPL 1.1/GPL 2.0/LGPL 2.1
-#
-# The contents of this file are subject to the Mozilla Public License Version
-# 1.1 (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-# http://www.mozilla.org/MPL/
-#
-# Software distributed under the License is distributed on an "AS IS" basis,
-# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
-# for the specific language governing rights and limitations under the
-# License.
-#
-# The Original Code is [Open Source Virtual Machine.].
-#
-# The Initial Developer of the Original Code is
-# Adobe System Incorporated.
-# Portions created by the Initial Developer are Copyright (C) 2010
-# the Initial Developer. All Rights Reserved.
-#
-# Contributor(s):
-# Adobe AS3 Team
-#
-# Alternatively, the contents of this file may be used under the terms of
-# either the GNU General Public License Version 2 or later (the "GPL"), or
-# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
-# in which case the provisions of the GPL or the LGPL are applicable instead
-# of those above. If you wish to allow use of your version of this file only
-# under the terms of either the GPL or the LGPL, and not to allow others to
-# use your version of this file under the terms of the MPL, indicate your
-# decision by deleting the provisions above and replace them with the notice
-# and other provisions required by the GPL or the LGPL. If you do not delete
-# the provisions above, a recipient may use your version of this file under
-# the terms of any one of the MPL, the GPL or the LGPL.
-#
-# ***** END LICENSE BLOCK ****
-#
-# Hook script used by tamarin team on tamarin-redux and tamarin-central.
-#
-# For documentation on hook scripts see:
-# http://hgbook.red-bean.com/read/handling-repository-events-with-hooks.html
-# http://mercurial.selenic.com/wiki/MercurialApi
-
-
-import sys, re
-from mercurial import hg, ui, commands, node
-
-
-# _quiet function from hghooklib by Johann Duscher
-# http://code.google.com/p/hghooklib/
-def _quiet(ui, fn):
- oldQuiet = ui.quiet
- ui.quiet = True
- result = fn()
- ui.quiet = oldQuiet
- return result
-
-def master_hook(ui, repo, **kwargs):
- ui.debug('running tamarin master_hook\n')
- ui.debug('kwargs: %s\n' % kwargs)
- # The mercurial hook script expects the equivalent of an exit code back from
- # this call:
- # False = 0 = No Error : allow push
- # True = 1 = Error : abort push
- error = False
- error = security_check(ui, repo, **kwargs) or error
- return error
-
-def security_check(ui, repo, **kwargs):
- ui.debug('running security_check\n')
- error = False
-
- ui.pushbuffer()
- _quiet(ui, lambda: commands.log(ui, repo, rev=['%s:tip' % kwargs['node']],
- template='{node}\n', date=None, user=None,
- logfile=None))
- nodes = ui.popbuffer().split('\n')
-
- # reenable this code if we need to blacklist a node
- for node in nodes:
- if node.startswith('8555e8551203') or node.startswith('e09bb3ece6c7'):
- ui.warn('blacklisted changeid found: node %s is blacklisted\n' % node)
- error = True # fail the push
-
- # Look for blacklisted bugs
- blacklist = [
- # Serrano
- 580489, 604354,
- # Wasabi
- 507624,
- # Cyril
- 570049, 628834,
- ]
-
- bugs = re.compile('(%s)' % '|'.join([str(bug) for bug in blacklist]))
-
- ui.pushbuffer()
- _quiet(ui, lambda: commands.log(ui, repo, rev=['%s:tip' % kwargs['node']],
- template='{desc}', date=None, user=None,
- logfile=None))
- descs = ui.popbuffer()
-
- searchDescs = bugs.search(descs)
- if searchDescs:
- ui.warn('blacklisted bug found: %s\n' % searchDescs.groups()[0])
- error = True
-
- return error
\ No newline at end of file
deleted file mode 100755
--- a/test-convert.sh
+++ /dev/null
@@ -1,108 +0,0 @@
-#!/bin/sh
-# This script tests the pushlog converter script. I've only run it on OS X, so be warned.
-
-SCRIPTDIR=`dirname $0`
-
-rm -rf /tmp/hghooks
-# pull an older revision so we can test using the older hooks and converting
-hg clone -r 6209a348c992 http://hg.mozilla.org/users/bsmedberg_mozilla.com/index.cgi/hghooks/ /tmp/hghooks
-
-# need the record script in PATH
-export PATH=$PATH:/tmp/hghooks
-
-REPO=/tmp/hg-test
-CLONE=${REPO}-clone
-# cleanup any existing stuff
-rm -rf $REPO $CLONE
-
-# create a new hg repo
-mkdir $REPO
-hg init $REPO
-
-# setup the old flatfile pushlog hook
-cat > $REPO/.hg/hgrc <<EOF
-[hooks]
-pretxnchangegroup.z_linearhistory = hg_record_changeset_info
-EOF
-
-# now clone it, then commit and push some things
-hg clone $REPO $CLONE
-
-# push two changes together first
-echo "checkin 1" > $CLONE/testfile
-hg add -R $CLONE $CLONE/testfile
-hg ci -R $CLONE -m "checkin 1"
-
-echo "checkin 2" >> $CLONE/testfile
-hg ci -R $CLONE -m "checkin 2"
-hg push -R $CLONE $REPO
-
-# then one separately
-echo "checkin 3" >> $CLONE/testfile
-hg ci -R $CLONE -m "checkin 3"
-hg push -R $CLONE $REPO
-
-# then two together
-echo "checkin 4" >> $CLONE/testfile
-hg ci -R $CLONE -m "checkin 4"
-
-echo "checkin 5" >> $CLONE/testfile
-hg ci -R $CLONE -m "checkin 5"
-hg push -R $CLONE $REPO
-
-# now switch to the previous python+sqlite hook, and run the old convert script
-export PYTHONPATH=/tmp/hghooks
-
-cat > $REPO/.hg/hgrc <<EOF
-[hooks]
-pretxnchangegroup.z_linearhistory = python:mozhghooks.pushlog.log
-EOF
-
-python /tmp/hghooks/convert-pushlog-db.py $REPO/.hg/pushlog || ( echo "FAIL: failed to convert flat-file -> sqlite" && exit 1 ) || exit 1
-
-# Now push a few more things
-# two together, first
-echo "checkin 6" >> $CLONE/testfile
-hg ci -R $CLONE -m "checkin 6"
-
-echo "checkin 7" >> $CLONE/testfile
-hg ci -R $CLONE -m "checkin 7"
-hg push -R $CLONE $REPO
-
-# then one separately
-echo "checkin 8" >> $CLONE/testfile
-hg ci -R $CLONE -m "checkin 8"
-hg push -R $CLONE $REPO
-
-# finally two more together
-echo "checkin 9" >> $CLONE/testfile
-hg ci -R $CLONE -m "checkin 9"
-
-echo "checkin 10" >> $CLONE/testfile
-hg ci -R $CLONE -m "checkin 10"
-hg push -R $CLONE $REPO
-
-# now run the newer convert script
-python $SCRIPTDIR/convert-pushlog-db.py $REPO || ( echo "FAIL: failed to convert pushlog.db -> pushlog2.db" && exit 1 ) || exit 1
-
-# Test total push count
-PUSHCOUNT=`echo "SELECT COUNT(*) FROM pushlog;" | sqlite3 $REPO/.hg/pushlog2.db`
-if [[ "$PUSHCOUNT" != "6" ]]; then
- echo "FAIL: push count $PUSHCOUNT != 6";
- exit 1;
-else
- echo "PASS: push count correct";
-fi
-
-# Test stored changesets
-hg log -R $REPO --template="{node}\n" > /tmp/hg-log-output
-echo "SELECT node from changesets LEFT JOIN pushlog ON pushlog.id = changesets.pushid ORDER BY pushid DESC, rev DESC;" | sqlite3 $REPO/.hg/pushlog2.db > /tmp/pushlog-output
-
-if diff /tmp/hg-log-output /tmp/pushlog-output >/dev/null; then
- echo "PASS: recorded and converted all changesets";
-else
- echo "FAIL: hg log and pushlog changesets differ!";
- exit 1;
-fi
-
-echo "Passed all tests!"