.. rbt-command:: rbtools.commands.post.Post

====
post
====

:command:`rbt post` simplifies both creating and updating review requests.
It can look at your source directory, generate a diff, and upload it to a new
or existing review request on an associated Review Board server. This saves a
lot of time over the web UI, and for some types of code repositories (such as
Perforce), it's actually required in order to produce a compatible diff.


.. rbt-command-usage::


Posting and Updating Review Requests
====================================

Depending on the repository type, :command:`rbt post` will either require
a changeset number, or it will rely on the changes in the current source
tree. The end result is that :command:`rbt post` will build a diff and
post it to a Review Board server. The diff and any additional review
request information will be saved on the server as a draft, which can then
be published.

After posting a new review request or updating an existing one,
:command:`rbt post` will display the URL of the review request. If the
:option:`-o` parameter is passed, the default web browser will be opened
to that URL.

The following subsections will explain how :command:`rbt post` is used
with different repository types.


.. _rbt-post-perforce:

Perforce
--------

Posting Changesets
~~~~~~~~~~~~~~~~~~

Perforce has a concept of changesets, which are server-stored descriptions of
a change along with an ID number and associated files. For Perforce, Review
Board stores changeset numbers of a posted change and can use these to
associate particular changes with review requests.

To post a review request for a specific change, or to update an existing
review request for that change, type:

.. code-block:: console

    $ rbt post CHANGENUM

Where ``CHANGENUM`` is a pending or shelved changeset number in Perforce.

.. note::

    When ``CHANGENUM`` refers to a shelved changeset which does not have opened
    files in the client, any moved files within the change will be shown as a
    deleted file and an added file. This is due to limitations in Perforce's
    interface for shelved changesets.

The diff will be generated and uploaded to Review Board, and the review
request information will be updated based on the changeset description.

:command:`rbt post` must be used if you're using Perforce with
Review Board, as the diff generated by :command:`p4 diff` doesn't provide
the information necessary to properly display a side-by-side diff.


Posting Paths
~~~~~~~~~~~~~

There are cases where you may want to post individual paths containing files
instead of changesets. Take the following cases, for example:

* You have code or other files that must be checked in before they're
  reviewed and have undergone multiple changes.
* You're working in a side branch for a while, possibly with other people,
  and need to review the code before it's integrated into the main branch.
* You want to post a really old, previously abandoned change for review
  that previously went unreviewed.

To post with a path, :command:`rbt post` should be run with a standard
Perforce depot path as a parameter, which may contain revision information.
The following paths are supported:


**Uploading a file as a "new" file**::

   //path/to/file

**Uploading all files in a directory as "new" files**::

   //path/to/dir/...

**Uploading a file from a revision as a "new" file (not as common)**::

   //path/to/file/[@#]rev

**Uploading a diff of a file between two revisions**::

   //path/to/file[@#]rev,[@#]rev

**Uploading a diff of all files between two revisions in a directory**::

   //path/to/dir/...[#@]rev,[#@]rev


.. _rbt-post-cvs:
.. _rbt-post-subversion:

CVS and Subversion
------------------

CVS and Subversion don't have a concept of changesets, so instead the
working copy's uncommitted changes are posted for review. To post a
review request with all uncommitted files in a tree, simply run:

.. code-block:: console

    $ rbt post

This will create a new review request and post the diff of the uncommitted
changes. If you  want to update an existing review request with new changes
instead, use the :option:`-r` parameter. For example, to update
review request #42, type:

.. code-block:: console

    $ rbt post -r 42

If you need to post specific files, leaving other uncommitted files out of
the review request, you can include them on the command line, like so:

.. code-block:: console

    $ rbt post -I src/foo.c -I data/bar.png


.. _DVCS:
.. _rbt-post-git:
.. _rbt-post-mercurial:

Distributed Version Control Systems
-----------------------------------

When using a distributed version control system, such as Git or Mercurial,
:command:`rbt post` will by default post the diff between the current
branch and the ``master`` branch. To post a new review request with the
diff between the current branches commit, and the master branch, simply run:

.. code-block:: console

   $ rbt post

If you'd like to update an existing review request with new changes instead,
use the :option:`-u` parameter. This will attempt to locate the matching
review request for your change's commit message.

.. code-block:: console

   $ rbt post -u

If you want to update a specific review request by ID, you can use the
:option:`-r` parameter:

.. code-block:: console

    $ rbt post -r 42

In the case where you are working on code based on a branch that isn't
available to the repository Review Board has configured, you'll want to take
advantage of :command:`rbt post`'s parent diff support.

.. index:: parent diffs

A parent diff is a diff between some known upstream revision that Review Board
has access to and the parent of your branch. It's used to provide a working
baseline for your branch's diff.

For example, in the case of Git, you may be working on the ``topicB`` branch,
which has an ancestry that looks like::

   o master
    \
     o---o topicA
          \
           o---o topicB

If you want to upload a diff of everything between ``topicA`` and ``topicB``,
you would need to tell :command:`rbt post` to also generate a parent diff
between ``master`` and ``topicA``.

This is done by using the :option:`--parent` parameter with the branch name.
For example, in this case you would simply do:

.. code-block:: console

    $ rbt post --parent=topicA

That would generate a parent diff between ``master`` and ``topicA``, and
a normal diff of your changes between ``topicA`` and ``topicB``. The changes
in the parent diff won't appear as changed lines in the diff viewer, meaning
that users will only see changes made between ``topicB`` and ``topicA``.


Tracking Branches
~~~~~~~~~~~~~~~~~

When using Git, :command:`rbt post` makes the assumption that the closest
upstream branch for the diff will be ``origin/master``. This may be wrong if
you are working on a feature branch or have a remote named something other than
``origin``.

In this case, you will want to use the :option:`--tracking-branch` option,
which specifies the remote branch name. For example:

.. code-block:: console

    $ rbt post --tracking-branch=upstream/master


.. _rbt-post-clearcase:

ClearCase and VersionVault
--------------------------

.. versionchanged:: 3.0
   As of Version 3.0, RBTools supports both the legacy "ClearCase" repository
   type, as well as the new "VersionVault" type which is a part of `Power
   Pack`_. VersionVault can be used with both IBM ClearCase as well as HCL
   VersionVault, and is the recommended implementation to use.

:command:`rbt post` provides support for posting changes using IBM ClearCase or
HCL VersionVault repositories. There are several different modes which can be
used depending on how you've organized your repository. Changes must be posted
from within a snapshot or dynamic view.

The most simple case is posting a diff of all currently checked out files in
your view. This will work no matter what workflow you are using:

.. code-block:: console

    $ rbt post

To post a change between a branch and its predecessor, use:

.. code-block:: console

    $ rbt post brtype:branchname

To post a change between a label and its predecessor, use:

.. code-block:: console

    $ rbt post lbtype:labelname

A diff between two labels can also be posted. This requires posting from within
a dynamic view:

.. code-block:: console

    $ rbt post lbtype:label1 lbtype:label2

If you're using UCM, you can also post activities, baselines, and streams:

.. code-block:: console

    $ rbt post activity:my-activity
    $ rbt post baseline:project-dev
    $ rbt post baseline:project-integration baseline:project-dev
    $ rbt post stream:dev-stream

Finally, you can also assemble a diff using file@revision pairs. This requires
posting from within a dynamic view. Each argument will be a
``file@@revision1:file@@revision2`` pair:

.. code-block:: console

    $ rbt post /vobs/proj/file.c@@/main/0:/vobs/proj/file.c@@/main/1

Multiple files can be posted by adding additional file/revision pairs:

.. code-block:: console

    $ rbt post /vobs/proj/file.c@@/main/0:/vobs/proj/file.c@@/main/1 \
               /vobs/proj/file.h@@/main/0:/vobs/proj/file.h@@/main/1


.. note::

   Without any configuration, :command:`rbt post` tries to match Review Board's
   repository based on the VOB's family UUID, and may fall back to trying to
   match the name with the VOB tag. In both these cases, the match may be slow.
   It's highly recommended to set ``REPOSITORY`` in :file:`.reviewboardrc` or
   use the :option:`--repository` command-line option.

.. note::

   There are two ways that ClearCase repositories may be configured on the
   Review Board server. If the repository is using the community-driven
   ClearCase backed, review requests may only contain changes from a single
   VOB. If the repository uses the newer VersionVault backend, changes may span
   across multiple VOBs.

.. _`Power Pack`: https://www.reviewboard.org/powerpack


.. _rbt-post-sos:

Cliosoft SOS
------------

.. versionadded:: 3.1

:command:`rbt post` provides support for posting changes using
`Cliosoft SOS`_ 7.20 or higher. It supports posting changelists (recommended)
or selections.

See :ref:`rbtools-workflow-sos` for a detailed guide.


Posting Changelists
~~~~~~~~~~~~~~~~~~~

Changelists can be posted by passing a changelist name to :command:`rbt post`.
For example:

.. code-block::

   $ rbt post my-changelist

You can then update the review request that matches that changelist by using
:option:`-u`:

.. code-block::

   $ rbt post -u my-changelist


Posting Selections
~~~~~~~~~~~~~~~~~~

To post a default selection (which includes all modified files, or files
added to/removed from checked-out directories):

.. code-block::

   $ rbt post

To post an explicit SOS selection:

.. code-block::

   $ rbt post "select:<flags>"

   # For example:
   $ rbt post "select:-scm -sor -sunm"

You can update the review request by using :option:`-r` and passing the ID
of the review request you created. Make sure to pass in any selections along
with this. Examples include:

.. code-block::

   $ rbt post -r 123
   $ rbt post -r 123 "select:-scm -sor -sunm"


.. _Cliosoft SOS: https://www.cliosoft.com/products/sos/


.. index:: post-commit review
.. _posting-committed-code:

Posting Committed Code
======================

By default, :command:`rbt post` assumes that you're posting uncommitted
code. This is called a :term:`pre-commit review`. However, it's sometimes
useful to post code that has already been committed to a repository, such
as in an experimental branch. This is a :term:`post-commit review`.

In order to do this, you can pass in revisions as arguments, which will
generate a diff based on a range of committed revisions. This allows a single
review request to show a diff representing the entire history of a branch, if
desired.

Usage is easy. Simply type:

.. code-block:: console

    $ rbt post STARTREV STOPREV

Where ``STARTREV`` is the beginning revision in the range, and
``STOPREV`` is the ending revision, inclusive. If you only need to post
a single revision, you can type:

.. code-block:: console

    $ rbt post REVISION

The syntax for revisions and revision ranges is as close to possible as the
native syntax for the underlying revision control system. You can therefore
pass in ranges either as separate arguments, or using a native range syntax
(such as ``R1:R2`` for SVN or ``R1..R2`` for Git).


.. _posting-existing-diffs:

Posting Existing Diffs
======================

:command:`rbt post` will generate diffs automatically based on the
repository type, but if you need to post a pre-existing diff, you can
use the :option:`--diff-filename` parameter to specify the path to
the diff file.

For example:

.. code-block:: console

    $ rbt post --diff-filename=mycode.diff

You can also use the special value of ``-`` to pipe a diff into STDIN:

.. code-block:: console

    $ cat mycode.diff | rbt post --diff-filename=-

Using STDIN will require either a valid cookie, or the :option:`--username`
and :option:`--password` options.


.. _guessing-fields:

Auto-Setting Summary and Description
====================================

The summary and description of a review request can be automatically
set ("guessed") based on the posted commit by using the
:option:`-g/--guess-fields <-g>`, :option:`--guess-summary`, or
:option:`--guess-description` options.

This saves some time when creating a review request by allowing you to write
a thorough summary and description only once in the commit, and reusing it for
the review request.

This feature only works for SCMs where you're posting commits, instead of
changes from a working directory. For example, Git, Mercurial and Bazaar.

.. tip::

   :option:`-g/--guess-fields <-g>` implies :option:`--guess-summary` and
   :option:`--guess-description`. Generally, you'll want to use it instead
   of the more specific options.


.. _guessing-behavior:

Controlling Guessing Behavior
-----------------------------

.. versionadded:: 0.6

The guessing options can each take a value to control when guessing is done:

* ``yes`` --
  Guessing will be used when creating or updating the review request.

* ``no`` --
  Guessing will not be used. This is useful for overriding a default
  (see :ref:`configuring-guessing-defaults`).

* ``auto`` --
  Guessing will be used only if creating a new review request,
  and not when updating.

You can specify a value when using either short-form or long-form arguments.
For example:

.. code-block:: console

    $ rbt post --guess-fields=no

By default, if no guessing options are specified, ``--guess-fields=auto`` will
be implied. This allows you to run the following and have it automatically
fill in the summary and description:

.. code-block:: console

    $ rbt post

If specifying a guessing argument without a value, ``yes`` will be implied
instead, forcing the fields to be updated, regardless of the default. For
example:

.. code-block:: console

    $ rbt post -g


.. _configuring-guessing-defaults:

Configuring Defaults
--------------------

.. versionchanged:: 0.6

Projects that want to change the default guess behavior can set the
``GUESS_FIELDS``, ``GUESS_SUMMARY``, and ``GUESS_DESCRIPTION`` settings
in :file:`.reviewboardrc`. These accept ``'yes'``, ``'no'``, and ``'auto'``
values.

On RBTools 0.6 or higher, the default is ``'auto'``. On older versions,
the default was ``False`` (equivalent to ``'no'``).

Setting ``GUESS_FIELDS`` will imply setting ``GUESS_SUMMARY`` and
``GUESS_DESCRIPTION``. Rarely will you need to set anything but
``GUESS_FIELDS``.

For example, to default to guessing fields for review requests that are either
newly created or being updated, you can use::

    GUESS_FIELDS = 'yes'


.. _automating-rbt-post:

Automating rbt post
===================

It's possible to automate :command:`rbt post` on a user's behalf. This can
be useful from a repository's :term:`post-commit hook` to automatically
create or update a review request. This works through a combination of a
special Review Board user and the :option:`--submit-as` option.

To set this up, first register a new user. This user will be specific to
your script, and will have special permissions, so make sure the password
is protected. You'll then want to grant the
:ref:`can-submit-as-user-permission` and
:ref:`can-edit-review-request-permission` to the user. This will give this
user to the ability to modify a review request as another user.

You can then invoke :command:`rbt post` by doing the following:

.. code-block:: console

    $ rbt post --username=SPECIAL_USER \
               --password=PASSWORD \
               --submit-as=ANOTHER_USER

Of course, you can pass any other values as you see fit.

This will log in as ``SPECIAL_USER`` and perform operations as
``ANOTHER_USER``.

You can set the default for :option:`--submit-as` by setting ``SUBMIT_AS``
in :file:`.reviewboardrc`.


JSON Output
===========

.. versionadded:: 3.0

When running with :option:`--json`, the results of posting the review request
will be outputted as JSON. This can be used by programs that wrap RBTools in
order to automate posting changes for review.


Successful Payloads
-------------------

When posting is successful, the results are in the form of:

.. code-block:: javascript

   {
       "status": "success",

       // The path to the new diff.
       "diff_url": "<string>",

       // The ID of the review request.
       "review_request_id": <int>,

       // The URL of the review request.
       "review_request_url": "<string>"
   }

For example:

.. code-block:: console

   $ rbt post --json my-branch
   {
       "diff_url": "https://example.com/r/123/diff/",
       "review_request_id": 123,
       "review_request_url": "https://example.com/r/123/"
   }


Error Payloads
--------------

When there's an error posting a change for review, the results will be in the
form of:

.. code-block:: javascript

   {
       "status": "failed",

       // A list of errors from the operation.
       "errors": [
           "<string>",
           ...
       ]
   }

For example:

.. code-block:: console

   $ rbt post --json my-branch
   {
       "errors": [
           "Could not find the repository on the Review Board server."
       ],
       "status": "failed"
   }


.. rbt-command-options::
