Project Flow & Tracker “Paris” bursts into life as a feature – Part 2

Dedicated to the compadres at #drupalcampla

Today we witness the birth of PFT "Paris" as a feature, that is, based on the Open Atrium compatible features family of modules which promise plug and play feature components for Drupal. It should also serve as a useful tutorial on how to get started with features (and a smidgeon of drush and bzr too!). And you can download the whole shebang and enjoy Project Flow & Tracker lite. What we'll do:

Dedicated to the compadres at #drupalcampla

Today we witness the birth of PFT “Paris” as a feature, that is, based on the Open Atrium compatible features family of modules which promise plug and play feature components for Drupal. It should also serve as a useful tutorial on how to get started with features (and a smidgeon of drush and bzr too!). And you can download the whole shebang and enjoy Project Flow & Tracker lite. What we’ll do:

At the end of the previous article in this series I had already installed Open Atrium, and was all set to start working with a new feature. So today we take up where we left off.

Scrum, WIP, GTD, oh my

There has been a lot of talk in recent times about what I would term “here and now” project (life?) manager approaches (such as GTD: Getting Things Done),  as people are recognizing that the times of most productivity one has is when one is focused on a task at hand, running with the ball, in the swim… and that means, less time lurking in the interstices of the backlog and more time spent on WIP (work in progress).

Whereas I am still convinced that iterations have a big role to play, all of this will have a profound affect on the usability of Project Flow & Tracker “Paris”: no matter what you are doing, there will always be a WIP view… no need to reduce everything to WIP if you can always have a view. Anyway, we will come back to this debate in actual practice sooner rather than later in this series of articles.

Let’s get started with features!

OK, let’s get to the meat. On the Open Atrium site, if you click on the Features area you are taken to a listing of the features already bundled with the initial beta release.  There it says:

“If you want a feature that’s not on that list, you can add it yourself. Read the documentation, specifically the How to Build a Feature section, to find out how to do it.”

OK, that’s what we want, to build a feature. Clicking on the howto link, we read:

  1. Build feature (CCK, Views, Context, etc. and exported using Features module), can be done on non-atrium site
  2. Add feature and dependency modules to codebase in admin/modules/contrib and admin/modules/features

The rest of the points will be very useful when it comes time to install our features based component on Open Atrium and take advantage of all the spaces goodness, etc.; but not much is said here about features themselves: “can be done on non-atrium site” kind of sticks out.

We are directed to watch Making and Using Features in Drupal. Which in turn links to a really good features background article on the Development Seed site, which was published when the Features module first came out in May. You might want to take a moment to read that article and watch that video before continuing here. I know I did (wow, that video went by fast…). But I will be explaining what I am doing in my example here step by step: What we are going to do now is install a fresh open atrium and create the feature independently, and step by step.

Starting development environment

For everything we are going to do here, we need drush. You need drush. We all need drush. Fastest way to a bottle of beer. If at this point you are not yet drush enabled, click here .

I’m kind of interested in finding out about using Bazaar as my initiation into distributed version control systems, but Open Atrium (along with Linux and a heck of a lot of other interesting projects often hosted at github) can be checked out directly from its Git repository. In order to avoid complications (best practices are said to follow a cloning of the Open Atrium project as a basis for a development environment, but I want to keep things simple, and also want to keep Project Flow & Tracker as a feature set that can be installed from on any Drupal site), I am going to check out open atrium anonymously (so I can easily update to future releases), and then version Project Flow and Tracker as an indpendent Git sub module (one way to emulate the SVN vendor branch thing).

And as it turns out, to appreciate the generation of a features based component, its packaging as  a tarball, and its installation and enabling on the target site, we actually need two sites set up, one as a “features machine” (features generator), and the other Project Flow & Tracker just waiting to be born by having its features, well, seeded and enabled. Both sites of course could be Open Atrium based, because obviously that comes with the right set of modules to work with features. But just to show exactly what is required, and to maintain that comfortable feeling that comes from knowing it could be installed onto any Drupal 6 site having the proper dependencies installed and be converted it into an installation profile publishable right on good old, let’s build our features generator from scratch!

Features Machine

Mosey on down to a suitable workspace and type:

$ drush dl drupal
Project drupal (6.13) downloaded to /home/victorkane/...... . [success]
$ ls -l
drwxr-xr-x 9 victorkane victorkane 4096 2009-07-01 17:55 drupal-6.13
$ mv drupal-6.13/ features
$ ls -l
$ drwxr-xr-x 9 victorkane victorkane 4096 2009-07-01 17:55 features

I went ahead and installed a basic Drupal instance and pointed my browser at the new URL to carry out the install. Once I was welcomed to my new Drupal site, using drush, I set up all the necessary modules (with a few obvious hints from even though I am not out to build a features server here):

$ drush dl cck context features diff views admin_menu

Then went in and enabled the modules (more easily done with Administer > Site building > Modules than with drush enable {module} due to multitude of sub modules, etc) and wound up with the following:

$ drush statusmodules
Name Enabled/Disabled Description
Administration menu (admin_menu) Enabled Provides a dropdown menu to most administrative tasks an ...
Aggregator (aggregator) Disabled Aggregates syndicated content (RSS, RDF, and Atom feeds).
Block (block) Enabled Controls the boxes that are displayed around the main co ...
Blog (blog) Disabled Enables keeping easily and regularly updated user web pa ...
Blog API (blogapi) Disabled Allows users to post content using applications that sup ...
Book (book) Disabled Allows users to structure site pages in a hierarchy or o ...
Color (color) Enabled Allows the user to change the color scheme of certain th ...
Comment (comment) Enabled Allows users to comment on and discuss published content.
Contact (contact) Disabled Enables the use of both personal and site-wide contact f ...
Content (content) Enabled Allows administrators to define new content types.
Content Copy (content_copy) Enabled Enables ability to import/export field definitions.
Content Permissions (content_permissions) Enabled Set field-level permissions for CCK fields.
Context (context) Enabled Provide modules with a cache that lasts for a single pag ...
Context Contrib (context_contrib) Enabled Provides integration with Context on behalf of the follo ...
Context UI (context_ui) Enabled Provides a simple UI for settings up a site structure us ...
Database logging (dblog) Enabled Logs and records system events to the database.
Diff (diff) Enabled Show difference between node revisions.
Features (features) Enabled Provides feature management for Drupal.
Fieldgroup (fieldgroup) Enabled Create display groups for CCK fields.
Filter (filter) Enabled Handles the filtering of content in preparation for display.
Forum (forum) Disabled Enables threaded discussions about general topics.
Help (help) Enabled Manages the display of online help.
Locale (locale) Disabled Adds language handling functionality and enables the tra ...
Menu (menu) Enabled Allows administrators to customize the site navigation menu.
Node (node) Enabled Allows content to be submitted to the site and displayed ...
Node Reference (nodereference) Enabled Defines a field type for referencing one node from another.
Number (number) Enabled Defines numeric field types.
OpenID (openid) Disabled Allows users to log into your site using OpenID.
Option Widgets (optionwidgets) Enabled Defines selection, check box and radio button widgets fo ...
Path (path) Disabled Allows users to rename URLs.
PHP filter (php) Disabled Allows embedded PHP code/snippets to be evaluated.
Ping (ping) Disabled Alerts other sites when your site has been updated.
Poll (poll) Disabled Allows your site to capture votes on different topics in ...
Profile (profile) Disabled Supports configurable user profiles.
Search (search) Disabled Enables site-wide keyword searching.
Statistics (statistics) Disabled Logs access statistics for your site.
Syslog (syslog) Disabled Logs and records system events to syslog.
System (system) Enabled Handles general site configuration for administrators.
Taxonomy (taxonomy) Enabled Enables the categorization of content.
Text (text) Enabled Defines simple text field types.
Throttle (throttle) Disabled Handles the auto-throttling mechanism, to control site c ...
Tracker (tracker) Disabled Enables tracking of recent posts for users.
Content translation (translation) Disabled Allows content to be translated into different languages.
Trigger (trigger) Disabled Enables actions to be fired on certain system events, su ...
Update status (update) Enabled Checks the status of available updates for Drupal and yo ...
Upload (upload) Disabled Allows users to upload and attach files to content.
User (user) Enabled Manages the user registration and login system.
User Reference (userreference) Enabled Defines a field type for referencing a user from a node.
Views (views) Enabled Create customized lists and queries from your database.
Views exporter (views_export) Enabled Allows exporting multiple views at once.
Views UI (views_ui) Enabled Administrative interface to views. Without this module, ...

Decided to use Bazaar distributed version control to work with this project, so did the following (See Bazaar in five minutes):

$ drush sql dump > sites/all/backup/db/features.sql
$ bzr init
Created a standalone tree (format: pack-0.92)
$ bzr add
[ bzr added all the files ] ...
adding sites/all/modules/cck/modules/fieldgroup/panels/content_types/
adding sites/all/modules/cck/modules/fieldgroup/panels/content_types/icon_cck_field_group.png
adding sites/all/modules/cck/modules/nodereference/panels/relationships/
adding sites/all/modules/cck/modules/userreference/panels/relationships/
$ bzr commit -m "initial minimum install of features machine with context, features and other primary dependencies"
added ... [all files]
added themes/pushbutton/tabs-option-hover.png
added themes/pushbutton/tabs-option-off-rtl.png
added themes/pushbutton/tabs-option-off.png
added themes/pushbutton/tabs-option-on.png
Committed revision 1.

Setting up PFT lite

This is actually a stripped-down version of PFT I have been using successfully with many clients. A short overview of PFT lite capabilities:

  • Creating and listing roles and user stories
  • Prioritizing the user stories
  • Writing acceptance tests for each user story
  • Tracking your project

After the roles and user stories have been entered, a simple view allows for a basic tracking capability:

Tracking with Project Flow & Tracker Lite

This is plenty for many small to medium sized projects that just need to show WIP (work in progress) and where you are at in a basic burn down context.

To get it going I did the following:

  • Imported a simple user story content type
  • Created simple tag taxonomy for Roles, and apply to user story content type
  • Created simple tag taxonomy for Projects, and apply to user story content type
  • Imported the view (includes WIP primary menu entry to invoke it)
  • Populated with sample data for the Project Flow & Tracker project

And the result is:

PFT initial setup on Features Machine


Whoaa! We’ve created a bare-bones but usable PFT in its own right… There are tons of features (hmmm) left out, there is no access control, there is no features/user story/task  hierarchy, there are no project documents (although you could use the project taxonomy applied to any content type for that (books for example) and add exposed filters to the WIP view, but we’ll see how that goes later on in this series of articles)

Hmmmm. So, first, we’ll create the feature, download it, and it could be installed onto any D6 site having the contrib module dependencies installed. Or we could convert it into an installation profile for vanilla off-the-shelf D6 which  could be published right on, which is comforting.

So let’s see if we can get the feature going.

Exporting PFT lite as a feature

Want to save the state of the project in bzr before we go on.

$ drush sql dump > sites/all/backup/db/features.sql
$ bzr status
$ bzr commit -m "PFT lite initial setup"
Committing to: /home/victorkane/Work/AWebFactory/projects/FeaturesMachine/features/
modified sites/all/backup/db/features.sql
Committed revision 2.

We go to Administer > Site building > Features and click on the Export link. We fill in the info as follows:

exporting pft as a feature - 1

We click on the Next button. We indicate that we wish to include the user story content type and the list_user_stories view:

exporting pft as a feature - 2

We click on the Next button. Now we are asked to confirm the components, and this gives us a chance to specify any module dependencies:

exporting pft as a feature - 3

We can always update later, but for now we include basic CCK and Views stuff, and click on the Next button. We are presented with our downloadable feature:

exporting pft as a feature - 4

So we click on the Download feature button and save pft_lite-6.x-1.0-alpha1.tar.gz to our local file system (It is attached here: be sure to change the security conscious tar_.gz extension to tar.gz in order to be able to unpack the tarball).

So to finish up, let’s take a look at what we have in the feature tarball, and, most importantly, let’s install it in our Project Flow & Tracker site and see if it works 🙂 (If you want to skip “seeing what we have” click here to go directly to installing it and seeing if it works).

Seeing what we have

So, inside the tarball, there is a module 🙂

$ tar xvzf pft_lite-6.x-1.0-alpha1.tar.gz
$ ls -gG pft_lite
total 32
-rw-r--r-- 1 20107 2009-08-09 07:26
-rw-r--r-- 1 606 2009-08-09 07:26
-rw-r--r-- 1 1398 2009-08-09 07:26
-rw-r--r-- 1 46 2009-08-09 07:26 pft_lite.module

The module info file, as alway, describes what we have:

$ cat pft_lite/              
core = "6.x"
package = "Features"
project = "pft_lite"
name = "PFT Lite"
description = "Bare bones Project Flow & Tracker user story project management system"
version = "6.x-1.0-alpha1"
features[content][] = "user_story-field_us_burned_points"
features[content][] = "user_story-field_us_confirmation"
features[content][] = "user_story-field_us_conversation"
features[content][] = "user_story-field_us_points"
features[content][] = "user_story-field_us_priority"
features[content][] = "user_story-field_us_state"
features[dependencies][] = "content"
features[dependencies][] = "content_copy"
features[dependencies][] = "content_permissions"
features[dependencies][] = "menu"
features[dependencies][] = "nodereference"
features[dependencies][] = "system"
features[dependencies][] = "taxonomy"
features[dependencies][] = "user"
features[dependencies][] = "userreference"
features[dependencies][] = "views_export"
features[dependencies][] = "views_ui"
features[node][] = "user_story"
features[views][] = "list_user_stories"
dependencies[] = "content_copy"
dependencies[] = "content_permissions"
dependencies[] = "features"
dependencies[] = "menu"
dependencies[] = "node"
dependencies[] = "nodereference"
dependencies[] = "number"
dependencies[] = "system"
dependencies[] = "taxonomy"
dependencies[] = "user"
dependencies[] = "userreference"
dependencies[] = "views_export"
dependencies[] = "views_ui"

You can see the dependencies[] entry in many modules: it is used to list the modules that this module assumes to be installed and enabled, and figuring prominently in the list is, of course, the Features module itself. Thanks to it being installed, the rest of the info makes sense and can be understood by how we entered information onto the forms on the screens involved in the features export itself.

The module file itself has only a single line:

$ cat pft_lite/pft_lite.module


The file invoked by the module,, basically executes the installation of the specified components, including the default fields (which bundled together conform the content type), the node info, and the default view(s) we have included:


* Implementation of hook_content_default_fields().
function pft_lite_content_default_fields() {
module_load_include('inc', 'pft_lite', 'pft_lite.defaults');
return _pft_lite_content_default_fields();

* Implementation of hook_node_info().
function pft_lite_node_info() {
module_load_include('inc', 'pft_lite', 'pft_lite.defaults');
return _pft_lite_node_info();

* Implementation of hook_views_default_views().
function pft_lite_views_default_views() {
module_load_include('inc', 'pft_lite', 'pft_lite.defaults');
return _pft_lite_views_default_views();

As you can see, the details (the exportables, the user story content type, the list_user_stories view, etc.) are to be found in the remaining file, which we won’t list here since it is included in the attached downloadable feature pft_lite-6.x-1.0-alpha1.tar_.gz  (rename …tar_.gz to tar.gz).

So, that’s what we we’ve got. Does it work?

Installing it and seeing if it works

In the next article in this series we will install the feature into an Open Atrium site and integrate: that will be exciting. Today, however, what we want to see is how an exported bare bones feature can then be imported into a vanilla Drupal installation (having the features module installed, of course, together with the other dependencies) and… just work.

What we need, actually, is our Features Machine as it was before we set up the PFT Lite functionality.

Fortunately, since we have been using Bazaar (bzr), it is simple to roll back the clock.

$ bzr log                                          
revno: 2
committer: Victor Kane <>
branch nick: features
timestamp: Sun 2009-08-09 07:01:28 -0300
PFT lite initial setup
revno: 1
committer: Victor Kane <>
branch nick: features
timestamp: Sat 2009-08-08 16:59:33 -0300
initial minimum install of features machine with context, features and other primary dependencies

We need to turn the clock back to Revision 1, refresh the database with our backed up SQL file corresponding to that snapshot, test that there is no trace of the PFT Lite functionality we had set up after that, install the feature as a module, and test.

Reverting to Revision 1 and seeing what we have

Wait, won’t that be complicated? Not with bzr:

$ bzr revert -r 1
M sites/all/backup/db/features.sql

Go ahead and restore the database to its snapshot state with the features.sql file, and check that there is now no trace of PFT Lite functionality.

Caveat: since the database contains content field info, you actually want to zap the database completely before restoring, otherwise CCK might go a little crazy when you create user stories again. Do this (the drush status command will tell you what the database name is for the site) in order to empty the database and restore the saved sql file:

$ drush status
PHP configuration : /etc/php5/cli/php.ini
Drupal Root : /home/victorkane/Work/AWebFactory/projects/FeaturesMachine/features
Drupal version : 6.13
Site Path : sites/default
Site URI : http://default
Database Driver : mysqli
Database Hostname : localhost
Database Username : features
Database Name : features
Database Password : [erased here but drush will show it]
Database : Connected
Drupal Bootstrap : Successful
Drupal User : Anonymous
victorkane@victorkane:~/Work/AWebFactory/projects/FeaturesMachine/features$ drush sql cli
Welcome to the MySQL monitor. Commands end with ; or g.
Your MySQL connection id is 2878
Server version: 5.0.75-0ubuntu10.2 (Ubuntu)

Type 'help;' or 'h' for help. Type 'c' to clear the buffer.
mysql> drop database features;
Query OK, 57 rows affected (0.01 sec)

mysql> create database features;
Query OK, 1 row affected (0.00 sec)

mysql> use features;
Database changed
mysql> source sites/all/backup/db/features.sql
Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
mysql> exit

By the way, normally you can restore that file with drush’s invocation of the MySql command line, and pipe in the sql file, like this (ignore any pesky warning signs, don’t mean a thing):

$ drush sql cli < sites/all/backup/db/features.sql

Then, go to the home page, and the Primary Menu item “WIP” is gone, along with everything else we did after we committed revision number 1 to bzr. No content items, no views, nothing up my sleeve.

Installing the feature

Install the pft_lite module to sites/all/modules just as you would any module, but to enable it you do NOT go to Administration > Site building > Modules, as usual, but rather to Administer > Site building > Features, where you will find it listed. Select the checkbox to enable the feature:

Enabling a feature we have installed ourselves

And click on the Save settings button.

Just for good measure, clear all caches (in the admin menu on the left hand side, mouse over the Drupal icon and click on flush all caches.


Lo and behold, our WIP primary menu item has miraculously appeared once more!

Our feature revealed once again!

Hellelulya sister and brother, you have installed your own feature! Nothing can stop us now.

Clicking on WIP lists nothing, of course, since we imported the site structure, not the content. However, clicking on Create content will offer the choice of creating some user stories, which you can do very quickly, and we are all set up with PFT Lite once again.


Currently, taxonomy is not covered by the Features module since it does not in and of itself create an exportable. Since we are dealing here with two simple tag vocabularies which take just a few moments to set up, that is not a problem. Otherwise you can make use of one of the taxonomy export modules (for example see in the Features module issue queue). Taxonomy and other elements will surely soon be covered by exportables and will therefore be able to be included in features in their own right.

Road map: expanding integration with Open Atrium

In the next article, we will import into our Open Atrium site and explore integration with those features, that will be pretty exciting (coming next week).


  1. Features module:
  2. Context module:
  3. Open Atrium site:
  4. Making and using features (article):
  5. Making and using features (video):
  6. Build a feature howto on Open Atrium site:
  7. Lullabot podcast on this subject (make sure you listen to it AND read the comments):
  8. Bazaar in five minutes:
  9. Bazaar User’s Guide:
  10. Drush module:
  11. Excellent guide to installing drush: