diff --git a/source/_static/kolab.css b/source/_static/kolab.css --- a/source/_static/kolab.css +++ b/source/_static/kolab.css @@ -131,6 +131,50 @@ font-style: italic; } +span.blue { + background: #dee7f8 none repeat scroll 0 0; + border: 1px solid transparent; + border-color: #cfdbe3; + border-radius: 3px; + color: #464c5c; +/* font-size: 12px; */ + padding: 0 4px; +} + +/* + * span.blue::before { + * content: " "; + * font-family: FontAwesome; + * } + */ + +span.gray { + background: #edeef2 none repeat scroll 0 0; + border: 1px solid transparent; + border-color: #e3e4e8; + border-radius: 3px; + color: #555; + padding: 0 4px; +} + +span.orange { + background: #fbede1 none repeat scroll 0 0; + border: 1px solid transparent; + border-color: #f8dcc3; + color: #ba6016; + border-radius: 3px; + padding: 0 4px; +} + +span.red { + background: #f7e6e6 none repeat scroll 0 0; + border: 1px solid transparent; + border-color: #efcfcf; + border-radius: 3px; + color: #a53737; + padding: 0 4px; +} + table.highlighttable { width: 100%; } diff --git a/source/conf.py b/source/conf.py --- a/source/conf.py +++ b/source/conf.py @@ -361,7 +361,7 @@ # add variables as substitutions to the head of each page rst_prolog = "" -for var,repl in variables.items(): +for var, repl in variables.items(): rst_prolog += " .. |%s| replace:: %s\n" % (var, repl) rst_prolog += " .. |**%s**| replace:: **%s**\n" % (var, repl) @@ -377,6 +377,9 @@ rst_prolog += """ .. _Architecture & Design: https://git.kolab.org/tag/architecture_design/ +.. _bugzilla: https://issues.kolab.org/ +.. _current sprint: https://git.kolab.org/tag/sprint_current/ +.. _next sprint: https://git.kolab.org/tag/sprint_next/ .. _Differential: https://git.kolab.org/differential/ .. _Diffusion: https://git.kolab.org/diffusion/ .. _Drydock: https://git.kolab.org/drydock/ @@ -391,7 +394,17 @@ .. _Product Owners: https://git.kolab.org/tag/product_owners/ .. _Projects: https://git.kolab.org/projects/ .. _Quality Assurance: https://git.kolab.org/tag/quality_assurance/ +.. _Report a bug: https://git.kolab.org/maniphest/task/edit/form/9/ +.. _Scrum: http://en.wikipedia.org/wiki/Scrum_%28software_development%29 .. _Scrum Masters: https://git.kolab.org/tag/process_managers/ .. _Sprints: https://git.kolab.org/project/sprint/ .. _Why Your System Should Have a Proper FQDN: https://kanarip.wordpress.com/2016/02/04/why-your-system-requires-a-proper-fqdn/ """ + +rst_prolog += """ +.. role:: blue +.. role:: gray +.. role:: green +.. role:: orange +.. role:: red +""" diff --git a/source/contributor-guide/bug-reporting-casual.rst b/source/contributor-guide/bug-reporting-casual.rst new file mode 100644 --- /dev/null +++ b/source/contributor-guide/bug-reporting-casual.rst @@ -0,0 +1,29 @@ +============================ +Reporting Bugs Against Kolab +============================ + +For the version of Kolab you are running, it is assumed that the issue you are +running in to exists in both your version, and the next version of Kolab (i.e. +the development version). + +At the time of this writing, this can be :orange:`Kolab 16` (stable) or +:orange:`Winterfell` (development). + +Therefore, `report a bug`_ against Kolab in Phabricator. You'll describe what +it is you did, what the expected results are, what results you got, and how +those results do not meet your expectations. + +It is assumed all bugs are issues in the development of Kolab, for two main +reasons: + +* Development teams need to ensure the software is tested for the issue you + find. + +* The bug zappers are able to assist you with troubleshooting, suggesting + work-arounds, configuration, and providing the necessary information. + +.. seealso:: + + * :ref:`contributor-guide-structured-contributions-reporting-bugs` + +Return to other :ref:`contributor-guide-casual-contributions` you could make. diff --git a/source/contributor-guide/bug-reporting-structured.rst b/source/contributor-guide/bug-reporting-structured.rst new file mode 100644 --- /dev/null +++ b/source/contributor-guide/bug-reporting-structured.rst @@ -0,0 +1,154 @@ +.. _contributor-guide-structured-contributions-reporting-bugs: + +=========================================================== +Reporting Bugs Against (Long-Term) Supported Kolab Versions +=========================================================== + +Long-term support versions of Kolab maintain larger sets of different versions +of software, and it becomes important to ensure that the fix for an issue in +`foo-1.0` does not require a properly entitled customer to upgrade to a later +version of Kolab, or even a later version of `foo`. + +The stability requirements imply that support be able to track issues with +specific versions of the software, targets these issues to be resolved in +certain newer versions of the software, and trusts the resolution of the issue +to be verifiable against multiple versions of the software collection. + +Example +======= + +The following table depicts the versions of the **roundcubemail** package, and +the **roundcubemail-plugins-kolab** package, as distributed for each product +stream. + +.. table:: Version table for Roundcubemail and Kolab Plugins + + +-------------------------------+---------------+-----------------------------+ + | | roundcubemail | roundcubemail-plugins-kolab | + +===============================+===============+=============================+ + | :orange:`Kolab Enterprise 13` | `1.0.4` | `3.1.16` | + +-------------------------------+---------------+-----------------------------+ + | :orange:`Kolab Enterprise 14` | `1.1.4` | `3.2.11` | + +-------------------------------+---------------+-----------------------------+ + | :orange:`Kolab 16` | `1.2` | `3.3` | + +-------------------------------+---------------+-----------------------------+ + | :orange:`Kolab Winterfell` | `1.2` | `3.3` | + +-------------------------------+---------------+-----------------------------+ + +Stability requirements for :orange:`Kolab Enterprise 13` demand the following: + +* The version of **roundcubemail** shipped to the product stream is one of + the **1.0 series** of upstream releases, + +* Upstream maintains a **stable** 1.0 series for roundcubemail, + +* The version of **roundcubemail-plugins-kolab** shipped to the product + stream is one of the **3.1 series** of upstream releases, + +* Upstream maintains a **stable** 3.1 series for roundcubemail-plugins-kolab, + +* Future versions of roundcubemail in the 1.0 series remain backward + compatibility for consumers of its API (such as + roundcubemail-plugins-kolab), + +* Added functionality in roundcubemail-plugins-kolab, if any, does not + require any changes in roundcubemail that would break other compatibility, + +* The aforementioned conditions all last for up to 5 years, + +* For a large number of target platforms. + +The same conditions apply to :orange:`Kolab Enterprise 14` and +:orange:`Kolab 16` -- with different version series, different timelines and +sometimes different stacks. + +Further down the dependency stack, this includes maintenance for +**libkolabxml**, **libkolab** and **libcalendaring**. + +In the future, this will extend up to 6 product streams that will need to be +maintained. + +It is therefore important that an issue logged against a version 1.0.1, with +the current version in the 1.0 series perhaps being 1.0.10, needs to go through +the following stages: + +#. Is the issue reproducible in the unstable development version of the + software suite? + + a. If it is, it is a development issue; `report a bug`_ in Phabricator. + + Developer teams become responsible for testing the resolution of the + issue first, and fixing the issue second (see + :ref:`contributor-guide-test-driven-development`). + + For each of the product streams in between current development and + the original issue report, create a ticket in `bugzilla`_. + + .. seealso:: + + * Something about backporting with the verification included. + + b. If it is not, in what product stream can the issue still be reproduced? + + This process can be very costly lather-rinse-repeat exercise, and + therefore needs to be covered ahead of time, through + :ref:`contributor-guide-test-driven-development`. + + Create a `bugzilla`_ ticket for the appropriate + + .. seealso:: + + * Something about constructive troubleshooting efforts + +#. Using the input of 1) and outcome of 1a) or 1b), describe the range of + targets; + + * branch 1.2 for :orange:`Kolab 16`: yes or no? + * branch 1.1 for :orange:`Kolab Enterprise 14`: yes or no? + * etc. + + Each becomes a separate `bugzilla`_ ticket, each of them depending on the + resolution of the more recent product stream('s software version). + +Example +======= + +Let's assume "yay" fails on all versions of Roundcube. + +#. Issue: + + *Yay fails on Roundcube 1.0.1 on* :gray:`Enterprise Linux 6` + + This is an original ticket. The intended milestone for the resolution is + `1.0-next`. + +#. Support: + + #. *Does yay fail in* :orange:`Kolab Winterfell` *on Enterprise Linux 7?* + + Yes, this is a new development issue; `Report a bug`_. Add a project + tag for :orange:`Winterfell` + + #. *Does yay fail in* :orange:`Kolab 16` *on Enterprise Linux 7?* + + Yes, and :orange:`Kolab 16` is on the same software version series as + :orange:`Winterfell`; + + It is thus a new development issue; `Report a bug`_ and have it + blocked by the bug created in 2.1). + + Associate the :orange:`Kolab 16` release target with the bug. + + Also create a `bugzilla`_ ticket. The milestone here is `1.2-next`. + Refer to the task created in Phabricator. + + #. *Does yay fail in* :orange:`Kolab Enterprise 14` *on* + :gray:`Enterprise Linux 6` *?* + + Yes, create a `bugzilla`_ ticket and block it with the ticket created + in 2.2). The milestone here is `1.1-next`. + + #. *Does yay fail in* :orange:`Kolab Enterprise 13` *on* + :gray:`Enterprise Linux 6` *using version 1.0.4?* + + Yes, block the original ticket in 1) with the ticket from 2.3). diff --git a/source/contributor-guide/continuous-integration.rst b/source/contributor-guide/continuous-integration.rst new file mode 100644 --- /dev/null +++ b/source/contributor-guide/continuous-integration.rst @@ -0,0 +1,3 @@ +================================ +(Ab)using Continuous Integration +================================ diff --git a/source/contributor-guide/docker-containers.rst b/source/contributor-guide/docker-containers.rst new file mode 100644 --- /dev/null +++ b/source/contributor-guide/docker-containers.rst @@ -0,0 +1,4 @@ +================================= +Run Kolab Using Docker Containers +================================= + diff --git a/source/contributor-guide/documentation/index.rst b/source/contributor-guide/documentation/index.rst new file mode 100644 --- /dev/null +++ b/source/contributor-guide/documentation/index.rst @@ -0,0 +1,76 @@ +.. _contributor-guide-documentation: + +================================= +Contributing to the Documentation +================================= + +This documentation can easily be contributed to by cloning the following git +repository. + + https://git.kolab.org/diffusion/D/docs.git + +.. IMPORTANT:: + + The documentation is only as good as your willingness to contribute + to it. + +Other documentation included here: + +.. toctree:: + :maxdepth: 1 + + writing-documentation + todolist + +Building the Documentation +========================== + +Most of our more regular contributors clone the repository to their +local workstation, and then build the documentation before pushing back +changes to their fork of kolab-docs. To build the documentation, you +need to have `Sphinx`_ installed. You can also find some hints, tips and +tricks on their website, with regards to the `reStructuredText`_ format +the documentation is written in. + +#. Naturally, first clone the git repository. + + .. parsed-literal:: + + $ :command:`git clone https://git.kolab.org/diffusion/D/docs.git` + +#. Navigate in to the fresh clone: + + .. parsed-literal:: + + $ :command:`cd docs` + +#. To build the documentation, issue the following command: + + .. parsed-literal:: + + $ :command:`make html` + +#. Make some changes, and build and view the result: + + .. parsed-literal:: + + $ :command:`make html` + $ :command:`xdg-open build/html/index.html` + +#. When you are satisfied, commit the results and submit a `Differential`_: + + .. parsed-literal:: + + $ :command:`git commit -a` + $ :command:`arc diff` + +#. Push your changes back into our Phabricator instance. + Timotheus wrote `a good tutorial on how to do that `_. + +Enjoy and thanks for contributing to Kolab! + +.. _Sphinx: http://sphinx-doc.org/ +.. _reStructuredText: http://sphinx-doc.org/rest.html +.. _Working with Git Submodules: http://git-scm.com/book/en/Git-Tools-Submodules +.. _docs.kolab.org: https://docs.kolab.org + diff --git a/source/contributor-guide/documentation/todolist.rst b/source/contributor-guide/documentation/todolist.rst new file mode 100644 --- /dev/null +++ b/source/contributor-guide/documentation/todolist.rst @@ -0,0 +1,12 @@ +Possible Contributions +====================== + +The following list is a collection of all the places where a todo item was included, +because there is more work to do. +Please consider picking one of those up helping to complete the documentation. + +That's left to do: +------------------ + +.. todolist:: + diff --git a/source/contributor-guide/documentation/writing-documentation.rst b/source/contributor-guide/documentation/writing-documentation.rst new file mode 100644 --- /dev/null +++ b/source/contributor-guide/documentation/writing-documentation.rst @@ -0,0 +1,59 @@ +.. _dev-writing-documentation: + +===================== +Writing Documentation +===================== + +The Kolab community has a reference implementation of its releases, +which can best be described as a **next-next-finish** installation [#]_ +of a **single node** [#]_ running **Enterprise Linux 7** [#]_. + +For writing documentation, this means that all documented commands and +file paths mentioned need to match that specific implementation [#]_ of +Kolab installed on Enterprise Linux 7, and that every HOWTO needs to +start at the aforementioned *null* situation. + +This sounds harsh, and it probably is, but here's how you can work with +it: + +* When you create a HOWTO for something on Debian, your HOWTO should + probably be titled: *HOWTO: Achieve Greatness (on Debian Wheezy)*. + +* When you do write a generic HOWTO, you can re-iterate the commands + issued for different distributions:: + + After changing the configuration, restart the service: + + .. parsed-literal:: + + # :command:`systemctl restart postfix` + + On Debian Wheezy, execute the following instead: + + .. parsed-literal:: + + # :command:`/etc/init.d/postfix restart` + +.. rubric:: Footnotes + +.. [#] + + This means to confirm the default settings (other than perhaps the + passwords) during :ref:`installation-guide-setup-kolab`, including but not + limited to the characters used in the passwords chosen -- while we + have learned of issues when using passwords with special characters, + which relate to third party application defaults. + +.. [#] + + A single node is a single operating system instance; physical, + virtual, docked or contained. + +.. [#] + + In the family of Enterprise Linux 7 distributions that we provide + packages for are Red Hat Enterprise Linux and CentOS. + +.. [#] + + The specific implementation is a single-node deployment topology. diff --git a/source/contributor-guide/feature-requests/index.rst b/source/contributor-guide/feature-requests/index.rst new file mode 100644 --- /dev/null +++ b/source/contributor-guide/feature-requests/index.rst @@ -0,0 +1,91 @@ +.. _contributor-guide-feature-requests: + +================ +Feature Requests +================ + +The Definition of a Feature Request +=================================== + +A feature request is a description of a problem space for which we may seek the +resolution to be provided within, or with the help of, Kolab. + +Such a problem space is articulated in and by itself, and allows for +understanding to be formed and interpretation to be fine-tuned over the course +of a process with multiple parties contributing. + +.. IMPORTANT:: + + Using **problem spaces** re-inforces the importance of the human + experience for the final product enhancement. + +A bad example of a feature request would be: + + *Make the button background red.* + +This example neither addresses the actual problem, nor the potential value of a +resolution. + +A better example would be: + + *The contrast between the button background and page is too low.* + +Any target use-case or workflow described must be considered only as a context +establishing a higher level of comprehension in elaboration, about the +dimensions of the problem space. Per the existing example: + + *Color vision deficiencies do not allow some people to distinguish the + button from the background.* + +This would allow us to clarify whether a high-contrast UI is needed, or a +slight adjustment suffices. We would also get to cover other angles. + +Feature requests without a sufficiently accurate or encompassing description of +the problem space to address will not be accepted. + +Where Do Feature Requests Go? +============================= + +Feature requests can be entered in to the Kolab development platform using `this +form `_. + +It's submitted to the backlog of the :red:`Architecture & Design` team. + +The `Architecture & Design`_ team evaluates the enhancement requests, requests +additional feedback if needed, and assigns the priority should the request be +promoted. + +The responsibility of this team is to ensure that, before the construction phase; + +* we have an accurate and full problem space description, and + +* we understand the scope and dimensions of the problem space, and + +* we can successfully determine where the problem should be resolved, and + +* we can determine the resolution to this problem space makes sense for the + product that is Kolab, or + +* we can determine that the problem space is better addressed by existing, + external tooling, and find a means for that external tooling to be + integrated with Kolab, or + +* we can determine that addressing the problem space does not enhance the + Kolab product, and + +* an estimate value of resolving the problem space can be established. + +This leads to a common understanding of scope of delivery, the definition of +done, and the way to verify the results. + +**Backlog** + +**Inception** + +**Elaboration** + +**Construction** + +**Transition** + +.. This part of the process is called :ref:`developer-guide-process-inception`. diff --git a/source/contributor-guide/getting-started.rst b/source/contributor-guide/getting-started.rst new file mode 100644 --- /dev/null +++ b/source/contributor-guide/getting-started.rst @@ -0,0 +1,84 @@ +.. _contributor-guide-getting-started: + +================================ +Getting Started with Phabricator +================================ + +#. Navigate to https://git.kolab.org. We recommend you use a browser. + +#. Determine whether you are a Kolab Systems employee, and act accordingly; + + #. If you are a Kolab Systems employee, use your corporate credentials to + login using LDAP. + + #. If you are not a Kolab Systems employee, create yourself an account if + you have not already done so. You can use any of the forms except for + the one that requests LDAP credentials. + +#. `Set your date-time notation format `_. + +#. Set your profile picture. + +#. `Upload an SSH public key `_. + +#. `Set your text-area font to fixed width `_. + +#. `Configure email notifications `_, + especially the ones for actions you place yourself. + +#. :ref:`contributor-guide-setup-tools`. + +#. Hook up **arcanist** to your Phabricator account: + + .. parsed-literal:: + + $ :command:`arc install-certificate` + +Projects +======== + +Software development projects use a communication icon (envelope) in +:blue:`blue`. + +Each software development project is provided a workboard, such they could, at +their option, visualize a roadmap. + +.. NOTE:: + + The use of sub-projects and milestones in Phabricator is under review. + +Teams +===== + +Teams include groups of people that work on software development projects, or +form the :red:`Architecture & Design` team, :red:`Release Managers`, etc. + +Membership of these teams usually provides you with commit access to a GIT +repository, and is used to authorize differentials in +:ref:`contributor-guide-peer-review`. + +* Software developer teams are used to authorize commit access, and use a group icon in :red:`red`. + +* You need to request membership from one of the existing members. + +* You only need membership in order to push to the GIT repositories directly. + +Sprints +======= + +Sprints are time-boxed team efforts with the duration of exactly one week -- +running from Monday morning to Friday afternoon. + +TODO: More about sprints + +Release Targets +=============== + +Release targets are irrelevant for developers. The only release target that is +relevant for developers is :orange:`Winterfell`. + +Distributions +============= + +Distributions (target platforms) are irrelevant for developers. The only target +platform relevant to developers is :gray:`Maipo` (Enterprise Linux 7). diff --git a/source/contributor-guide/index.rst b/source/contributor-guide/index.rst new file mode 100644 --- /dev/null +++ b/source/contributor-guide/index.rst @@ -0,0 +1,83 @@ +.. _contributor-guide: + +================= +Contributor Guide +================= + +Kolab Groupware development largely follows an iterative and incremental +agile software development metholodogy also known as `Scrum`_. + +In summary, the development process is divided into stages, with different +teams participating in getting tasks to the next stage of the process. + +Kolab Groupware is a collaboration suite consisting of many components, +each of them separate software development projects, some of them +dependent on third-party software development projects, and some of them +separate altogether. + +.. IMPORTANT:: + + Still to do: + + * Contributing to translations (l10n and i18n) + + * Switch current documentation stuff over + + * Fixing packaging issues + + * Feature requests' inception/elaboration/construction/transition + phases + + * Testing Kolab + + * Participation section on Peer Review -- the actual execution of + things. + + Note that this includes the applying of a differential to review + the work in its full context. + + * Running docker containers + + * (Ab)using Continuous Integration (fully testing locally) + + * SCRUM details + + * Packaging and Continuous Delivery + +.. _contributor-guide-casual-contributions: + +Casual Contributions +==================== + +The following guides are intended for casual contributors and contributions, +such as a one-time 5-line patch for that one itch to scratch. + +.. toctree:: + :maxdepth: 1 + + translations + bug-reporting-casual + documentation/index + packaging/casual + feature-requests/index + testing + +.. _contributor-guide-structured-contributions: + +Structured Contributions +======================== + +The following guides set you up for regular, structured contributions to Kolab, +such as continued development and participation in sprints. + +.. toctree:: + :maxdepth: 1 + + getting-started + setup-development-environment + peer-review + docker-containers + continuous-integration + scrum + packaging + bug-reporting-structured diff --git a/source/contributor-guide/packaging.rst b/source/contributor-guide/packaging.rst new file mode 100644 --- /dev/null +++ b/source/contributor-guide/packaging.rst @@ -0,0 +1,3 @@ +================================= +Packaging and Continuous Delivery +================================= diff --git a/source/contributor-guide/packaging/casual.rst b/source/contributor-guide/packaging/casual.rst new file mode 100644 --- /dev/null +++ b/source/contributor-guide/packaging/casual.rst @@ -0,0 +1,4 @@ +======================= +Fixing Packaging Issues +======================= + diff --git a/source/contributor-guide/peer-review.rst b/source/contributor-guide/peer-review.rst new file mode 100644 --- /dev/null +++ b/source/contributor-guide/peer-review.rst @@ -0,0 +1,33 @@ +.. _contributor-guide-peer-review: + +=========== +Peer Review +=========== + +Peer review is a process in which developers submit code changes to a staging +environment, so that other peers have the opportunity to review the work before +the code changes are submitted back to the source code management repository. + +In our development platform, this process is facilitated by `Differential`_. To +use `Differential`_, you must install **arcanist** and set it up. + +.. seealso:: + + * :ref:`contributor-guide-setup-your-development-environment` + +In Kolab development, this stage allows work to progress on writing tests that +fail, first, subsequently supplemented by the work on code changes that make +those tests succeed. + +.. seealso:: + + * :ref:`contributor-guide-test-driven-development` + +The changes submitted are reviewed on Thursday afternoons at the latest. + +Your changes need to be reviewed by at least one other person, who is a +software development project member. + +In :ref:`contributor-guide-test-driven-development`, the submission of the +differential associated with your review process aides in the staging of the +code changes. diff --git a/source/contributor-guide/scrum.rst b/source/contributor-guide/scrum.rst new file mode 100644 --- /dev/null +++ b/source/contributor-guide/scrum.rst @@ -0,0 +1,17 @@ +===== +SCRUM +===== + +Our agile development process is time-boxed with sprints. + +.. toctree:: + :maxdepth: 1 + + scrum/sprints + +.. toctree:: + :maxdepth: 1 + + scrum/start-of-sprint-checklist + scrum/during-the-sprint + scrum/end-of-sprint-checklist diff --git a/source/contributor-guide/scrum/during-the-sprint.rst b/source/contributor-guide/scrum/during-the-sprint.rst new file mode 100644 --- /dev/null +++ b/source/contributor-guide/scrum/during-the-sprint.rst @@ -0,0 +1,3 @@ +================= +During the Sprint +================= diff --git a/source/contributor-guide/scrum/end-of-sprint-checklist.rst b/source/contributor-guide/scrum/end-of-sprint-checklist.rst new file mode 100644 --- /dev/null +++ b/source/contributor-guide/scrum/end-of-sprint-checklist.rst @@ -0,0 +1,33 @@ +======================= +End of Sprint Checklist +======================= + +* The `current sprint`_ must be archived after Friday, 17:00 CET. + +* The `current sprint`_ must have its additional ``#sprint_current`` + hashtag removed. + +* Tickets that remain open in the `current sprint`_ must be moved forward + on to the `next sprint`_. + + .. NOTE:: + + The column for these tickets in the `current sprint`_ should be + reflected in the `next sprint`_, which requires manual intervention. + +* The `next sprint`_ becomes the current sprint, and thus: + + * Remove the additional hashtag ``#sprint_next``, + + * Add the additional hashtag ``#sprint_curret``. + +* The sprint after the next sprint needs to be created; + + * The sprint runs from a Monday 09:00 AM to the following Friday 05:00 + PM. + + * Use an additional hashtag of ``#sprint_next``. + +* Verify the (now) `current sprint`_ (but actually next week's) actually has + sufficient tickets in its backlog, because idling is for jet engines with + reverse thrusters deployed while in flight. diff --git a/source/contributor-guide/scrum/sprints.rst b/source/contributor-guide/scrum/sprints.rst new file mode 100644 --- /dev/null +++ b/source/contributor-guide/scrum/sprints.rst @@ -0,0 +1,3 @@ +======= +Sprints +======= diff --git a/source/contributor-guide/scrum/start-of-sprint-checklist.rst b/source/contributor-guide/scrum/start-of-sprint-checklist.rst new file mode 100644 --- /dev/null +++ b/source/contributor-guide/scrum/start-of-sprint-checklist.rst @@ -0,0 +1,9 @@ +========================= +Start of Sprint Checklist +========================= + +* Contributors assign story points to the tickets in the backlog. + +* Product owners prioritize tickets. + +* A sprint planning meeting provides the opportunity to talk things over. diff --git a/source/contributor-guide/setup-development-environment.rst b/source/contributor-guide/setup-development-environment.rst new file mode 100644 --- /dev/null +++ b/source/contributor-guide/setup-development-environment.rst @@ -0,0 +1,309 @@ +.. _contributor-guide-setup-your-development-environment: + +================================== +Setup Your Development Environment +================================== + +This guide sets you up a development workstation to contribute to Kolab +Groupware development on `Phabricator`_. + +#. :ref:`contributor-guide-setup-tools` + +.. _contributor-guide-setup-tools: + +Install the Tools +================= + +#. Ensure you have our Tools repository configured. + + .. parsed-literal:: + + # :command:`cd /etc/yum.repos.d/` + + For **Fedora 23**: + + .. parsed-literal:: + + # :command:`wget https://obs.kolabsys.com/repositories/Tools/Fedora_23/Tools.repo` + + For **Fedora 22**: + + .. parsed-literal:: + + # :command:`wget https://obs.kolabsys.com/repositories/Tools/Fedora_22/Tools.repo` + + For **Red Hat Enterprise Linux 7**: + + .. parsed-literal:: + + # :command:`wget https://obs.kolabsys.com/repositories/Tools/RHEL_7/Tools.repo` + +#. Import the GPG public key the packages are signed with: + + .. parsed-literal:: + + # :command:`rpm --import https://ssl.kolabsys.com/community.asc` + +#. Install **arcanist**: + + For **Fedora 22** and **Fedora 23**: + + .. parsed-literal:: + + # :command:`dnf -y install arcanist` + + For **Red Hat Enterprise Linux 7**: + + .. parsed-literal:: + + # :command:`yum -y install arcanist` + +.. _contributor-guide-setup-recommended-configuration: + +Recommended Configuration +========================= + +**SSH Configuration** + + Configure SSH to use the correct username and SSH identity when you use + ``git.kolab.org``: + + .. parsed-literal:: + + $ :command:`grep -A3 git.kolab.org ~/.ssh/config` + Host git.kolab.org + User git + IdentityFile ~/.ssh/id_rsa + +**BASH Completion** + + Say something about bash completion and how great it is. + +**GIT Prompt** + + Say something about the git prompt. + +**GIT Configuration** + + For each repository separately, or otherwise globally: + + .. parsed-literal:: + + $ :command:`git config [--global] user.name "Jeroen van Meeuwen (Kolab Systems)"` + $ :command:`git config [--global] user.email vanmeeuwen\@kolabsys.com` + $ :command:`git config [--global] branch.autosetuprebase always` + $ :command:`git config [--global] push.default matching` + +**~/.bashrc** + +A recommended snippet for `~/.bashrc` to assist you visually: + +.. parsed-literal:: + + export GIT_PS1_SHOWDIRTYSTATE=1 + export GIT_PS1_SHOWUNTRACKEDFILES=1 + export GIT_PS1_SHOWUPSTREAM="auto verbose" + + if [ ! -f "/etc/bash_completion" ]; then + if [ -f "/etc/bash_completion.d/git" ]; then + cp /etc/bash_completion.d/git ~/.git-completion.sh + . ~/.git-completion.sh + PS1='[\u\@\h \W$(__git_ps1 " (%s)")]\$ ' + elif [ -f "/usr/share/bash-completion/completions/git" ]; then + cp /usr/share/bash-completion/completions/git ~/.git-completion.sh + . ~/.git-completion.sh + PS1='[\u\@\h \W$(__git_ps1 " (%s)")]\$ ' + fi + else + PS1='[\u\@\h \W$(__git_ps1 " (%s)")]\$ ' + fi + + if [ -f "/usr/share/git-core/contrib/completion/git-prompt.sh" ]; then + source /usr/share/git-core/contrib/completion/git-prompt.sh + fi + +This makes your shell navigating in to a GIT repository appear as follows: + +#. :command:`cd` in to a GIT repository: + + .. parsed-literal:: + + [kanarip\@dws06 ~]$ :command:`cd ~/devel/puppet/domains/kolabsys.com` + [kanarip\@dws06 kolabsys.com (development u=)]$ + + This means a clean working copy. + +#. Create an untracked file: + + .. parsed-literal:: + + [kanarip\@dws06 kolabsys.com (development u=)]$ :command:`touch something` + [kanarip\@dws06 kolabsys.com (development % u=)]$ + + THe `%` means untracked files exist in the directory hierarchy. + +#. Add the untracked file: + + .. parsed-literal:: + + [kanarip\@dws06 kolabsys.com (development % u=)]$ :command:`git add something` + [kanarip\@dws06 kolabsys.com (development + u=)]$ + + The `+` means tracked, uncommitted files exist in the directory hierarchy. + +#. Change a file: + + .. parsed-literal:: + + [kanarip\@dws06 kolabsys.com (development + u=)]$ :command:`echo 1 > something` + [kanarip\@dws06 kolabsys.com (development \*+ u=)]$ + + The `*` means uncommitted changes to tracked files exist. The `+` still + indicates a tracked file is not yet committed. + +#. Checkout another branch. In this example, it is specifically made dirty to + show off: + + .. parsed-literal:: + + [kanarip\@dws06 kolabsys.com (development \*+ u=)]$ :command:`git checkout testing` + A something + Switched to branch 'testing' + Your branch and 'origin/testing' have diverged, + and have 4 and 65 different commits each, respectively. + (use "git pull" to merge the remote branch into yours) + [kanarip\@dws06 kolabsys.com (testing \*+ u+4-65)]$ + + This means we have 4 commits to our local working copy not yet in the + remote tracked, and 65 commits in the remote tracked not yet in our local + working copy. + +#. Attempt to rebase on top of the tracked remote: + + .. parsed-literal:: + + [kanarip\@dws06 kolabsys.com (testing \*+ u+4-65)]$ :command:`git rebase origin/testing --autostash` + Created autostash: 49f31f4 + HEAD is now at a6fb106 Ensure docker runs on atomic hosts + First, rewinding head to replay your work on top of it... + Applied autostash. + [kanarip\@dws06 kolabsys.com (testing + u=)]$ + + You'll notice the `+` again stands for the tracked, not yet committed file + :file:`something`. + +Pushing Changes +=============== + +There is virtually no need to push only to the development branch, but merging +and cherry-picking individual changes should be avoided: + +.. parsed-literal:: + + $ :command:`cd ~/devel/puppet/domains/kolabsys.net` + (...make some changes...) + $ :command:`git commit -a -m "Make some changes"` + +Attempt a push if you feel so inclined: + +.. parsed-literal:: + + $ :command:`git push origin development` + +This may be refused as a non-fast forward attempt, so fetch the origin first. + +.. IMPORTANT:: + + Do **NOT** just issue a :command:`git pull` if your prompt shows your + current local working copy is not clean -- this can still result in a merge + commit and those will not be allowed when pushing them back. + +.. parsed-literal:: + + $ :command:`git fetch origin` + $ :command:`git rebase origin/development --autostash` + +Your prompt should now show something like: + +.. parsed-literal:: + + [kanarip\@dws06 kolabsys.com (development u+1)]$ + +To push your changes: + +.. parsed-literal:: + + $ :command:`git push origin development` + $ :command:`git push origin development:testing` + $ :command:`git push origin development:production` + +Creating a Differential for Review +================================== + +A standard repository comes with three branches: development, testing, +production. + +Make sure you have **development** checked out, and for the sake of preventing +superfluous merge and rebase exercises, ensure it's in sync with upstream: + +.. parsed-literal:: + + $ :command:`git checkout development` + $ :command:`git fetch origin` + $ :command:`git rebase origin/development --autostash` + +Make sure you have a ticket for `Engineering`_ for your work and +`Operations`_ for the final application to production systems. + +Given such a ticket, such as :task:`144`, you can branch off the GIT +repository; + +.. parsed-literal:: + + [kanarip\@dws06 kolabsys.com (development u=)]$ :command:`git checkout -b T144` + [kanarip\@dws06 kolabsys.com (T144)]$ + +Make your changes, and commit them in however many commits you think is +reasonable. + +Then, create the `Differential`_: + +.. parsed-literal:: + + [kanarip\@dws06 kolabsys.net (T125 %)]$ arc diff + You have untracked files in this working copy. + + Working copy: /home/kanarip/devel/puppet/domains/kolabsys.net/ + + Untracked changes in working copy: + (To ignore these changes, add them to ".git/info/exclude".) + bin/reroute-vpn + files/haproxy/haproxy.cfg.transparent + haproxy.patch + nodes + puppet/manifests/classes/puppet.pp~HEAD + puppet/manifests/classes/yum.pp.rej + + Ignore these untracked files and continue? [y/N] :command:`y` + +You will now be requested to provide some information about your proposed +changes. + +Set the first ``Summary:`` line to ``Resolves T345678``, so that your +differential will be associated with the ticket automatically, and an accepted +differential also closes the ticket you refer to. + +.. parsed-literal:: + + Linting... + No lint engine configured for this project. + Running unit tests... + No unit test engine is configured for this project. + Updating commit message... + Created a new Differential revision: + Revision URI: https://noc.kolabsys.net/D8 + + Included changes: + M puppet/manifests/classes/puppet.pp + +And that's it. diff --git a/source/contributor-guide/test-driven-development.rst b/source/contributor-guide/test-driven-development.rst new file mode 100644 --- /dev/null +++ b/source/contributor-guide/test-driven-development.rst @@ -0,0 +1,19 @@ +.. _contributor-guide-test-driven-development: + +======================= +Test-Driven Development +======================= + +Test-driven development is a process in the +:ref:`contributor-guide-phases-construction`. + +The process of development driven by testing can be transcribed as follows: + +#. You get handed a set of clear requirements -- mostly in the form of user + stories you can verify, and documentation on the design -- architecture and + mockups. + +#. You write the tests that verify those requirements are implemented. + +#. You write the code that makes the tests succeed. + diff --git a/source/contributor-guide/testing.rst b/source/contributor-guide/testing.rst new file mode 100644 --- /dev/null +++ b/source/contributor-guide/testing.rst @@ -0,0 +1,3 @@ +============= +Testing Kolab +============= diff --git a/source/contributor-guide/translations.rst b/source/contributor-guide/translations.rst new file mode 100644 --- /dev/null +++ b/source/contributor-guide/translations.rst @@ -0,0 +1,3 @@ +================================================== +Translation: Localization and Internationalization +================================================== diff --git a/source/developer-guide/process.rst b/source/developer-guide/process.rst new file mode 100644 --- /dev/null +++ b/source/developer-guide/process.rst @@ -0,0 +1,500 @@ +.. _developer-guide-process: + +=================== +Development Process +=================== + +.. todo:: + + Describe continuous integration + +.. todo:: + + Describe the difference between build, unit, functional, install, + integration, performance and acceptance tests. + +.. todo:: + + Describe continuous deployment + +.. todo:: + + Describe how to create a ticket + +.. todo:: + + Describe how to submit a patch + +.. todo:: + + Describe how to review and accept or decline a patch + +.. todo:: + + Describe how to formulate a feature request + +Kolab Groupware development largely follows an iterative and incremental +agile software development metholodogy also known as `Scrum`_. + +In summary, the Kolab Groupware development process is divided into +stages, with different teams participating in getting tasks to the next +stage of the process. + +Kolab Groupware is a collaboration suite consisting of many components, +each of them separate software development projects, some of them +dependent on third-party software development projects, and some of them +separate altogether. This creates some discrepancies in applying vanilla +Scrum practices to all projects in the Kolab universe. + +Furthermore, Kolab Groupware is a community software development +project, and not all participants in the community can be expected to be +familiar with (otherwise professional) software development processes. + +It is therefore that we document here how we work with `Scrum`_ using +`Phabricator`_. + +Benefits of Phabricator, Scrum and Test-Driven Development +========================================================== + +A plethora of benefits exist in using Phabricator and Scrum over the +current processes (which do not fall under any known nomenclature), and +Test-Driven Development (TDD). + +* The processes and facilities are focused on structured software + development. + +* Software development stands in stark contrast with longer-term + commitments such as support. + +* A developer is supposed to work on tomorrow's version of the + software, and not yesterday's, as every distraction with yesterday's + software stands in the way of the focus and dedication needed to + provide tomorrow's innovative and competitive software. + +* And every distraction stands in the way of the personal and + professional development of the individual developer. + +* We aim to pull product support away from software development. + +* A Bugzilla is not suitable for agile software development (even with + tooling such as Scrumbugz), and the former point may have + illustrated we wish software development to be agile. + +* Various factors in the world of IT as well as common software + development practices predicate a shift toward continuous deployment + (at one cost) over sometimes overly precautious long-term support + methodologies (at another cost). + +* The dynamics of these costs work in favor of a level of agility in + software development as well as operations, especially with smaller + teams. + +Getting Acquainted with Phabricator +=================================== + +We use `Projects`_ in `Phabricator`_ as a means to group people and +assign them roles, rights and responsibilities in a broader process. + +Tickets are created as `Maniphest`_ tasks, and roll on forward through +the process from thereon. + +Software Development Projects +----------------------------- + +The first type of project is a **Software Development Project**. These +are generally associated with one or more source code management +repositories. + +Each software development project is responsible for a single software +component included in Kolab Groupware, such as **chwala** or +**pykolab**. + +Because the Kolab community is an open community, membership to these +software development projects is *open* -- meaning registered users can +join and leave as they like. + +Authorization Groups (Developer Teams) +-------------------------------------- + +Each software development project that operates source code management +repositories also has a group associated with it that is used for +authorization to push to the associated source code management +repositories. + +For the **PyKolab** software development project for example, a group +**PyKolab Developers** has access to push to the ``pykolab`` GIT +repository. + +These groups are mostly self-regulated, in that members of the group can +add other members to the group. + +Teams and Roles +--------------- + +Teams and roles that are not software development teams include teams +such as `Product Owners`_, `Scrum Masters`_ and `Quality Assurance`_. + +Sprints +------- + +`Sprints`_ are what is in the name. They are a time-limited series of +events resulting in deliverables being emitted at the end of the sprint. + +This series of events consists of: + +**Planning Meeting** + + Held at the beginning of each sprint, the `Product Owners`_ and the + developer team negotiate which tasks on the Sprint's backlog they + will attempt to complete. + + The `Product Owners`_ determine the priority of tasks and declare + which (of all tasks) render the most business value. + + The development team determines the amount of work they feel they + can achieve during the sprint without incurring technical debt. + + .. NOTE:: + + The `Product Owners`_ use tasks related to individual software + development projects and associate them with the **next** + sprint in order to build an initial sprint backlog. + + Working the other way around, where the team in collaboration + with the `Product Owners`_ determine which tasks to put on the + sprint backlog doesn't scale to the number of individual + software development projects for Kolab Groupware as a whole. + +**Daily Scrums** + + Short, daily stand-up meetings are used to let team members + summarize yesterday's work, today's work and talk about any + impediments encountered. + + This ensures team members communicate early and often about their + work, problems they find, and facilitate the fast exchange of + knowledge and ideas or call for help. + +**Review Meeting** + + + +**Retrospective Meeting** + +Process Stages +============== + +The stages of the development process largely align with a manufacturing +process of, say, cars. + +.. _developer-guide-process-stage-concept: + +Concept +------- + +This stage is an almost completely iterative process; Ideas are +generated, possibly prototyped and thrown away on a regular basis. + +As such, concepts may or may not make it to production. In keeping with +the analogy of a car manufacturer, this may be a design drawing for a +new car (up to and including showing off a prototype on a trade show), +or some new technology (stage 2 artificial intelligence). + +For Kolab Groupware, this stage mostly involves research and +development not necessarily based on consumer input. + +The output of this process (if at all "valid") is additional input to +the next stage, :ref:`developer-guide-process-stage-pre-production`. + +.. _developer-guide-process-stage-pre-production: + +Pre-Production +-------------- + +The pre-production stage is an interaction between consumers of the +product, `Product Owners`_, `Architecture & Design`_ and +`Quality Assurance`_. + +:ref:`developer-guide-process-roles-consumers` of the product request +features or report issues, that end up on the *Product Backlog* [#]_. +`Product Owners`_ prioritize these tasks. + +Depending on the complexity of the task, and with the existing need to +facilitate the smoothest possible execution of the **Production** phase, +`Product Owners`_ and `Scrum Masters`_ request a review to be aided by +the `Architecture & Design`_ and `Quality Assurance`_ teams. + +The input for this stage may be anything from UI elements with the wrong +teint (easy to forward to **Production** as-is) to complex enhancements +to Kolab Groupware as a whole, requiring design and possibly touching +the codebase of multiple software projects (such as the implementation +of Federated Central Authentication Services with Two-Factor +Authentication support). + +Regardless, the effort at this stage involves breaking down tasks in to +digestible sub-tasks ready for **Production**. + +Production +---------- + +Production is the stage where development work takes place. The form in +which is this happens is through `Sprints`_, which are limited chunks of +time in which several events take place that shape the development +process for :ref:`developer-guide-process-roles-developers`. + +The input for this stage has initially been composed during the previous +sprint, with `Product Owners`_ putting tasks from dozens of software +development project backlogs on to the backlog for the current sprint. + +Note that at this point, most facets of tasks have already been +negotiated -- but only to a certain extent. + +If a relatively small task involves changes in one software project +dependent on changes in another software project, then this should have +been settled either before the individual sub-tasks end up on the sprint +backlog, or happens during the sprint planning meeting. + +Post-Production +--------------- + +Roles +===== + +.. _developer-guide-process-roles-stakeholders: + +Stakeholders +------------ + +Stakeholders are parties interested in the product, and are responsible +for the creation of feature implementation requests, bug reports and +acceptance testing. + +As such, stakeholders include customers (of Kolab Systems and its +partners), but actually include all consumers of Kolab. In other words, +regardless of affiliation or status, while you are reading this you +are probably a stakeholder. + +However, some stakeholders' wishes have more weight than others. This +is likely reflected (at most) in the priority of the task(s) at hand, +which dictates the order in which tasks are worked on. + +.. _developer-guide-process-role-product-owner: + +Product Owner +------------- + +The role of a product owner (usually a singular entity) is to determine +the value of goals (set out as epics and tasks in `Maniphest`_) and +prioritize the associated epics and tasks accordingly. + +When the product owner does so, he or she determines the value of goals +on behalf of the stakeholders, and in light of an overall vision on +where the product should go. + +Within the Kolab Groupware universe, where the *product* is the Kolab +release, and dozens of individual software development projects make up +the *product*, several aspects make the `Product Owners`_ a team of +individuals rather than a single person: + +* Not all software development projects are related to the product. + + Such may include work on Phabricator or the Sprint extension to + Phabricator (i.e. facilitatory third-party software). + +* Not all software development projects are under the control of the + business. + + This may include third-party software development projects we + contribute to (i.e. Roundcube). + +However in the context of `Scrum`_ and particularly the `Sprints`_, +there is only one stakeholder representative -- **the** Product Owner. + +.. _developer-guide-process-roles-scrum-masters: + +Scrum Masters +------------- + +`Scrum Masters`_ facilitate the Scrum process ... + +.. rubric:: Checklist for the Beginning and End of a Sprint + +#. Remove the hash-tag `sprint_server_current` from the past sprint, +#. Remove the hash-tag `sprint_server_next` from the current sprint, +#. Add the hash-tag `sprint_server_current` to the current sprint, +#. Create a new sprint, +#. Set the start and end dates for the new sprint, +#. Add the hash-tag `sprint_server_next` to the next sprint. + +.. _developer-guide-process-roles-architecture-and-design: + +Architecture & Design +--------------------- + +.. _developer-guide-process-roles-quality-assurance: + +Quality Assurance +----------------- + +.. _developer-guide-process-roles-developers: + +Developers +---------- + +.. _developer-guide-process-roles-consumers: + +Consumers +--------- + +* A user or customer requests the resolution of a certain issue. + +* The product owner(s) + +Continuous Integration, Delivery & Deployment +============================================= + +.. graphviz:: + + digraph { + rankdir = LR; + splines = true; + overlab = prism; + + edge [color=gray50, fontname=Calibri, fontsize=11]; + node [shape=record, fontname=Calibri, fontsize=11]; + + "contributor" -> "Phabricator"; + + "Phabricator" -> "Build Host"; + + "Build Host" -> "Docker Container(s)"; + + } + +#. A *contributor* contributes code via `Differential`_ to create or + update a code review proposal, or `Diffusion`_ to commit directly + to the GIT repository for the Software Development Project. + +#. `Herald`_, the `Phabricator`_ rule engine, is used to trigger the + execution of a `Harbormaster`_ build plan [#]_. + +#. `Harbormaster`_ allocates a `Drydock`_ host to execute a script on. + +#. The `Drydock`_ host's script is supplied with the repository and + the commit in question. + +#. The `Drydock`_ hosts used are `Atomic`_ hosts, meaning they run + `Docker`_ containers to execute Continuous Integration. + +#. The so-called entrypoint for the Docker images (executed when a + container is started from the image) is designed to execute + Continuous Integration and Continuous Delivery. + +Continuous Integration +---------------------- + +Continuous Integration is performed using the following stages; + +* A *build* stage in which the software build dependencies are + installed in to the Docker container, and the software is built. + + In the case of software that does not need to be compiled, such as + PHP and/or JavaScript, the *build* stage executes syntax checks. + +* A *unit testing* stage, which is limited to testing individual + functions of the software, such as ``sum(a, b)`` with ``a=1; b=2`` + indeed resulting in ``3``, but also does not yield unexpected + behaviour: + + * ``sum(a, b)`` over ``a=1`` correctly raises an argument + exception (if expected to), or returns ``1`` (if expected to), + + * ``sum(a, b)`` over ``a="Hello"`` and ``b="world!"``; + + * does not unintentionally result in ``"Hello world!"`` nor + ``"Helloworld!"``, + + * raises the correct exception, or returns false, none or the + equivalent of ``NaN``, + + * ``sum(a, b)`` over ``a=1; b="apple"`` does not result in ``1`` + (unless expected) and raises the correct exception (if expected + to). + + * *etcetera*, *etcetera*. + + Unit testing further includes testing if underlying software + behaves in a way that the software can handle correctly. This may + include tests that determine whether stripping invalid characters + from a string (by **iconv**) yields the expected result, and + whether the version of the API provided by underlying software is + sufficient. + + .. NOTE:: + + In cases where function calls require infrastructure (such as a + SQL server) with :term:`fixtures`, unit tests have to replace + the code that would interact with the infrastructure with code + that returns data as if the infrastructure existed. This is + called *mocking up*. + + Tests that do indeed require infrastructure, and/or cannot be + *mocked up*, are called *functional tests*. + +* A *functional testing* stage, in which functions of the software + are tested which require a minimal amount of infrastructure. + + This may include functions that imply a caching layer such as + **memcached** is available (populating a cache with fixtures, + marking it as dirty, and expecting retrieval to return no data). + + .. NOTE:: + + It should be noted that the distinction between *unit* and + *functional* testing is largely a matter of job control. + + It should also be noted that functional tests are executed + against a *minimal* infrastructure -- the keyword being + minimal. This usually precludes infrastructure needed to + authenticate users, and usually precludes testing functions + against various implementations of a piece of functionality + (such as an IMAP server needed by Roundcube testing possibly + being either of UW-IMAP, Courier, Cyrus IMAP, Dovecot, ...). + +* A *packaging* stage, in which the software is packaged up for + distribution. + +* An *installation testing* stage, in which the result of the + *packaging* is installed. + +* An *upgrade testing* stage, in which any number of former release's + fixtures are put in place, and the upgrade path is supposed to be + completed successfully automatically (such as a + :command:`rake db:migrate`). + +* An *integration testing* stage + +* An *acceptance testing* stage, in which human beings experience + the implementation. + +Continuous Delivery +------------------- + +.. _developer-guide-using-arcanist: + +Using Arcanist +============== + +.. rubric:: Footnotes + +.. [#] + + Kolab Groupware consists of dozens of individual product backlogs. + +.. [#] + + The sources for this script live in the Stick repository at + `drydocker.sh`_. + +.. _Scrum: http://en.wikipedia.org/wiki/Scrum_%28software_development%29 +.. _drydocker.sh: https://git.kolab.org/diffusion/QA/browse/master/drydocker.sh diff --git a/source/index.rst b/source/index.rst --- a/source/index.rst +++ b/source/index.rst @@ -14,6 +14,13 @@ Read more in our :ref:`introduction`. +.. rubric:: The Currency of Kudo is Beer + +.. toctree:: + :maxdepth: 1 + + contributor-guide/index + .. rubric:: Planning Your Kolab Groupware Deployment .. toctree::