diff --git a/README.md b/README.md
index ec2da3934e..853e071fc6 100644
--- a/README.md
+++ b/README.md
@@ -63,17 +63,11 @@ Contributing to Spack is relatively easy. Just send us a
When you send your request, make ``develop`` the destination branch on the
[Spack repository](https://github.com/LLNL/spack).
-Before you send a PR, your code should pass the following checks:
-
-* Your contribution will need to pass the `spack test` command.
- Run this before submitting your PR.
-
-* Also run the `share/spack/qa/run-flake8-tests` script to check for PEP8 compliance.
- To encourage contributions and readability by a broad audience,
- Spack uses the [PEP8](https://www.python.org/dev/peps/pep-0008/) coding
- standard with [a few exceptions](https://github.com/LLNL/spack/blob/develop/.flake8).
-
+Your PR must pass Spack's unit tests and documentation tests, and must be
+[PEP 8](https://www.python.org/dev/peps/pep-0008/) compliant.
We enforce these guidelines with [Travis CI](https://travis-ci.org/LLNL/spack).
+To run these tests locally, and for helpful tips on git, see our
+[Contribution Guide](http://spack.readthedocs.io/en/latest/contribution_guide.html).
Spack uses a rough approximation of the [Git
Flow](http://nvie.com/posts/a-successful-git-branching-model/)
diff --git a/lib/spack/docs/contribution_guide.rst b/lib/spack/docs/contribution_guide.rst
index 108b23a6d0..ebfab854d5 100644
--- a/lib/spack/docs/contribution_guide.rst
+++ b/lib/spack/docs/contribution_guide.rst
@@ -1,247 +1,521 @@
.. _contribution-guide:
+==================
Contribution Guide
-=====================
+==================
This guide is intended for developers or administrators who want to
contribute a new package, feature, or bugfix to Spack.
It assumes that you have at least some familiarity with Git VCS and Github.
-The guide will show a few examples of contributing workflow and discuss
-the granularity of pull-requests (PRs).
+The guide will show a few examples of contributing workflows and discuss
+the granularity of pull-requests (PRs). It will also discuss the tests your
+PR must pass in order to be accepted into Spack.
First, what is a PR? Quoting `Bitbucket's tutorials `_:
- Pull requests are a mechanism for a developer to notify team members that they have **completed a feature**.
- The pull request is more than just a notification—it’s a dedicated forum for discussing the proposed feature
+ Pull requests are a mechanism for a developer to notify team members that
+ they have **completed a feature**. The pull request is more than just a
+ notification—it’s a dedicated forum for discussing the proposed feature.
-Important is completed feature, i.e. the changes one propose in a PR should
+Important is **completed feature**. The changes one proposes in a PR should
correspond to one feature/bugfix/extension/etc. One can create PRs with
changes relevant to different ideas, however reviewing such PRs becomes tedious
-and error prone. If possible, try to follow the rule **one-PR-one-package/feature.**
+and error prone. If possible, try to follow the **one-PR-one-package/feature** rule.
-Spack uses a rough approximation of the `Git Flow `_ branching
-model. The develop branch contains the latest contributions, and master is
-always tagged and points to the latest stable release. Thereby when you send
-your request, make ``develop`` the destination branch on the
+Spack uses a rough approximation of the `Git Flow `_
+branching model. The develop branch contains the latest contributions, and
+master is always tagged and points to the latest stable release. Therefore, when
+you send your request, make ``develop`` the destination branch on the
`Spack repository `_.
-Let's assume that the current (patched) state of your fork of Spack is only
-relevant to yourself. Now you come across a bug in a package or would like to
-extend a package and contribute this fix to Spack. It is important that
-whenever you change something that might be of importance upstream,
-create a pull-request (PR) as soon as possible. Do not wait for weeks/months to
-do this: a) you might forget why did you modified certain files; b) it could get
-difficult to isolate this change into a stand-alone clean PR.
+----------------------
+Continuous Integration
+----------------------
-Now let us discuss several approaches one may use to submit a PR while
-also keeping your local version of Spack patched.
+Spack uses `Travis CI `_ for Continuous Integration
+testing. This means that every time you submit a pull request, a series of tests will
+be run to make sure you didn't accidentally introduce any bugs into Spack. Your PR
+will not be accepted until it passes all of these tests. While you can certainly wait
+for the results of these tests after submitting a PR, we recommend that you run them
+locally to speed up the review process.
+If you take a look in ``$SPACK_ROOT/.travis.yml``, you'll notice that we test
+against Python 2.6 and 2.7. We currently perform 3 types of tests:
-First approach (cherry-picking):
---------------------------------
+^^^^^^^^^^
+Unit Tests
+^^^^^^^^^^
-First approach is as follows.
-You checkout your local develop branch, which for the purpose of this guide
-will be called ``develop_modified``:
+Unit tests ensure that core Spack features like fetching or spec resolution are
+working as expected. If your PR only adds new packages or modifies existing ones,
+there's very little chance that your changes could cause the unit tests to fail.
+However, if you make changes to Spack's core libraries, you should run the unit
+tests to make sure you didn't break anything.
+
+Since they test things like fetching from VCS repos, the unit tests require
+`git `_, `mercurial `_,
+and `subversion `_ to run. Make sure these are
+installed on your system and can be found in your ``PATH``. All of these can be
+installed with Spack or with your system package manager.
+
+To run *all* of the unit tests, use:
.. code-block:: console
- $ git checkout develop_modified
+ $ spack test
-Let us assume that lines in files you will be modifying
-are the same in `develop_modified` branch and upstream ``develop``.
-Next edit files, make sure they work for you and create a commit
+These tests may take several minutes to complete. If you know you are only
+modifying a single Spack feature, you can run a single unit test at a time:
.. code-block:: console
- $ git add
- $ git commit -m
+ $ spack test architecture
-Normally we prefer that commits pertaining to a package ````` have
-a message ``: descriptive message``. It is important to add
-descriptive message so that others, who might be looking at your changes later
-(in a year or maybe two), would understand the rationale behind.
+This allows you to develop iteratively: make a change, test that change, make
+another change, test that change, etc. To get a list of all available unit
+tests, run:
+.. command-output:: spack test --list
-Next we will create a branch off upstream's ``develop`` and copy this commit.
-Before doing this, while still on your modified branch, get the hash of the
-last commit
+Unit tests are crucial to making sure bugs aren't introduced into Spack. If you
+are modifying core Spack libraries or adding new functionality, please consider
+adding new unit tests or strengthening existing tests.
+
+.. note::
+
+ There is also a ``run-unit-tests`` script in ``share/spack/qa`` that runs the
+ unit tests. Afterwards, it reports back to Coverage with the percentage of Spack
+ that is covered by unit tests. This script is designed for Travis CI. If you
+ want to run the unit tests yourself, we suggest you use ``spack test``.
+
+^^^^^^^^^^^^
+Flake8 Tests
+^^^^^^^^^^^^
+
+Spack uses `Flake8 `_ to test for
+`PEP 8 `_ conformance. PEP 8 is
+a series of style guides for Python that provide suggestions for everything
+from variable naming to indentation. In order to limit the number of PRs that
+were mostly style changes, we decided to enforce PEP 8 conformance. Your PR
+needs to comply with PEP 8 in order to be accepted.
+
+Testing for PEP 8 compliance is easy. Simply add the quality assurance
+directory to your ``PATH`` and run the flake8 script:
.. code-block:: console
- $ git log -1
+ $ export PATH+=":$SPACK_ROOT/share/spack/qa"
+ $ run-flake8-tests
-and copy-paste this ```` to the buffer. Now switch to upstream's ``develop``,
-make sure it's updated, checkout the new branch, apply the patch and push to
-GitHub:
+``run-flake8-tests`` has a couple advantages over running ``flake8`` by hand:
+
+#. It only tests files that you have modified since branching off of develop.
+
+#. It works regardless of what directory you are in.
+
+#. It automatically adds approved exemptions from the flake8 checks. For example,
+ URLs are often longer than 80 characters, so we exempt them from the line
+ length checks. We also exempt lines that start with "homepage", "url", "version",
+ "variant", "depends_on", and "extends" in the ``package.py`` files.
+
+More approved flake8 exemptions can be found
+`here `_.
+
+If all is well, you'll see something like this:
.. code-block:: console
- $ git checkout develop
- $ git pull upstream develop
- $ git checkout -b
- $ git cherry-pick
- $ git push -u
+ $ run-flake8-tests
+ Dependencies found.
+ =======================================================
+ flake8: running flake8 code checks on spack.
-Here we assume that local ``develop`` branch tracks upstream develop branch of
-Spack. This is not a requirement and you could also do the same with remote
-branches. Yet to some it is more convenient to have a local branch that
+ Modified files:
+
+ var/spack/repos/builtin/packages/hdf5/package.py
+ var/spack/repos/builtin/packages/hdf/package.py
+ var/spack/repos/builtin/packages/netcdf/package.py
+ =======================================================
+ Flake8 checks were clean.
+
+However, if you aren't compliant with PEP 8, flake8 will complain:
+
+.. code-block:: console
+
+ var/spack/repos/builtin/packages/netcdf/package.py:26: [F401] 'os' imported but unused
+ var/spack/repos/builtin/packages/netcdf/package.py:61: [E303] too many blank lines (2)
+ var/spack/repos/builtin/packages/netcdf/package.py:106: [E501] line too long (92 > 79 characters)
+ Flake8 found errors.
+
+Most of the error messages are straightforward, but if you don't understand what
+they mean, just ask questions about them when you submit your PR. The line numbers
+will change if you add or delete lines, so simply run ``run-flake8-tests`` again
+to update them.
+
+.. tip::
+
+ Try fixing flake8 errors in reverse order. This eliminates the need for
+ multiple runs of ``flake8`` just to re-compute line numbers and makes it
+ much easier to fix errors directly off of the Travis output.
+
+.. warning::
+
+ Flake8 requires setuptools in order to run. If you installed ``py-flake8``
+ with Spack, make sure to add ``py-setuptools`` to your ``PYTHONPATH``.
+ Otherwise, you will get an error message like:
+
+ .. code-block:: console
+
+ Traceback (most recent call last):
+ File: "/usr/bin/flake8", line 5, in
+ from pkg_resources import load_entry_point
+ ImportError: No module named pkg_resources
+
+^^^^^^^^^^^^^^^^^^^
+Documentation Tests
+^^^^^^^^^^^^^^^^^^^
+
+Spack uses `Sphinx `_ to build its
+documentation. In order to prevent things like broken links and missing imports,
+we added documentation tests that build the documentation and fail if there
+are any warning or error messages.
+
+Building the documentation requires several dependencies, all of which can be
+installed with Spack:
+
+* sphinx
+* graphviz
+* git
+* mercurial
+* subversion
+
+.. warning::
+
+ Sphinx has `several required dependencies `_.
+ If you installed ``py-sphinx`` with Spack, make sure to add all of these
+ dependencies to your ``PYTHONPATH``. The easiest way to do this is to run
+ ``spack activate py-sphinx`` so that all of the dependencies are symlinked
+ to a central location. If you see an error message like:
+
+ .. code-block:: console
+
+ Traceback (most recent call last):
+ File: "/usr/bin/flake8", line 5, in
+ from pkg_resources import load_entry_point
+ ImportError: No module named pkg_resources
+
+ that means Sphinx couldn't find setuptools in your ``PYTHONPATH``.
+
+Once all of the dependencies are installed, you can try building the documentation:
+
+.. code-block:: console
+
+ $ cd "$SPACK_ROOT/lib/spack/docs"
+ $ make clean
+ $ make
+
+If you see any warning or error messages, you will have to correct those before
+your PR is accepted.
+
+.. note::
+
+ There is also a ``run-doc-tests`` script in the Quality Assurance directory.
+ The only difference between running this script and running ``make`` by hand
+ is that the script will exit immediately if it encounters an error or warning.
+ This is necessary for Travis CI. If you made a lot of documentation tests, it
+ is much quicker to run ``make`` by hand so that you can see all of the warnings
+ at once.
+
+If you are editing the documentation, you should obviously be running the
+documentation tests. But even if you are simply adding a new package, your
+changes could cause the documentation tests to fail:
+
+.. code-block:: console
+
+ package_list.rst:8745: WARNING: Block quote ends without a blank line; unexpected unindent.
+
+At first, this error message will mean nothing to you, since you didn't edit
+that file. Until you look at line 8745 of the file in question:
+
+.. code-block:: rst
+
+ Description:
+ NetCDF is a set of software libraries and self-describing, machine-
+ independent data formats that support the creation, access, and sharing
+ of array-oriented scientific data.
+
+Our documentation includes :ref:`a list of all Spack packages `.
+If you add a new package, its docstring is added to this page. The problem in
+this case was that the docstring looked like:
+
+.. code-block:: python
+
+ class Netcdf(Package):
+ """
+ NetCDF is a set of software libraries and self-describing,
+ machine-independent data formats that support the creation,
+ access, and sharing of array-oriented scientific data.
+ """
+
+Docstrings cannot start with a newline character, or else Sphinx will complain.
+Instead, they should look like:
+
+.. code-block:: python
+
+ class Netcdf(Package):
+ """NetCDF is a set of software libraries and self-describing,
+ machine-independent data formats that support the creation,
+ access, and sharing of array-oriented scientific data."""
+
+Documentation changes can result in much more obfuscated warning messages.
+If you don't understand what they mean, feel free to ask when you submit
+your PR.
+
+-------------
+Git Workflows
+-------------
+
+Spack is still in the beta stages of development. Most of our users run off of
+the develop branch, and fixes and new features are constantly being merged. So
+how do you keep up-to-date with upstream while maintaining your own local
+differences and contributing PRs to Spack?
+
+^^^^^^^^^
+Branching
+^^^^^^^^^
+
+The easiest way to contribute a pull request is to make all of your changes on
+new branches. Make sure your ``develop`` is up-to-date and create a new branch
+off of it:
+
+.. code-block:: console
+
+ $ git checkout develop
+ $ git pull upstream develop
+ $ git branch
+ $ git checkout
+
+Here we assume that the local ``develop`` branch tracks the upstream develop
+branch of Spack. This is not a requirement and you could also do the same with
+remote branches. But for some it is more convenient to have a local branch that
tracks upstream.
-Now you can create a PR from web-interface of GitHub. The net result is as
+Normally we prefer that commits pertaining to a package ```` have
+a message ``: descriptive message``. It is important to add
+descriptive message so that others, who might be looking at your changes later
+(in a year or maybe two), would understand the rationale behind them.
+
+Now, you can make your changes while keeping the ``develop`` branch pure.
+Edit a few files and commit them by running:
+
+.. code-block:: console
+
+ $ git add
+ $ git commit --message
+
+Next, push it to your remote fork and create a PR:
+
+.. code-block:: console
+
+ $ git push origin --set-upstream
+
+GitHub provides a `tutorial `_
+on how to file a pull request. When you send the request, make ``develop`` the
+destination branch.
+
+If you need this change immediately and don't have time to wait for your PR to
+be merged, you can always work on this branch. But if you have multiple PRs,
+another option is to maintain a Frankenstein branch that combines all of your
+other branches:
+
+.. code-block:: console
+
+ $ git co develop
+ $ git branch
+ $ git checkout
+ $ git merge
+
+This can be done with each new PR you submit. Just make sure to keep this local
+branch up-to-date with upstream ``develop`` too.
+
+^^^^^^^^^^^^^^
+Cherry-Picking
+^^^^^^^^^^^^^^
+
+What if you made some changes to your local modified develop branch and already
+committed them, but later decided to contribute them to Spack? You can use
+cherry-picking to create a new branch with only these commits.
+
+First, check out your local modified develop branch:
+
+.. code-block:: console
+
+ $ git checkout
+
+Now, get the hashes of the commits you want from the output of:
+
+.. code-block:: console
+
+ $ git log
+
+Next, create a new branch off of upstream ``develop`` and copy the commits
+that you want in your PR:
+
+.. code-block:: console
+
+ $ git checkout develop
+ $ git pull upstream develop
+ $ git branch
+ $ git checkout
+ $ git cherry-pick
+ $ git push origin --set-upstream
+
+Now you can create a PR from the web-interface of GitHub. The net result is as
follows:
-#. You patched your local version of Spack and can use it further
+#. You patched your local version of Spack and can use it further.
#. You "cherry-picked" these changes in a stand-alone branch and submitted it
as a PR upstream.
-
Should you have several commits to contribute, you could follow the same
procedure by getting hashes of all of them and cherry-picking to the PR branch.
-This could get tedious and therefore there is another way:
+.. note::
-Second approach:
-----------------
+ It is important that whenever you change something that might be of
+ importance upstream, create a pull request as soon as possible. Do not wait
+ for weeks/months to do this, because:
-In the second approach we start from upstream ``develop`` (again assuming
-that your local branch `develop` tracks upstream):
+ #. you might forget why you modified certain files
+ #. it could get difficult to isolate this change into a stand-alone clean PR.
+
+^^^^^^^^
+Rebasing
+^^^^^^^^
+
+Other developers are constantly making contributions to Spack, possibly on the
+same files that your PR changed. If their PR is merged before yours, it can
+create a merge conflict. This means that your PR can no longer be automatically
+merged without a chance of breaking your changes. In this case, you will be
+asked to rebase on top of the latest upstream ``develop``.
+
+First, make sure your develop branch is up-to-date:
.. code-block:: console
- $ git checkout develop
- $ git pull upstream develop
- $ git checkout -b
+ $ git checkout develop
+ $ git pull upstream develop
-Next edit a few files and create a few commits by
+Now, we need to switch to the branch you submitted for your PR and rebase it
+on top of develop:
.. code-block:: console
- $ git add
- $ git commit -m
+ $ git checkout
+ $ git rebase develop
-Now you can push it to your fork and create a PR
+Git will likely ask you to resolve conflicts. Edit the file that it says can't
+be merged automatically and resolve the conflict. Then, run:
.. code-block:: console
- $ git push -u
+ $ git add
+ $ git rebase --continue
-Most likely you would want to have those changes in your (modified) local
-version of Spack. To that end you need to merge this branch
+You may have to repeat this process multiple times until all conflicts are resolved.
+Once this is done, simply force push your rebased branch to your remote fork:
.. code-block:: console
- $ git checkout develop_modified
- $ git merge
+ $ git push --force origin
-The net result is similar to the first approach with a minor difference that
-you would also merge upstream develop into you modified version in the last
-step. Should this not be desirable, you have to follow the first approach.
+^^^^^^^^^^^^^^^^^^^^^^^^^
+Rebasing with cherry-pick
+^^^^^^^^^^^^^^^^^^^^^^^^^
+You can also perform a rebase using ``cherry-pick``. First, create a temporary
+backup branch:
+.. code-block:: console
-How to clean-up a branch by rewriting history:
------------------------------------------------
+ $ git checkout
+ $ git branch tmp
-Sometimes you may end up on a branch that has a lot of commits, merges of
-upstream branch and alike but it can't be rebased on ``develop`` due to a long
-and convoluted history. If the current commits history is more of an experimental
-nature and only the net result is important, you may rewrite the history.
-To that end you need to first merge upstream `develop` and reset you branch to
-it. So on the branch in question do:
+If anything goes wrong, you can always go back to your ``tmp`` branch.
+Now, look at the logs and save the hashes of any commits you would like to keep:
+
+.. code-block:: console
+
+ $ git log
+
+Next, go back to the original branch and reset it to ``develop``.
+Before doing so, make sure that you local ``develop`` branch is up-to-date
+with upstream:
+
+.. code-block:: console
+
+ $ git checkout develop
+ $ git pull upstream develop
+ $ git checkout
+ $ git reset --hard develop
+
+Now you can cherry-pick relevant commits:
+
+.. code-block:: console
+
+ $ git cherry-pick
+ $ git cherry-pick
+
+Push the modified branch to your fork:
+
+.. code-block:: console
+
+ $ git push --force origin
+
+If everything looks good, delete the backup branch:
+
+.. code-block:: console
+
+ $ git branch --delete --force tmp
+
+^^^^^^^^^^^^^^^^^^
+Re-writing History
+^^^^^^^^^^^^^^^^^^
+
+Sometimes you may end up on a branch that has diverged so much from develop
+that it cannot easily be rebased. If the current commits history is more of
+an experimental nature and only the net result is important, you may rewrite
+the history.
+
+First, merge upstream ``develop`` and reset you branch to it. On the branch
+in question, run:
.. code-block:: console
$ git merge develop
$ git reset develop
-At this point you your branch will point to the same commit as develop and
+At this point your branch will point to the same commit as develop and
thereby the two are indistinguishable. However, all the files that were
-previously modified will stay as such. In other words, you do not loose the
-changes you made. Changes can be reviewed by looking at diffs
+previously modified will stay as such. In other words, you do not lose the
+changes you made. Changes can be reviewed by looking at diffs:
.. code-block:: console
$ git status
$ git diff
-One can also run GUI to visualize the current changes
-
-.. code-block:: console
-
- $ git difftool
-
-Next step is to rewrite the history by adding files and creating commits
+The next step is to rewrite the history by adding files and creating commits:
.. code-block:: console
$ git add
- $ git commit -m
-
-
-Shall you need to split changes within a file into separate commits, use
-
-.. code-block:: console
-
- $ git add -p
+ $ git commit --message
After all changed files are committed, you can push the branch to your fork
-and create a PR
+and create a PR:
.. code-block:: console
- $ git push -u
+ $ git push origin --set-upstream
-
-
-How to fix a bad rebase by "cherry-picking" commits:
-----------------------------------------------------
-
-Say you are working on a branch ``feature1``. It has several commits and is
-ready to be merged. However, there are a few minor merge conflicts and so
-you are asked to rebase onto ``develop`` upstream branch. Occasionally, it
-happens so that a contributor rebases not on top of the upstream branch, but
-on his/her local outdated copy of it. This would lead to an inclusion of the
-whole lot of duplicated history and of course can not be merged as-is.
-
-One way to get out of troubles is to ``cherry-pick`` important commits. To
-do that, first checkout a temporary back-up branch:
-
-.. code-block:: console
-
- git checkout -b tmp
-
-Now look at logs and save hashes of commits you would like to keep
-
-.. code-block:: console
-
- git log
-
-Next, go back to the original branch and reset it to ``develop``.
-Before doing so, make sure that you local ``develop`` branch is up-to-date
-with the upstream.
-
-.. code-block:: console
-
- git checkout feature1
- git reset --hard develop
-
-Now you can cherry-pick relevant commits
-
-.. code-block:: console
-
- git cherry-pick
- git cherry-pick
-
-
-push the modified branch to your fork
-
-.. code-block:: console
-
- git push -f
-
-and if everything looks good, delete the back-up:
-
-.. code-block:: console
-
- git branch -D tmp