= Trac Object Model Proposal = == Introduction == Trac is a ''a minimalistic approach to web-based software project management''. To that end, it features ''an enhanced wiki and issue tracking system''. In addition, it also features: * An overview of all the events that happened in the project, by the way of the ''Timeline'' * A structured definition of the ''Roadmap'' for future evolutions of the software * A sophisticated Subversion repository browser * A search facility that covers all the text content of Trac The tight and coherent integration of these features is achieved by several means: * tracking of a single software repository * using a simple relational database to store all the informations about tickets, milestones, changesets and wiki pages. * using a unified ''language'' to talk about objects in the system, by the way of a wiki syntax (TacLinks) which can be used nearly everywhere: * in Subversion commit log messages * in Ticket descriptions and comments * in Wiki pages and change descriptions * in attachments descriptions * ... This unique approach enables a powerful structuring of the information in the system, yet this can be achieved in a very flexible and informal way thanks to that feature. In this light, Trac is a semi-structured Wiki, where one can create and modify ''objects'' and talk about them '''In the following, I'll try to show how those Trac ''objects'' are variations on a same theme, both from the data point of view and from the behavioral point of view.''' == Trac Objects == What can be consider as being a Trac object (''TracObject'') are: * a wiki page (''!WikiPage'') * a changeset (''Changeset'') * a ticket (''Ticket'') * a milestone (''Milestone'') * an attachment (''Attachment'') === Current State === Today, the various Trac objects are quite distinct objects. There is no code sharing between what defines objects and also not so much in the related Modules that manipulates objects. Indeed, those objects have distinct features. But some degree of unification would actually make sense, both in term of increased functionality and in term of decreased code complexity. === Toward an Unification === What would be a generic Trac object? * It would have a unique identity in the system * It would have some wiki syntax to describe it (a ''canonical'' form and also a ''shortcut'' form if possible) * There would be obviously a Wiki description of it * There would be some properties attached to it: * Some would be universal: * an author * a time of creation * Some would be always there for the particular type of object considered * Some would be ''custom'' properties * One would want to be able to attach files to that object * After the main wiki content, there could be a change history, a sequence of summary of commented property changes (or just comments) * The Wiki content of the object could be modified, so there would be an history of changes, the possibility to make diffs between revisions of wiki (see also TighterSubversionIntegration) Let's compare these generic feature with those of current Trac objects, and see what additional functionality and usages it would provide. ==== WikiPage ==== * The unique identity is the Wiki page name. * The wiki syntax is the one described in WikiPageNames. * The Wiki description would be actually the content of the Wiki page itself. * Only a few properties are relevant: * The universal properties (author and creation time) are there, * There's no need for specific properties for a !WikiPage (except maybe a ''readonly'' attribute?) * ''custom'' properties could make sense, but as usual with ''custom'' properties, their presence and pertinence would be site-dependant. * Wiki attachments are there * The change history would be contributed comments only, but that would make sense. That feature is mentionned in the MacroBazaar page. * Wiki history and revision diffs are there ==== Changeset ==== * The unique identity is the revision number * The wiki syntax is {{{changeset:XYZ}}} or {{{[XYZ]}}} * The Wiki description is the original commit log entered in Subversion. This is normally not meant to change, though it can sometimes be handy to fix a typo (therefore the occasional use of the {{{svnadmin setlog}}} command). There are 3 possibilities: * Keep it as it is (read-only) * Enable ''trac-only'' modifications * Provide the functionality of {{{svnadmin setlog}}} * Changeset properties: * The universal properties (author and creation time) are those of the commit information. * The properties specific to a Changeset could be the list of node changes corresponding to that revision. * Custom properties could be used for many things, as a way to annotate the revision. Some ideas are: * a boolean ''compilable'' flag (true by default, could be set to false to indicate that this revision can't be built) * a field indicating the % of successful test cases * a QA status * Attachments for a changeset also make sense: * in case of a build failure, the corresponding errors from the compiler could be attached. * patches that applies to that revision * A change history for a Changeset, wouldn't be that extreme? Actually, the contributed comments could be used for code reviews, another long standing request (#YYY TODO) * Wiki history and diffs would be usefull if the changelog is to be modified ==== Ticket ==== Introducing an object hierarchy was indeed the initial motivator for this proposal. While thinking about request for ''MasterTicket''s (#886), it struck me that ''Milestone''s could be seen as a kind of tickets. (I explained elsewhere (#919) the reasons why I think a categorization of tickets can be important. However, the approach taken in that proposed patch, is, well, just a patch.) A hierarchy of ticket classes would better serve the purpose of a categorization. It can achieve a better repartition of the specific properties. The relationships between these categories could also be done in a modular way. First I'll describe the generic ticket as I did above for the other Trac objects, then I will describe a hierarchy of tickets. * The unique identity for a ticket is its number * The wiki syntax is {{{ticket:XYZ}}} or #XYZ * The Wiki description for that object is the Ticket description * The ticket properties: * The universal properties (author and creation time) also apply here * The specific properties would be: * The short summary * The keywords * An optional due time * Assigned to... * Cc field * Custom properties as usual * Attachments for tickets are there * The change history is there * The wiki history and diff would be usefull if the description is to be modified A generic event can be used to dispatch some information immediately, or to indicate some future event (this needs to be coupled to #ShowFutureEventsInTimeline -- oh, by the way, what about #TicketAliases ?) Then, I would propose the following subclasses: * a !TaskTicket: ''something to be done about something'' * Additional specific properties: * Severity: ''what is the impact of this task?'' * Priority: ''what's the most urgent task among the urgent tasks?'' * Milestone: ''to what Milestone'' object does it relate? * The related component(s) ''(well, a Component could also be a Trac object...)'' * Status (opened/closed) * Resolution: ''in which way the task has been completed'' * !ProblemReportTicket would be a simple subclass of !TaskTicket * !EnhancementRequestTicket would be a simple subclass of !TaskTicket * !MilestoneTicket: ''a collection of Tasks that will happen sometime (due time either set or opened)'' Other possible Ticket types: * Information: ''just to pass some news around (its due time is present)'' * Deployment: ''a specific build has been made available'' ==== Attachment ==== * The unique identifier for an attachment would be its filename, plus the unique identifier of the object it is attached to. * There's currently no wiki syntax associated to an attachment, though in #944, I propose the {{{attachment:filename}}}. This currently works only from the Wiki of the parent object, the one to which the file is attached. What would be needed would be: {{{attachment::filename}}}, where !TracLink would specify the parent object. * The Wiki content would be the optional file description * Properties: * The universal properties also apply for attachment * The specific properties would be: * The size * The mime-type * Ok, attachments for attachments. Now ''that'' does not make sense... * Change history would probably be overkill * Wiki history and diff would probably be overkill here too But have a look to the TighterSubversionIntegration proposal to see that those last features would in some cases prove usefull... ==== Component ==== This would be a subtype of a !WikiPage. Therefore it would share most of what has been said for !WikiPage. In addition, there would be specific fields, like a list of repository paths describing the component in term of software artifacts. This would allow the following features: * automatically relate a Changeset to the affected components. * filter the Changesets in the Timeline to those belonging to a component This is just an example of a new type of Trac object. It may or may not sounds like a good idea, but by the way of the object model, its implementation would essentially focus about how it would interact with the Changeset and Timeline modules. See also TracReleaselist for the Release object... === Summary === The above correspond to the following hierarchy: * !TracObject * !WikiPage * Component * Changeset * Ticket * Task * !ProblemReport * !EnhancementRequest * Milestone * Information ''*'' * Deployment ''*'' * Attachment/File == Implementing Trac Objects == For processing Trac objects and for the logic associated to them, there would be a corresponding {{{Module}}} subclass (see TracPluggableModules). Therefore, the Trac object hierarchy outlined above will closely corresponds to a hierarchy of Python Module classes: * Module (much of the current Ticket code would be moved here) * Wiki * Component * Changeset * Ticket * Task * !ProblemReport * !EnhancementRequest * Milestone * Attachment/File (see TighterSubversionIntegration) But not only that, the Trac object hierarchy will also correspond to a specific object model for the schema in the database. There is essentially two approaches for the object-relational mapping: * For a class, have multiple tables, one for each level in the hierarchy, and join them on the shared identifier. The root level contains also the type of the object. * Have a table for each class, with common column names Each solution has its pros and cons. I will adopt the first approach here, to get things started. Common to all the Trac Objects, there would be a main table and some auxilliary tables: {{{ #!sql -- TracObject ------------- CREATE TABLE trac_object ( id text PRIMARY KEY, type text, time integer, -- the time it was created author text, description text, ); -- for the change history of any TracObject ------------------------------------------- CREATE TABLE object_change ( id text, time integer, author text, field text, oldvalue text, newvalue text, UNIQUE(id, time, field) ); -- for the custom fields associated to any TracObject ----------------------------------------------------- CREATE TABLE object_custom ( id integer, name text, value text, UNIQUE(id,name) ); CREATE TABLE object_custom_multi ( id integer, name text, value text ); }}} Each Trac object would eventually have an extension table, to represent its specific fields: {{{ #!sql -- Ticket (or Milestone) ------------------------ CREATE TABLE ticket ( id text, summary text, keywords text, duetime integer, owner text -- who is this ticket assigned to ); -- Task (or PR/ER) ------------------ CREATE TABLE task ( id text, severity text, priority text, milestone text ); -- Report --------- CREATE TABLE report ( id text, title text, sql text ); -- WikiPage ----------- CREATE TABLE wiki ( id text, readonly char(1) ); }}} Note: the Changeset doesn't need anything in addition to the TracObject fields. Finally, there would be auxilliary tables for some objects: {{{ #!sql -- For Changeset ---------------- CREATE TABLE changeset_node_change ( id text, path text, change char(1) ); -- For Component ---------------- CREATE TABLE component_path ( id text, path text ); }}} == Summary == This proposal aims both at a simplification of the current Trac implementation, which contains a different data representation for each Trac object, and at enhanced functionalities, because the rich functionality that is currently available for Ticket (attachments, change history, custom fields) would be also available for !WikiPage, Report, Changeset, Attachment/File and of course, subtypes of Tickets, like Task and Milestone. This does not mean that all these objects are interchangeable, or that any specific functionality would be lost in the process. Quite to the contrary, each module could focus on what makes it unique, and in which ways it can interact with the other modules, leaving to the generic {{{Module}}} all the shared functionality. ''--ChristianBoos''