.. _development-contributing:

=========================
Contributing to Transifex
=========================

We're passionate about helping Transifex users make the jump to contributing members
of the community, so there are many ways you can help Django's development:

* Report bugs and request features in our `ticket tracker`_.  Please read
  `Reporting bugs`_, below, for the details on how we like our bug reports
  served up.

* Submit patches for new and/or fixed behavior.  Please read `Submitting
  patches`_, below, for details on how to submit a patch.

* Join the `transifex-devel`_ mailing list and share your ideas for how
  to improve Transifex.  We're always open to suggestions, although we're
  likely to be skeptical of large-scale suggestions without some code to
  back it up.


.. _reporting-bugs:

Reporting bugs
==============

Well-written bug reports are *incredibly* helpful. However, there's a certain
amount of overhead involved in working with any bug tracking system, so your
help in keeping our ticket tracker as useful as possible is appreciated.  In
particular:

* **Do** read the :ref:`FAQ <faq-index>` to see if your issue might be a well-known question.

* **Do** `search the tracker`_ to see if your issue has already been filed.

* **Do** ask on `transifex-devel`_ *first* if you're not sure if what you're
  seeing is a bug.

* **Do** write complete, reproducible, specific bug reports. Include as
  much information as you possibly can, complete with code snippets, test
  cases, etc. This means including a clear, concise description of the
  problem, and a clear set of instructions for replicating the problem.
  A minimal example that illustrates the bug in a nice small test case
  is the best possible bug report.

* **Don't** use the ticket system to ask support questions.  Use the
  `transifex-devel`_ list, or the `#transifex`_ IRC channel for that.

* **Don't** use the ticket system to make large-scale feature requests.
  We like to discuss any big changes to Transifex's core on the `transifex-devel`_
  list before actually working on them.

* **Don't** reopen issues that have been marked "wontfix". This mark means
  that the decision has been made that we can't or won't fix this particular
  issue.  If you're not sure why, please ask on `transifex-devel`_.

* **Don't** use the ticket tracker for lengthy discussions, because they're
  likely to get lost. If a particular ticket is controversial, please move
  discussion to `transifex-devel`_.

* **Don't** post to transifex-devel just to announce that you have filed
  a bug report. All the tickets are mailed to another list
  (`transifex-updates`_), which is tracked by developers and triagers, so we
  see them as they are filed.


.. submitting-patches:

Submitting patches
==================

We're always grateful for patches to Transifex's code. Indeed, bug reports with
associated patches will get fixed *far* more quickly than those without patches.


.. _coding-style:

Coding style
============

Here are some notes on the common style we use for stuff landing in Transifex.

* Code follows the guidelines described in the standard Python Coding Style
  of PEP-8_. Docstrings follow PEP-257_.

* Use the following style (indented, auto-concat) when writing long strings::

    def lorem_ipsum():
       description = _(
           "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas "
           "nisl leo, suscipit sed, elementum ac, condimentum eget, augue. "
           "Pellentesque consequat posuere metus. Curabitur scelerisque faucibus "
           "massa. Vestibulum ut nisl ut leo cursus commodo."
       )

* Model filtering should be in the form::

    Module.query.filter_by(name='foo')

  and *not*::

    Module.query.filter(Module.name=='foo') 


Committing
==========


Commit messages
---------------

Commit messages should have a short first line and optionally more information
after a blank newline::

    Short (50 chars or less) summary of changes (#ticket)

    More detailed explanatory text can follow after a blank line, if
    necessary. Wrap to about 72 characters or so.

    If there is a ticket associated, include it in the summary line. Prefix
    line with "bugfix:" and "trivial:" for bugfixes and trivial commits.

     - Bullet points are okay, too. Typically a hyphen or asterisk is used
       for the bullet, preceded by a single space, with blank lines between
       items.

     - Use a hanging indent, like above.

Setup Hints for Common Editors
==============================

Configuring VIM for Transifex Code
----------------------------------

To configure vim for editing Transifex code, make sure that it sets up
the indentation level to 4 columns when editing Python code, that it
expands ASCII TAB (code: 9) characters to spaces, and wraps text at 72
columns.

To enable these options only for ``*.py`` files, you can add the following
options to your ``~/.vimrc`` file::

    if !exists("format_tx_python")
      let format_tx_python = 1

      " Formatting Python code for Transifex.
      autocmd BufNewFile,BufRead *.py set autoindent showmatch
      autocmd BufNewFile,BufRead *.py set formatoptions=tcq2l
      autocmd BufNewFile,BufRead *.py set textwidth=72 shiftwidth=4
      autocmd BufNewFile,BufRead *.py set softtabstop=4 tabstop=8 expandtab
    endif

Configuring Emacs for Transifex Code
------------------------------------

To configure Emacs for editing Transifex code, you can set up a hook
function that runs whenever ``python-mode`` is enabled.  Setting up the
column for wrapping text, and the use of only ASCII SPACE characters for
indentation is easy.  Just add the following Emacs Lisp snippet in your
Emacs startup file::

    ;; Formatting Python code for Transifex.
    (defun local/python-mode-options ()
      "My local configuration tweaks for `python-mode'."
      (setq fill-column 72		;text wrap column
            python-indent 4		;use 4-column indentation for Python
            indent-tabs-mode nil	;use only SPC for indentation
            next-line-add-newlines nil)) ;don't add newlines at end-of-file

    ;; When python-mode loads, call our hook function.
    (eval-after-load "python"
      '(add-hook 'python-mode 'local/python-mode-options))


Changing the model
==================

Like with all software having a database, changes to Transifex's models should
be handled with care. Production instances of Transifex rely on the stability
of the model when upgrading, and a safe upgrade path should be given to
everyone currently running a Transifex instance.

For this reason we usually discuss model changes on the mailing list,
especially if they're big ones. 

New model fields should follow the style of the current fields and include
any help texts attributes to them, if needed.

A commit which changes the models needs to include fixtures that work with the
new model. We already have some sample data for folks to try out in
``txcommon/fixtures/sample_data.json``.

Typical model change scenario
-----------------------------

When model modifications are introduced, the following steps can be followed
to have the fixture updated:

1. Flush, create tables and load data::

     ./manage.py flush
     ./manage.py syncdb
     ./manage.py loaddata txcommon/fixtures/sample_data.json

2. Make changes to the models.
3. Probably a migration will be required.

   From the Release 0.7, Transifex uses South for managing the schema 
   migrations of models. To get the migration script related to your model
   change run::
   
     ./manage.py startmigration <app_name> <migration_name> --auto

   Note that a new python script with the <migration_name> will be created under
   the <app_name>/migrations/ dir. As it's an automatic detection, please, have 
   a look on it for checking if it is really reflecting your changes correctly. 
   After check it, you can test it running::
   
     ./manage.py migrate <app_name> --db-dry-run
   
   In complex changes the South application might not be able to proceed 
   automatically (for example when adding a non-null column). In this case you can
   delete the column and re-add it, add it as null and change it, etc. South 
   also supports to write manual migrations and more information can be found 
   at http://south.aeracode.org/wiki/Documentation.
   
   Once your migration pass through the above command without errors, you can
   proceed the migration in the database skipping the option --db-dry-run::
       
      ./manage.py migrate <app_name>

4. With the new DB schema in place, dump the data again::

     ./manage.py dumpdata --indent=2 projects releases codebases \
     tarball vcs sites > txcommon/fixtures/sample_data.json

5. Try the new DB fixture::

     ./manage.py flush --noinput
     ./manage.py syncdb --noinput
     ./manage.py loaddata txcommon/fixtures/sample_data.json
     ./manage.py loaddata txcommon/fixtures/sample_users.json

   Open up your browser to check everything looks OK and that your changes
   have been included as you'd expect.
   
6. Update the documentation if needed. Commit all changes together.


Updating translation files (PO files)
=====================================

To extract new messages from the source code and update the PO files of 
Transifex it is necessary to run the following command and then commit the 
changes::

    ./manage.py txmakemessages --all


Various Development Tips
========================

Cross Site Request Forgery protection
-------------------------------------

Transifex is protected against CSRF_ attacks by ensuring that GET requests are
side-effect free. This means that every action inside Transifex that has an
effect on the database, session, etc. are not being done over a GET request.
With Django's `CSRF Middleware`_ enabled, attackers are prevented from meddling
with a Transifex user's settings.

Examples of CSRF-vulnerable elements are a link which calls ``/logout`` over
GET to log the user out, a 'pt_BR' link to change the page's language to
Brazilian Portuguese and save this setting to the user's cookie, a simple AJAX
request to lock a file, etc.

Examples not vulnerable actions are searching through the website for a string,
pagination, etc.

If you are adding some code in Transifex which has a side-effect, always do it
over POST.


 
.. _PEP-8:   http://www.python.org/dev/peps/pep-0008/
.. _PEP-257: http://www.python.org/dev/peps/pep-0257/
.. _transifex-updates: http://groups.google.com/group/transifex-updates
.. _search the tracker: http://transifex.org/search?&ticket=on
.. _`#transifex`: irc://irc.freenode.net/transifex
.. _ticket tracker: http://transifex.org/newticket
.. _transifex-devel: http://groups.google.com/group/transifex-devel
.. _CSRF: http://en.wikipedia.org/wiki/Cross-site_request_forgery
.. _`CSRF Middleware`: http://docs.djangoproject.com/en/dev/ref/contrib/csrf/
