{ "info": { "author": "Josh Bialkowski", "author_email": "josh.bialkowski@gmail.com", "bugtrack_url": null, "classifiers": [], "description": "==================\nGerrit Merge Queue\n==================\n\nA merge commit serializer for special branches.\n\n-------\nPurpose\n-------\n\n``gerrit-mq`` solves a particular problem in continuous integeration\nwhereby two separate changes are syntactically conflict free but semantically in\nconflict.\n\nHere's a motivating (though contrived) example. Let's say that our code\nrepository has the following:\n\n``foo.py``:\n\n.. code::\n\n def bar(x):\n return x + 10\n\n``foo_test.py``:\n\n.. code::\n\n import unittest\n\n import foo\n\n class TestFoo(unittest.TestCase):\n def test_foo(self):\n self.assertGreater(foo.bar(0), 5)\n\n if __name__ == '__main__':\n unittest.main()\n\n\nNow let's say that Alice decies to improve this loose test with some more\nmeaningful bounds and makes the following change to ``foo_test.py``:\n\n.. code::\n\n class TestFoo(unittest.TestCase):\n def test_foo(self):\n self.assertEqual(foo.bar(0), 10)\n\nAnd let's say that Bob makes the following change to ``foo.py``:\n\n.. code::\n\n def bar(x):\n return x + 6\n\nIf we have designed our continuous integration infrastructure with pre-submit\nbuild-and-test (on, say, jenkins or buildbot), then both of these changes will\npass pre-submit no problem. However, the two changes are logically incompatible.\nIf both changes are merged the unit test will begin to fail. One way to deal\nwith this issue is after-the-fact. We can add a post-merge job to our continuous\nintegration server to give us a heads-up every time something like this happens.\nHowever, as your team scales, this becomes impractical for two reasons:\n\n1. As the submit rate goes up, the frequency of this occurance will go up\n2. Once a breaking change is in, then all pre-submit jobs will fail. Your\n CI pre-submit job becomes an ignorable signal (if advisory) or the entire\n pipeline is frozen until someone can fix the build (if manditory).\n\n``gerrit-mq`` attempts to solve this problem by re-executing the\nbuild-and-tests checks on each merge in serial order. It ensures that no\nconflicts like that illustrated above ever get merged. In the above scenario,\nwhichever merge was queued first will pass, and the second will fail.\n\n------------\nHow it works\n------------\n\nThere are two components to the merge queue:\n\n1. The merge daemon: polls gerrit for new merge requests and verifies/merges\n them\n2. The web frontend: displays the current queue, past job summary table, and\n job output streams\n\nWhen ``gerrit-mq`` polls gerrit it looks for new \"merge requests\". A merge\nrequest is any change which is ``Code-Review: +2`` and ``Merge-Request: +1``.\nThe ``Merge-Request`` label is not a gerrit built-in and so must be added. For\nexample you might add the following to ``all_projects.config``::\n\n [access \"refs/heads/*\"]\n ...\n label-Merge-Queue = -1..+1 group TestGroup\n\nBecause the queue is maintained in gerrit, when a merge fails ``gerrit-mq`` will\nadd a ``Merge-Queue: -1`` label. In order to allow re-request of a merge,\n``gerrit-mq`` resolves the ``Merge-Queue`` label score as \"The highest score\nafter the latest -1\".\n\n\n-----\nUsage\n-----\n\n.. code-block:: text\n\n usage: gerrit-mq [-h] [-c CONFIG_PATH] [-l {debug,info,warning,error}] CMD ...\n\n Entry point / launcher for gerrit-mq components.\n\n positional arguments:\n CMD\n webfront Start the merge-queue master service.\n get-next Retrieve the next merge request.\n get-queue Retrieve the currently cached queue in json format\n daemon Execute the daemon process.\n render-templates Render jinja2 templates into full html files.\n migrate-database Migrate a database from one schema to another\n sync-account-table Fetch account table from gerrit and store locally\n gzip-old-logs Gzip files in an old log directory\n poll-gerrit Hit gerrit REST and read off the current queue of\n merge requests. Write that to a json file.\n\n optional arguments:\n -h, --help show this help message and exit\n -c CONFIG_PATH, --config-path CONFIG_PATH\n path to config file\n -l {debug,info,warning,error}, --log-level {debug,info,warning,error}\n\n-------------\nConfiguration\n-------------\n\n``gerrit-mq`` takes a configuration file as input. The configuration file is\npython and will be ``exec()``. See the example configuration in\n``samples/mqconfig.py`` which contains comments describing what each option\nmeans.\n\n``gerrit-mq`` supports multiple logical \"queues\". Each queue is defined by:\n\n1. which gerrit project the queue applies to\n2. a pattern used to match against branch names\n3. a unique name for the queue\n4. a dictionary describing the environment of subprocess calls\n5. a list of commands to execute to verify the merge request, if any exits with\n non-zero exit code then verification fails\n6. a flag indicating whether or not to finally merge using the gerrit rest API\n (you set this to false if the last command in your list of commands does\n the actual merge)\n\nThis allows you to configure different verification steps for different\nprojects or different branches. It also allows you to specify a common queue\nfor a pattern of branches. For instance,\n``release-candidate/\\d{4}-\\d{2}-\\d{2}`` will match branches like\n\n* ``release-candidate/2018-01-14``\n* ``release-candidate/2018-02-12``\n\nAll jobs from a single queue are built/verified in the same git working tree.\nThis means that (unless you otherwise specify) the merge queue will generally\nexecute an incremental build. You can, of course, remove the build tree as your\nfirst step to get a clean build every time.\n\n---------\nExecution\n---------\n\nStart the daemon with::\n\n gerrit-mq --config config.py daemon\n\nStart the webfront with ::\n\n gerrit-mq --config config.py webfront\n\nThe webfront only serves ``JSON``. Use::\n\n gerrit-mq render-templates \n\nto create the html document root for the webfront views.\n\nThe directory ``samples/`` contains an example nginx configuration and\n``systemd`` unit files for the webfront and daemon. These all presume that\nthe system has a user ``mergequeue``, the config file is at\n``/home/mergequeue/config.py`` and the html document root is at\n``/home/mergequeue/pages``.\n\n\n-----------\nInit System\n-----------\n\nIf you'd like to run ``gerrit-mq`` on startup in ubuntu, there are sample\n``systemd`` unit files in the ``samples/`` directory.\n\n----------\nTest setup\n----------\n\nThere is a script to create a docker image with gerrit configured for two\nusers. Just execute::\n\n python -Bm gerrit_mq.test.gerrit_docker build\n\nto create the docker image and then::\n\n python -Bm gerrit_mq.test.gerrit_docker start --debug\n\nto start the container (``--debug`` puts it in the foreground).\n\nOnce it's started open http://localhost:8081 in a browser and use the\n\"Become\" link to become one of the test users. Then add your public key\nto that user.\n\nStart the webfront and the nginx forward proxy::\n\n python -Bm gerrit_mq --config gerrit_mq/test/mqconfig.py webfront\n python -Bm gerrit_mq.test --config gerrit_mq/test/mqconfig.py start-nginx\n\nAnd check it out at http://localhost:8080.\n\nNow start the daemon with::\n\n python -Bm gerrit_mq --config gerrit_mq/test/mqconfig.py daemon\n\nAdd your public key to the mergequeue user on gerrit\nTODO(josh): plumb --identity through the daemon config and use the testing key\n\nYou can submit multiple jobs for testing with::\n\n python -Bm gerrit_mq.test --config gerrit_mq/test/mqconfig.py \\\n create-reviews --approve --queue 5\n\nYou can manually clone the test repo with::\n\n git clone ssh://test1@localhost:29418/mq_test\n\nGet the commit hook with::\n\n curl --insecure -Lo .git/hooks/commit-msg http://localhost:8081/tools/hooks/commit-msg\n chmod +x .git/hooks/commit-msg\n\nCheckout a feature branch::\n\n git checkout -b feature_001\n\nMake a change::\n\n cat > file_a.txt\n Hello world\n\n git add -A\n git commit\n git push -u origin\n git push origin HEAD:refs/for/master\n\n\n----------------\nNotes on testing\n----------------\n\nGerrit 2.8.11 only offers ``diff-hellman-group1-sha`` as an exchange method,\nwhich unfortunately OpenSSH (client) disables by default. To run tests againsts\nthis gerrit version in the docker container you'll need to add the following to\nyour ``~/.ssh/config`` ::\n\n Host localhost\n KexAlgorithms +diffie-hellman-group1-sha1\n StrictHostKeyChecking no\n UserKnownHostsFile=/dev/null\n\nCopy the commit message hook from the server using::\n\n curl -Lo .git/hooks/commit-msg http://review.example.com/tools/hooks/commit-msg\n\nThis will append a random changeID to the change message.\n\nPut the change out for review with::\n\n git push origin HEAD:refs/for/master\n\nCreate test commits for coalesced merge::\n\n python -m gerrit_mq.test -c test/config.py create-reviews --approve --queue --repo-path /tmp/mq_test --branch build pass-fail P P P P F P P P P\n", "description_content_type": "", "docs_url": null, "download_url": "https://github.com/cheshirekow/gerrit_mq/archive/0.3.0.tar.gz", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/cheshirekow/gerrit_mq", "keywords": "gerrit", "license": "", "maintainer": "", "maintainer_email": "", "name": "gerrit_mq", "package_url": "https://pypi.org/project/gerrit_mq/", "platform": "", "project_url": "https://pypi.org/project/gerrit_mq/", "project_urls": { "Download": "https://github.com/cheshirekow/gerrit_mq/archive/0.3.0.tar.gz", "Homepage": "https://github.com/cheshirekow/gerrit_mq" }, "release_url": "https://pypi.org/project/gerrit_mq/0.3.0/", "requires_dist": null, "requires_python": "", "summary": "Gerrit merge serializer", "version": "0.3.0" }, "last_serial": 3741635, "releases": { "0.3.0": [ { "comment_text": "", "digests": { "md5": "12279752e41671ca9661dc2b8ce61968", "sha256": "96b4383c2474cef14f51a6d88838ef959ab57bc62365fdedb0371cddf92cc9e2" }, "downloads": -1, "filename": "gerrit_mq-0.3.0.tar.gz", "has_sig": false, "md5_digest": "12279752e41671ca9661dc2b8ce61968", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 35871, "upload_time": "2018-04-06T16:25:19", "url": "https://files.pythonhosted.org/packages/3e/8e/b17ff16ceadfdf8a3685fa024b2de15fa6c9d191ad3071cd9640a55ea0fc/gerrit_mq-0.3.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "12279752e41671ca9661dc2b8ce61968", "sha256": "96b4383c2474cef14f51a6d88838ef959ab57bc62365fdedb0371cddf92cc9e2" }, "downloads": -1, "filename": "gerrit_mq-0.3.0.tar.gz", "has_sig": false, "md5_digest": "12279752e41671ca9661dc2b8ce61968", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 35871, "upload_time": "2018-04-06T16:25:19", "url": "https://files.pythonhosted.org/packages/3e/8e/b17ff16ceadfdf8a3685fa024b2de15fa6c9d191ad3071cd9640a55ea0fc/gerrit_mq-0.3.0.tar.gz" } ] }