Project classifiers (aka labels)
Consider merging this page with Multi-Project Support for Trac
In order to provide an structured solution so as not to limit the possible ways of grouping projects it is convenient to introduce the concept of project labels. Main goals are the following :
- Offer a structured mechanism to identify a group of projects no matter what hierarchy is involved .
- Encapsulate these details at the API level while determining (multi)project context.
Considering the reference example,
in spite of searching for tickets
in Family A
and Family B
but not in Tools
and 3rdParty
when needed,
a label containing both projects has to be created (either explicitly or
implicitly, see below) .
This document also suggests alternatives and approaches to implement some features defined in Multi-Project Support for Trac. Some content may actually overlap aforementioned specification.
URL space for different projects
A constraint should be imposed in order to simplify dispatching strategy so as to map projects to URLs. Project short name MUST be unique in the context of an environment.
- host mapping: the name of the (virtual) host used to access the Trac environment is taken to be the name of the project. A given host can be configured to be an alias for the default, top-level project. Label names are not allowed to be used this way.
- prefix mapping: if the
PATH_INFO
starts with/p/<project name>/
prefix, name of a project will be taken to be<project_name>
. Otherwise if it starts with/l/<label_name>/
then the request is addressed to the set of projects included in label<label_name>
. In general this is less ambiguous than the mapping suggested in original proposal. Explanation and implementation details provided below.
The Data Model and the API
Labels may be considered as resources bound to the environment rather
than to particular projects (e.g. like Changeset
and Source
which belong
to a given repository - see MultiRepos). Hence only an
additional labels
table is also needed, and it can take the form of a
resource table specialization from the GenericTrac. Project labels should
have at least short name (and maybe description) field. Project labels can be
linked explicitly to projects and labels (if using nested labels).
These connections can take the form of relations from
Trac Relations.
I think it is vital that labels be first-class objects with history (like tickets, not milestones). Say I have a
.../l/Label1
link somewhere in a wiki page or ticket description or something. Today Label1 points to ProjectA, ProjectB, and ProjectC but for whatever administrative reason, ProjectC gets reclassified or cancelled or something. I might click through my link and wonder where all the ProjectC stuff went. If labels have history, I can go look and see, "Oh, Bob cancelled Project C yesterday. He said, 'Customer Foo cancelled their order.'" — Chris Nelson, 4 Jan 2012
URL prefix mapping explained
Project-specific URLs will start with /p/<project name>
prefix.
Requests involving multiple projects will be made available on a per-label
basis at URLs starting with /l/<label name>
prefix. Remaining path after
this will be used to select what instance of IRequestHandler
should process
the request. Examples below illustrate some use cases. In all cases
multi-project environment root URL is http://server.com/path/to/trac/
and
it will contain the reference project hierarchy used throughout this document :
URL | Target projects | Comments |
http://server.com/path/to/trac/ | top-level project (i.e. '' ) | |
http://server.com/path/to/trac/roadmap | top-level project (i.e. '' ) | Top-level milestone view. This may be used to show top-level (e.g. product, current year, …) milestones. |
http://server.com/path/to/trac/p/FamilyB/roadmap | project FamilyB | FamilyB project-specific milestones. |
http://server.com/path/to/trac/p/product_c/roadmap | project product_c | product c project-specific milestones. |
http://server.com/path/to/trac/l/javascript/roadmap | all projects in label javascript | display milestones for javascript projects. |
By doing things this way request dispatch may be implemented as a combination of
two existing architectural features , namely request filters and
request handlers. First of all by supporting multi-project
specifications the context associated to the request has to contain
information about target project(s) . One component acting as a request filter
intercepts the request before match is performed. If any multiproject
prefix (i.e. /p/<project name>
or /l/<label name>
) is detected then
project resolution takes place. Single-project requests only
need to add corresponding internal project resource to context.
In the case of labels the context should contain label name as well as a
list of resources identifying target projects . In the case of
more complex project selector expressions the context should contain the
expression itself, the instance of IProjectLabelManager
matching label name,
and the list of resource objects identifying target projects . If this
advanced feature will be supported, it may be considered as a generic way to
encapsulate multi-project context in spite of having flexibility and uniformity,
considering the fact that first two variants are just particular cases.
Aforementioned data may be retrieved right away at dispatch time or loaded
on demand.
Immediately after multi-project context resolution, the request filter rewrites
PATH_INFO
by removing project selection prefix. The request is then
matched as usual so as to determine the handler responsible for processing it
(e.g. wiki
, ticket
, …). The target instance of IRequestHandler
will
rely on request context so as to determine target projects involved and
build the response accordingly.
Advanced labels features
Subsequent sub-sections deal with some advanced features that may be useful
under certain circumstances but may also over-complicate core design .
Nonetheless I mention them here for the sake of
could not find the right word.
Project alias
A label related to a single project may be considered a project alias. This scenario may happen when two or more projects are merged and previous project name is to be kept so as not to break external references, for instance.
Nested labels
It might be convenient as well to provide a way to specify a hierarchy of
labels (rather than projects). In order to illustrate this with a particular
example which might be very common in practice, let's consider we have the
sample hierarchy of projects
and still need to
group them according to programming languages and frameworks used to build
them (let them be explicit project dependencies or not). In that case it will
be useful to have some labels like javascript
, python
, c#
, vb.net
,
f#
, ruby
, php
and so on. Let's also consider a similar situation
and project classification also includes frameworks, so there are further
tags like e.g. trac
, wcf
, jquery
, mootools
, wpf
, django
, dojo
, …
Nonetheless :
- It may be useful to know which projects are related to .NET framework.
- It may be useful to ease the process by tagging projects using a single label identifying a framework and having them auto-magically included in the label for the corresponding programming language .
In order to do that the following label hierarchy might help :
+-- python | +-- trac | +-- django +-- ruby +-- javascript | +-- jquery | +-- dojo | +-- mootools +-- .net | +-- .net languages | | +-- c# | | +-- vb.net | | +-- f# | +-- .net technologies | | +-- wpf | | +-- wcf | | +-- wwf +-- php
For instance , Trac-Hacks website may be one such
example where there's a flat one-level project hierarchy and labels to group
hacks. In Apendix B it is possible to see
sample label hierarchy based on hack classifiers available at present. Idea
is , for instance, that if somebody tags a project using macro
label then
it also belongs auto-magically in plugins
label.
There's another precision that needs to be mentioned up to this point and it
is whether it is more convenient to define label relationships using graphs
rather than a tree . Considering the same case mentioned above ,
labels like iron_python
, iron_ruby
would be hard to
classify considering aforementioned hierarchy as they may be related to both
.net
and (python
| ruby
) (same reasoning for e.g. jpype
, jython
for
python
& java
; rython
, unholy
for python
& ruby
… and it's
possible to find more examples even in totally different business domains).
Project context extensions
It may be useful to be able to specify special project groups like :
- all parents of project A
- direct children of project B
- descendant of project C
*
all the projects (mentioned in original Multi-Project specification)- glob pattern (mentioned in original Multi-Project specification)
!
prefix to exclude projects (mentioned in original Multi-Project specification)- comma-separated list of project names (e.g.
FamilyA,product_d,3rdParty
) - XPath expressions
These are just a few examples. In order to prepare the system for flexibilty
and maybe allow the definition of other project selector expressions (e.g. in
plugins) it is convenient to introduce a new interface
(namely IProjectLabelManager
) used to determine which projects belong in a
given label, provided its name. Selection should work using a chain of
responsibilty similar to the one already used for IRequestHandler
. All
instances of IProjectLabelManager
are requested to expand a project selector
expression. This will consist of returning a list of project names matching
a given label name (aka project selector expression ⇐ this seems to be
more generic ;) , or None
if such match is not found. In the later case
the next instance of IProjectLabelManager
is considered and so on … until
either a match is found (and subsequent request handling takes place) or all
options are exhausted (and error handling occurs e.g. HTTP 404 Not Found
returned to the client) .
User interface
Considering everything mentioned up to this point , the following variants of project selector GUI control are suggested.
Project selector (drop-down menu)
The use of labels makes possible to present a flat drop-down menu to the user in order to select a set of projects like shown below. This may be considered more appropriate than always having to display a hierarchy.
PS: Create new label … option should be visible only if user can create labels. If the user can modify labels (i.e. classify projects in categories) then it may be useful to include shortcut links to update projects membership. In both cases a dialog (see picture below) should be displayed.
Project selector (tree view)
Another option is to provide a more ellaborate version of the box suggested in Multi-Project Support specification. One of the benefits is that it will be possible to select either projects or labels. It should look like this
Once label is selected then target projects should be highlighted like above.
Ideally it should be possible to drag a project & drop it on an item representing a label in order to add that project to that label (a confirmation box may be shown so as to detect mistakes).
Label membership editor dialog box may be displayed as well so as to edit a label if user clicks on Edit link.
Appendix A : Other systems supporting labels
Other similar examples of the use of labels in other products are :
- Google+ circles which allow to group people,
- GMail contact groups which serve to a similar purpose
- GMail labels which allow to mark e-mails
Other instances of similar label hierarchies :
- GMail nested labels.
Appendix B : Proposed label hierarchy for Trac-Hacks
This section considers just a subset of Trac-Hacks classifiers.
+-- supported-version | +-- 0.1 | +-- 0.10 | +-- 0.10.4 | +-- 0.11 | +-- 0.11.5 | +-- 0.11.6 | +-- 0.12 | +-- 0.12-compatible | +-- 0.12dev | +-- 0.13 | +-- 0.3.4 | +-- 0.4 | +-- 0.5 | +-- 0.5dev | +-- 0.8 | +-- 0.9 | +-- 0.9.1 | +-- 0.9.2 | +-- 0.9.6 | +-- 1.1dev | +-- trunk | +-- anyrelease +-- db | +-- sql | +-- sqlalchemy | +-- sqlite | | +-- sqlite3 | +-- postgresql | +-- mysql +-- plugin | +-- macro | +-- theme +-- scripts +-- patch +-- integration +-- translation +-- workflow