bif is a command-line project management tool with a focus on distributed issue/bug tracking. This document is an introduction to bif
version 0.1.5_8 (yyyy-mm-dd). It is based on situations typically encountered by software developers.
It is assumed that you are already comfortable working with command line programs and your operating system shell (e.g. bash).
Once you have installed bif (see bif-doc-about) you can read this tutorial again at any time from the command line using the bif-doc command:
$ bif doc intro
We will begin this tutorial with brief overview of bif terminology before creating our first bif repository. Then we will cover the following scenarios:
Finally we will deal with time tracking and advanced topics such as forking projects and managing hubs.
Bif is all about managing discussions and keeping track of their status. Each discussion, whether it be about an issue, a task, a bug or a feature is considered to be a "topic." If you have a bunch of topics in the pursuit of a particular goal or milestone then you can group all of them into a "project." An "org" is a special project that represents an organisation.
Bif describes itself as distributed. What this means in practice is that most actions are run inside a local repository (or database) where you have a copy of the projects and topics you need to work on. You can even have a copy of external projects you may depend on.
When you have connectivity you can synchronize your local repository with remote repositories which are referred to as "hubs." Synchronize in this context means that missing changes are exchanged until both the local repository and the remote hub have the same data again.
A bif repository is created with the bif-init command.
$ bif init
# Name: Email: blah blah
# Initialising repository: $PWD/.bif (v323)
# Importing identity from $HOME/.bifu
Only the first time you run the bif-init command are you asked to provide your name and contact details. They are then stored in a special user repository (usually $HOME/.bifu) and automatically imported into the local repository during initialization.
You generally don't have to remember the location of a repository when working in sub-directories. Bif commands search automatically upwards through the filesystem to find the nearest repository.
An initialized repository always starts out empty. What you will want to do next depends on who you are working with and how their projects are managed.
The first scenario we present is managing isolated projects. The activities described are however fairly generic and form the basis for the following scenarios as well.
Before you can create tasks or issues you need a project to hold them in. The 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.
$ 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 "/":
$ bif new project
# Path: [] todo/today
# Title: [] Things to do today
# An editor is invoked for the comment
You can display the projects in the repository using bif-list-projects.
$ bif list projects
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.
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.
$ 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 --status
option:
$ 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 --message
option if desired instead of having the editor invoked.
You might start to see a pattern with regards how the bif commands are laid out - bif ACTION OBJECT[S]. The designers have attempted to maintain this calling convention but there are a couple of minor inconsistencies. One of those is listing tasks and issues. They are actually grouped together into a "topic" type, and so to display them the bif-list-topics command is the one to use.
$ bif list topics
The bif-show command shows you a summary of a topic's properties in more detail.
$ bif show 20
The same command can be used for projects as well:
$ bif show today
Note that the name of the project can usually be used instead of the full path as long as bif can uniquely identify the project.
If you have been manually typing commands while reading this introduction you will be wondering if life has to always be so verbose. Bif provides command aliases to reduce the amount of typing needed for common invocations. Aliases are created by editing the configuration file in your user repository $HOME/.bifu/config.
A project has two main types of status associated with it:
New projects can be created using different status templates [NOT IMPLEMENTED], given specific initial status, or copied/forked from other projects. Bif comes with a default set of project status types:
$ bif list topic-types todo
# ID State Status Rank
# 6 define define 10
# 7 offer offer 20
# 8 run run 30
# 9 eval eval 40
# 10 closed closed 50
Likewise, bif has a default set of topic types and status as well:
$ bif list project-status todo
# ID Type State Status Rank Default
# 13 issue open open 10 *
# 14 issue stalled stalled 20 *
# 12 issue closed closed 30 *
# 11 issue - - 40 *
# 17 task open open 10 *
# 18 task stalled stalled 20 *
# 16 task done done 30 *
# 15 task - - 40 *
See bif-new-project for details.
You can add comments to a node with the bif-update command.
bif update ID [--message MESSAGE]
If the --message
option is not used an editor will be invoked. A second argument can also be used to change the status of the node, and a --title
option can be used to modify the node summary.
bif update ID [STATUS] [--title TITLE]
The bif-log command lets you review the history of a topic when you give it a topic ID or project PATH as its first argument.
$ bif log 20
# Lots of stuff
Comments on a node can also be nested. That is, you can use bif-reply to respond to a previous update (or a previous reply).
bif reply UPDATE_ID [--message MESSAGE]
The UPDATE_ID
argument is actually a full ID.UPDATE_ID
value that you see with the bif-log command. bif-reply cannot modify a node's status or title.
bif-log without any arguments will display the entire history of the repository in reverse chronological order.
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.
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 bif-drop command can be used to remove a particular comment, or an entire node.
[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.
Before we move on to scenario 2 we'll provide a brief taste of bif's interproject collaboration functionality. There are occasions, particularly in the software world where a single issue has multiple statuses.
This occurs for example if you have several versions of a software distribution, and an earlier version has a bug which has been fixed in a more recent release.
You can manage this in bif by creating a project for each distribution version. The bif-push command could then be used to "fork" an issue into another project.
$ bif push 17 other
$ bif list topics
The pushed issue now has an ID and a status for each project it is associated with. However it is still treated as a single set of conversation threads. Updates to one ID are visible to all the others.
$ bif update 45 closed
$ bif show 17
Similarly, running bif-log on either of the two issue IDs will produce roughly the same output.
The above scenario limits itself to local repository actions. However the real value of bif comes from its collaboration capabilities with others via the internet.
We now consider the case of a distributed team (i.e. a project organisation) working closely together on a project. In the context of bif this assumes the existence of a organisational hub for exchanging updates:
User A <--> Organisation <--> User B Hub ^ | User C
To make your local reposistory aware of the project organisation you use the bif-clone command with the location of your organisation's hub. Authenticated hubs obviously need some kind of prior communication with the hub administrator to obtain access.
$ bif clone ssh://demo.v1@bifax.org
The first thing to check is that the organisation and its hubs have been imported:
$ bif list orgs
$ bif show demo.v1
You may have noticed that bif-list-orgs has the same output format as bif-list-projects. Well it turns out that "org" (short for organisation) objects in bif are in fact projects as well. So if your organisation/project is comprised of one or two people you may wish to simply create all your tasks and issues in your org.
However larger organisations will certainly have several "normal" projects in place:
$ bif list projects --all
The --all
flag is needed in this case because by default most bif-list commands only show local (or fully synchronized) nodes. Non-local projects cannot be accurately summarized as indicated by the '*' in place of topic counts.
The reason why project topics are not automatically imported when cloning an organisation is scope and performance. Imagine a large organisation using bif with hundreds of projects and thousands of issues. Very few users would have the interest, time, disk space and bandwidth to import the whole hub.
So we can use the bif-clone command again to import all topics for a particular project.
$ bif clone myproject
When we run the list commands again we see that the project is now fully local.
$ bif list projects
$ bif list topics
All actions from the standalone scenario can be used against imported projects and topics as if they were created locally. Aside from the clone commands no connectivity is required again until you are ready to synchronise repositories.
Changes such as new nodes or updates to existing nodes are exchanged with a hub (in both directions) with the bif-sync command.
$ bif sync
By default all nodes will be synchronised to all relevant organisations, but you can limit that as desired.
bif sync -p unstable # ignore all other projects
[TODO: describe the merge algorithm for meta data]
What is useful after a bif-sync call is to review what updates were transfered from the hub to the local repository. The bif-log command with the [TO BE IMPLEMENTED] option may be useful here.
It is worth pointing out that a hub is obviously a form of centralization and therefore represents a single point of failure when it comes to remote collaboration.
Since we don't like to hear terms like single-point-of-failure when promoting the benefits of distributed bug tracking, bif allows organisations to define multiple hubs. The bif-show command displays all hubs attached to an organisation.
By default bif-sync first attempts to connect with the hub from which the organisation was cloned. If that fails it will work its way through the rest of the list. It is also possible to manually change the order using the --local-set-default-hub
option of the bif-update-org command.
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]
Imagine the situation where a (non-team-member) user has an issue they want to report to a project team.
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 bif-push-issue command is the way to manually ask another project for support on a particular issue. The bif-push-issue command asks for (or can be given) an update message the same way that a bif-update command does:
bif push issue 13 todo2 \
--action fork \
--message "also present in todo v2"
The --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 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 node ID, and can show up in multiple times in the output of the bif-list-topics command. The bif-show-issue command reveals the details:
bif show issue 13
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 bif-push-task action therefore results in a move.
Alternatively the --action copy
option to 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, bif-new-project probably has more interesting mechanisms for copying template-style projects.
Bif comes built-in with time-tracking functionality for those who need it. Time worked is also synchronized across repositories just like regular updates. It works like this:
Say you are managing a software project, and you are releasing a new version but are also continuing to work on your development branch. Rather than having to push each issue separately from the old project to the new we can just fork the old one.
bif new project v2 --fork devel
And notice that the new project has exactly the same issues as the original:
bif list topics
Do you have repeatable projects?
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 --dup
option to the 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 --copy-issues
, --move-issues
and --fork-issues
options, each of which takes a status argument and can be called multiple times.
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.
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 ssh-keygen(1) manpage for how to create a keypair, and 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.
The reason for registering with a hub is to obtain the list of projects hosted there.
bif pull hub my.org@provider.com
By default the 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 bif-list-projects command:
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.
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 bif-pull-project command.
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 bif-sync command. Any new issues or tasks added to the project anywhere will now synchronise locally. Likewise, any nodes 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.
How did a project get up to a hub in the first place? Well the inverse of bif-pull-project is bif-push-project. To mirror the todo project from the local repository to the bifax.org hub for example we would run the following:
bif push project todo bifax.org
As with importing, exporting a project is a one-off activity; further updates are exchanged with the bif-sync command.
New versions of bif will necessarily require changes to the database structure, and possibly the data itself. The 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 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 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 sqlite3
from working for some statements.
Bif is also used to create and manage hub repositories hosted by a hub provider.
If you want to create a new hub and already know the provider's offer & 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:offer host
This is equivalent to the following:
bif pull provider bifhub.com bif new hub hub.name bif signup hub.name offer bif push hub hub.name host
The second step is to register a hub provider, in order to see their hosts and/or availabe offers.
bif pull provider bifhub.com
Listing the offers (offers) and locations (hosts) is possible with the appropriate list
command:
bif list hosts
bif list offers
bif signup my.org bifhub.com:offer2
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:
bif list invoices
The 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 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.
After a push your hub will be available on the designated hosts, and you can inform your team how to register their 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:
bif init
bif push identity 1 your.org@zrh.bifhub.com
Once we have enabled the permissions you can register the hub:
bif pull hub your.org@zrh.bifhub.com
And then import the "devel" project to work on straight away.
bif pull project devel
# bif new issue/task etc...
Don't forget to sync regularly.
bif sync
Thanks,
PM
You can at any time confirm the hub and its status:
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.
Mark Lawrence <nomad@null.net>
Copyright 2013-2017 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.