#!perl
use strict;
use warnings;
use App::bif::OptArgs;
use OptArgs qw/class_optargs/;

eval {
    my ( $class, $opts ) = class_optargs('App::bif');
    $class->new( opts => $opts )->run;
};

if ($@) {
    print STDERR $@;
    exit 1;
}

1;

__END__

=encoding utf-8

=head1 NAME

=for bif-doc #intro bif - the bif manual

bif - distributed bug tracking tool

=head1 VERSION

0.1.4 (2014-10-27)

=head1 SYNOPSIS

  bif COMMAND [...]

=head1 STATUS

Although functional, bif is still under active development.
Documentation and tests are incomplete, and the database schema changes
regularly.  B<DO NOT USE BIF FOR REAL DATA!>

=head1 DESCRIPTION

Bif is a distributed bug tracker with a command-line interface. It
helps you manage tasks and issues using a local database, exchanging
updates with remote databases on demand.  The tool has several features
of interest to distributed project teams:

=over

=item Offline Operation

Many bif actions work offline; you can create and update tasks and
issues while disconnected from the network.

=item Inter-project Cooperation

Bif issues (and tasks) can be linked with (or copied to) multiple
projects, mirroring the inter-project relationships that exist in the
real world.

=back

This document is the bif manual and includes design background,
terminology, general usage and a tutorial. Those who are impatient to
get started may prefer to begin with one of the following:

=over

=item L<bif-doc>

The table of contents for all bif documentation.

=item L<bif-doc-intro>

A very quick hands-on introduction to bif.

=item L<bif-doc-faq>

A list of common questions and answers.

=back

Reference documents for bif commands have titles like
I<bif-command-name>.

=head2 Design Background

Communication is a core component of project management. For
decentralized projects up to a certain scale, email often fulfills the
communication requirements.  Tasks, issues, feature requests and the
like can exist in multiple inboxes as shared conversation topics.
Unfortunately, email on its own provides no solution for managing the
various types of structured meta-data (status, priority, due-date, etc)
that we may want to assign and query throughout a project's lifetime.

Managing structured data is exactly what relational databases are
designed for, and bif takes advantage of SQLite for this purpose. A
database schema helps ensure the integrity of the data, and relevant
and insightful queries can be created using the full power of SQL.  In
addition, SQLite gives us fulltime local reporting and data
modification - a wonderful independence from the network when we need
it.

However a database on its own is not a decentralized communication
tool. Database implementations generally do not have a built-in
functionality for the efficient exchange of updates.  Distributed
Version Control Systems (DVCS) on the other hand do provide a useful
information exchange model, but the techniques of mapping textual
differences to tree structures unfortunately don't translate well to
row-based relational data sets.

Bif therefore is an attempt at applying some DVCS I<princples> to a
standard Create, Retrieve, Update and Delete (CRUD) database
application. The end goal is a distributed communication system that
carries both conversations and structured meta-data. The finer details
of the advantages and trade-offs with regards the bif design can be
found in L<bif-doc-design> and L<bif-doc-faq>.

=head2 Terminology

=over

=item Repository

A bif repository is usually a configuration file and an SQLite database
inside a directory named F<.bif>. The database contains the history,
status and relationships of a set of topics.  All bif commands find the
"current working" repository by searching upwards through the
file-system for such a directory. The terms repository and database are
often used interchangeably.

=item Hub

A bif hub is conceptually synonymous with a project organisation. It is
located across one or more repositories that act as synchronisation
points for exchanging project activities.  A hub can be referred to by
its globally unique name (typically an organisation's domain name)
after it has been registered (see L<bif-pull-hub>) with the local
repository.

=item Topic

Topic is is a catch-all term for a task, issue, bug, feature etc - even
a hub.  Topics are identified by an integer ID which is unique to the
local repository, or by a hexidecimal UUID which is globally unique.
Some topic types (issues for example) can be associated with multiple
projects in which case they have multiple IDs and multiple status
values.

=item Project

A project is also considered a topic, but one that comes with some
extra functionality.  The key property of a project is that it is a
container for grouping together tasks and issues together. Multiple
projects can be managed within a repository.  Projects are fully
identified by their hub name, a "/", and their pathname, although you
can usually just specify their pathname if it is unique.

=back

=head2 Command Structure

Bif commands are structured where possible the same way the English
language describes actions - verb followed by subject. For example
C<bif list topics> or C<bif update issue 34>. The top level bif verbs
are as follows:

    drop              remove an item from the database
    init              initialize a new repository or hub
    list              list topics in the repository
    log               view comments and status history
    new               create a new topic
    pull              import topics from elsewhere
    push              export topics to somewhere else
    show              display a topic's current status
    signup            sign up with a hub provider
    sql               run an SQL command against the database
    sync              exchange changes with a hub
    update            comment on or modify a topic
    upgrade           upgrade a repository

In addition, a couple of useful aliases are created by default:

    ls              list topics --status open --project-status run
    lsi             list identities
    lsp             list projects define plan run
    lss             list topics --status stalled --project-status run

=head2 Global Options

The following options are common to all commands:

=over

=item --debug, -D

Turn on debugging statements, which are included in the I<stdout>
stream.

=item --help, -h

Print a full usage message and exit. Some arguments and options are
only shown when this option is used; a normal usage/error message may
keep some rarely used options hidden.

=item --no-pager

Do not pipe a command's output to a pager.

=item --user-repo

Run commands against the user repository instead of the current
repository.

=back

=head2 Command Interaction

=over

=item Input

Some arguments and options not supplied on the command line are
prompted for.  An editor based on the C<$EDITOR> or C<$VISUAL>
environment variables may also be invoked for certain types of input.

=item Output

Normal output is printed to I<stdout> or sometimes paged with
L<less>(1) when I<stdout> is connected to a terminal.  Error messages
are sent to I<stderr>.

=item Connectivity

The only commands that (may) involve network communication are C<pull>,
C<push>, and C<sync>. Everything else is a local action.

=item Exit Status

An exit value of zero indicates success.

=back

=head1 TUTORIAL

=head2 Initialization

Bif commands that make changes to a repository need to know your
identity.  Bif stores your name and email address in a special user
repository which will be created the first time you run L<bif-init>.

=for bifcode #!sh

    bif init
    # Initialising repository: $HOME/.bifu (v323)
    # Creating "self" identity:
    #   Name: [Your Name] 
    #   Contact Method: [email] 
    #   Contact Email: [your@email.adddr] 
    # Identity created: 1
    # Initialising repository: $PWD/.bif (v323)
    # Importing identity from $HOME/.bifu

An initialized repository always starts out empty - there is no bif
equivalent of the git-clone command.

You generally do not have to remember the location of a repository as
it is automatically discovered when you are working in a subdirectory.

=head2 Scenario 1 - Standalone Project Management

The first scenario we present is for an individual wanting to keep
track of their personal activities.

=begin graph-easy

    (Local Repository [projects],[issues],[tasks])

#    [issue] -- [project] #    [task] -- [project]

=end graph-easy

    + - - - - - - - - - -+
    ' Local Repository   '
    '                    '
    ' +----------------+ '
    ' |     issues     | '
    ' +----------------+ '
    ' +----------------+ '
    ' |    projects    | '
    ' +----------------+ '
    ' +----------------+ '
    ' |     tasks      | '
    ' +----------------+ '
    '                    '
    + - - - - - - - - - -+


=head3 Creating Projects

The L<bif-new-project> command asks for a project path (like a name for
identification), a title, and an initial comment.  That information can
be given on the command line if desired, otherwise it will be prompted
for.

=for bifcode #!sh

    bif new project

    # Path: [] todo
    # Title: [] Things to do
    # An editor is invoked for the comment

Projects can be nested by defining them with a parent path and a "/":

=for bifcode #!sh

    bif new project

    # Path: [] todo/today
    # Title: [] Things to do today
    # An editor is invoked for the comment

Apart from visual organisation, the main impact of having nested
projects is that child projects are included when importing or
exporting them to hubs. Also, child projects will not be displayed in
list commands if the parent project will not be displayed.

A project has three different types of status associated with it.
Project status is for the status of the project itself. Task and issue
status is obviously for the status of tasks and issues associated with
the project.  New projects can be created using different status
templates, given specific initial status, or copied/forked from other
projects.

=head3 Creating Tasks and Issues

Tasks and issues are created similarly to projects, with a summary and
a comment.  As they exist only in the context of a project they may
also require a project path if more than one project exists in the
repository.

=for bifcode #!sh

    bif new task

    # Project: [todo] todo/today
    # Title: Take out the rubbish
    # editor invoked - describe the task in more detail

A task or an issue, like a project, is created with the default status
for that type according to the project. An different initial status can
be set with the C<--status> option:

=for bifcode #!sh

    bif new issue --status needinfo

    # Project: [todo] todo/today
    # Title: Don't feel like taking out the rubbish
    # editor invoked - describe the task in more detail

A comment can be provided directly with the C<--message> option if
desired instead of having the editor invoked.

=head3 Template Projects

Do you have repeatable projects?

=head3 Retrieving Information

Tasks and issues can be viewed, commented on and updated with the
appropriate commands:


=head3 Updating Topics

You can add comments to a topic with the L<bif-update> command.

    bif update ID [--message MESSAGE]
    
If the C<--message> option is not used an editor will be invoked.  A
second argument can also be used to change the status of the topic, and
a C<--title> option can be used to modify the topic summary.

    bif update ID [STATUS] [--title TITLE]

Comments on a topic can also be nested. That is, you can use
L<bif-reply> to respond to a previous update (or a previous reply).

    bif reply UPDATE_ID [--message MESSAGE]

The C<UPDATE_ID> argument is actually a full C<ID.UPDATE_ID> value that
you see with the L<bif-log> command. L<bif-reply> cannot modify a
topic's status or title.

=head3 Editing

There is no mechanism for editing available in bif at this time.  Be as
wild in your comments as you like, but as with the rest of the
internet, once your changes have been shared, you most likely can't
alter them or take them back. First rule of commenting is: take a deep
breath first.

=head3 Deletion

Of course, even after taking a deep breath you may anyway make a change
to your repository that you didn't mean to. You are not alone; this
happens to all of us.  As long as you have not already synchronised
your changes with a hub, they can be removed[1].

The L<bif-drop> command can be used to remove a particular comment, or
an entire topic.

[1] There is nothing magical or otherwise to stop you from dropping any
change. However you will find that as soon as you re-synchronise with a
hub that has those changes they will return to haunt you like the
undead.

=head2 Scenario 2 - Distributed Project Team

The above scenario only uses local operations.  However the real value
of bif comes from its collaboration capabilities with others via the
internet. The second scenario presents the

Project team members probably want to know about every issue and task
in a project.

=begin graph-easy

    (Local [issue],[task],[project])
    (Remote [issues],[tasks],[projects])

    [issue] -- [project]
    [task] -- [project]
    [issues] -- [projects]
    [tasks] -- [projects]

    [issue] -- [issues]
    [task] -- [tasks]
    [project] -- [projects]

    (Local Repository [project],[issues],[tasks])
    (Remote Hub [project],[issues],[tasks])

    [projects] -- [project]

=end graph-easy 

    + - - - - - - +     + - - - - - - - - - - - - - - - - - -+
    ' Local       '     ' Remote                             '
    '             '     '                                    '
    ' +---------+ '     ' +--------+     +----------+        '
    ' |  issue  | ' --- ' | issues | --- | projects | ---+   '
    ' +---------+ '     ' +--------+     +----------+    |   '
    '             '     '                                |   '
    '             '     + - - - - - - - - - - - - - -    |   '
    '   |         '                        |         '   |   '
    '   |         '                        |         '   |   '
    '   |         '                        |         '   |   '
    ' +---------+ '                        |         '   |   '
    ' | project | '------------------------+         '   |   '
    ' +---------+ '                                  '   |   '
    '   |         '                                  '   |   '
    '   |         '                                  '   |   '
    '   |         '                                  '   |   '
    '             '     + - - - - - - - - - - - - - -    |   '
    '             '     '                                |   '
    ' +---------+ '     ' +--------+                     |   '
    ' |  task   | ' --- ' | tasks  | --------------------+   '
    ' +---------+ '     ' +--------+                         '
    '             '     '                                    '
    + - - - - - - +     + - - - - - - - - - - - - - - - - - -+


=head3 Signing up with a provider

As previously mentioned, a remote repository known as a hub is the
mechanism for exchanging updates with others.  You can either self host
a hub on a server you control, or you can use a commercial provider.
Regardless of who is hosting, the communication with the server is via
ssh, for which you will want your own ssh keypair.

Read the L<ssh-keygen>(1) manpage for how to create a keypair, and
L<ssh-copy-id>(1) for how to transfer the public key to your own
server. Hub providers will probably use another method for transfering
the public key during their signup process.

=head3 Registering With A Hub

The reason for registering with a hub is to obtain the list of projects
hosted there.

=for bifcode #!sh

    bif pull hub my.org@provider.com

By default the C<my.org> part of the provider address can be used as
the hub name in other commands.  To view the list of projects we give
the hub alias to the L<bif-list-projects> command:

=for bifcode #!sh

    bif list projects my.org

Registering a project brings in a shallow copy - only the project and
its status types are visible. The local user can create issues against
this project just as if the project was local.

=head3 Importing Projects

A developer must also sign up and register a hub as described
previously. They can then import an entire project into their local
repository using the L<bif-pull-project> command.

=for bifcode #!sh

    bif pull project devel@bifax.org

Importing a project is a one-time activity. Updates to a project that
occur after an import have occured are exchanged with the L<bif-sync>
command.  Any new issues or tasks added to the project anywhere will
now synchronise locally. Likewise, any topics added locally will be
distributed to the hub.

The nice thing about pulling projects is that you only get the data
that you want to see locally. As time goes on and projects are created
and then completed, their relevance becomes less and less. New team
members are not forced to download the entire project history to work
on the current project.

=head3 Exporting Projects

How did a project get up to a hub in the first place? Well the inverse
of L<bif-pull-project> is L<bif-push-project>.  To mirror the todo
project I<from> the local repository I<to> the bifax.org hub for
example we would run the following:

=for bifcode #!sh

    bif push project todo bifax.org

As with importing, exporting a project is a one-off activity; further
updates are exchanged with the L<bif-sync> command.

=head3 Synchronising & Reviewing Updates

Updates such as new topics or updates to existing topics are not
exchanged until you run the L<bif-sync> command.

    bif sync [ID] [HUB]

By default all topics will be synchronised to all relevant hubs, but
you can limit that as desired.

=for bifcode #!sh

    bif sync -p unstable   # ignore all other projects

[TODO: describe the merge algorithm for meta data]

What is useful after a L<bif-sync> call is to review what updates were
transfered from the hub to the local repository. The L<bif-log> command
(an alias for L<bif-log-repo> does just that.

=for bifcode #!sh

    bif log repo

Actions that were transferred into the local repository during the last
sync are marked in the output of the log and list commands. New topics
are prefixed with a "+". Updated topics are prefixed with a "+-".

=head2 Advanced Topic Management

=head3 Inter-Project Issue Collaboration

There are occasions when an issue reported in a project is also, or
perhaps only in the domain of another project.  Bif therefore has the
ability to fork/copy/move individual issues.

The L<bif-push-issue> command is the way to manually ask another
project for support on a particular issue.  The L<bif-push-issue>
command asks for (or can be given) an update message the same way that
a L<bif-update> command does:

=for bifcode #!sh

    bif push issue 13 todo2 \
        --action fork \
        --message "also present in todo v2"

The C<--action> option determines the relationship between the issue
and its old and new projects. Note that this command is still local -
the change will be propagated during the next L<bif-sync> call.

As was mentioned in the introduction, issue status is tracked on a
per-project basis. This means one project can consider the issue solved
and another project can still consider the issue to be blocking. When
an issue is pushed somewhere it therefore gains an extra topic ID, and
can show up in multiple times in the output of the L<bif-list-topics>
command. The L<bif-show-issue> command reveals the details:

=for bifcode #!sh

    bif show issue 13

=head3 Task Collaboration?!?

It does not make sense to distribute tasks across projects the same way
issues can be. A single task cannot have multiple status: it is either
done or it is not, regardless of which projects are interested in the
outcome.

There are however reasons for migrating tasks from one project to
another. The obvious one is simply that they can be defined (by
accident or circumstance) in the wrong place. The default
L<bif-push-task> action therefore results in a I<move>.

Alternatively the C<--action copy> option to L<bif-push-task> does what
it says on the label, which can be useful if you have a template task
in a project that you regularly want to use in other projects. Once
again however, L<bif-new-project> probably has more interesting
mechanisms for copying template-style projects.

=head3 Making A New Release

Consider what happens when a software team makes a new stable release
from their development version. This is effectively an internal fork -
a new project that kicks off as the first project continues along the
same path. At the time of the fork both projects will have exactly the
same set of issues. From that point on the issue status may diverge
based on project activities, but the issues they have in common have
themselves not inherently changed.

The C<--dup> option to the L<bif-new-project> command lets us deal with
the above situation, which specifies an existing project from which to
copy the project title and status names from.  We can also specify that
issues should be copied, moved, or forked with the C<--copy-issues>,
C<--move-issues> and C<--fork-issues> options, each of which takes a
status argument and can be called multiple times.

=for bifcode #!sh

    bif new project v2 \
        --dup devel \
        --fork-issues open,stalled \
        --move-issues closed

There are similar copy/move options for tasks.  In contrast to a copy,
comments made on forked issues in one project will propagate to other
projects, as if there was only a single issue, which is in fact the
case.

=head3 Inter-hub Collaboration

There are times when an issue may be reported to one organisation, but
should actually be resolved by a different organisation.  This
situation is often encountered by operating system distributors and
also occurs when software has external dependencies.  To address this
bif makes it possible (under certain conditions) to collaborate on an
issue across multiple hubs.  [to be implemented]

=head3 External Collaboration

Imagine the situation where a (non-team-member) user has an issue they
want to report to a project team.

=begin graph-easy

    (Local Repository [issue])
    (Remote Hub [project])

    [issue] --> [project]


=end graph-easy 

    + - - - - - - - - - -+     +- - - - - - - +
    ' Local Repository   '     ' Remote Hub   '
    '                    '     '              '
    ' +----------------+ '     ' +----------+ '
    ' |     issue      | ' --> ' | project  | '
    ' +----------------+ '     ' +----------+ '
    '                    '     '              '
    + - - - - - - - - - -+     +- - - - - - - +


=head2 Repository Administration

New versions of bif will necessarily require changes to the database
structure, and possibly the data itself. The L<bif-upgrade> command
exists to advance the database status to match that required by the bif
software version. It is safe (but pointless) to run L<bif-upgrade> when
the versions already match. When and how this command is run should be
described in the release notes of newer versions of bif.

One other command which is more about the repository than project
management is L<bif-sql>. This is more of a developer or debugging aide
for querying the database directly. This is needed as the bif software
architecture prevents the SQLite command-line tool C<sqlite3> from
working for some statements.

=head2 Hub Administration

Bif is also used to create and manage hub repositories hosted by a hub
provider.

=head3 Quickstart

If you want to create a new hub and already know the provider's plan &
host(s) you wish to use, you can get up and running with the following
command inside an initialized repository:

    bif signup --create hub.name bifhub.com:plan host

This is equivalent to the following:

    bif pull provider bifhub.com
    bif new hub hub.name
    bif signup hub.name plan
    bif push hub hub.name host

=head3 Importing a providers plans and locations

The second step is to register a hub provider, in order to see their
hosts and/or availabe plans.

=for bifcode #!sh

    bif pull provider bifhub.com

Listing the offers (plans) and locations (hosts) is possible with the
appropriate C<list> command:

=for bifcode #!sh

    bif list hosts

    bif list plans

=head3 Signing up for a plan

=for bifcode #!sh

    bif signup my.org bifhub.com:plan2

This will do a check with the provider to ensure that the name has not
been already taken. If successful you should be able to see the
invoice:

=for bifcode #!sh

    bif list invoices

=head3 Initializing A Hub

The L<bif-init> command is also used to create a hub repository when
given the appropriate arguments.

    bif init [NAME] [LOCATION]

The first argument to the C<init> command is the name of your hub.  The
name is representative of your project organisation, and should be
globally unique. We generally recommend to use something similar to a
DNS zone.

When the LOCATION specified matches one of the hosts from a provider
than the initialization happens remotely.

=head3 Team communication

After a push your hub will be available on the designated hosts, and
you can inform your team how to register their L<bif> repositories with
the hub:

    Hi team,

    Our collaboration hub has been created at the following location:

        your.org@zrh.bifhub.com
    
    To access the hub send us your identity from a local bif
    repository:

=for bifcode #!sh

        bif init
        bif push identity 1 your.org@zrh.bifhub.com

    Once we have enabled the permissions you can register the hub:

=for bifcode #!sh

        bif pull hub your.org@zrh.bifhub.com

    And then import the "devel" project to work on straight away.
        
=for bifcode #!sh

        bif pull project devel

        # bif new issue/task etc...

    Don't forget to sync regularly.

=for bifcode #!sh

        bif sync

    Thanks,
    PM

=head3 Managing the hub

You can at any time confirm the hub and its status:

=for bifcode #!sh

    bif list hubs

    bif show hub ID

At some point in the future there will be actions that a hub manager
can take, such as allowing access, defining roles & permissions, paying
invoices and so on.

=head1 FILES

=over

=item F<$HOME/.bifu/db.sqlite3>

User repository datatbase.

=item F<$HOME/.bifu/config>

User configuration file.

=item F<$PWD/.bif/config>

Curent repository configuration file.

=item F<$PWD/.bif/db.sqlite3>

Current repository database.

=back

=head1 SEE ALSO

L<bifsync>(1)

=head1 SUPPORT

Bif is community supported software, and the community expects (and
should offer) respectful communication with all of its members.

=over

=item Website:

L<http://bifax.org/bif/>

=item Code Repository:

git://bifax.org/bif.git/

=item Issue Tracker:

Doesn't exit yet.

=item Mailing List:

Subscribe via L<http://www.freelists.org/list/bif-devel> and then send
mail to <bif-devel@freelists.org>.

=back

If you have an issue with bif please first make the effort to read the
documentation and/or search for an answer to your issue in the
internet. If you are still stuck send us a message as if you were
answering the following questions:

=over

=item * What does C<bif show VERSION> print?

=item * What are goal you trying to achieve?

=item * What commands are you running?

=item * What (output) did you expect (to see)?

=item * What (output) actually occured?

=back

We will most likely need to ask for more information from you. You can
possibly speed things along by already running your commands with the
C<--debug> flag turned on.

=head1 AUTHOR

Mark Lawrence E<lt>nomad@null.netE<gt>

=head1 COPYRIGHT AND LICENSE

Copyright 2013-2014 Mark Lawrence <nomad@null.net>

This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3 of the License, or (at your
option) any later version.

