Setting up TRAC on macOS

Trac Logo

For those who haven’t heard of it yet, TRAC is an open source combination of a ticket and a wiki system mixed with version control integration written in Python. It’s great for organising work especially in small to mid-size development teams but due to the large number of plug-ins and its incredible plug-in API, one can even customise it to cover other aspects of a business. I had meant to write a blog post about it for a while, mostly as a cheat sheet for myself or as a reference to point others to. Since I had to move my personal TRAC to a new machine it is the perfect occasion to write it down for once. So here goes …

At the time of writing, the latest stable TRAC release is 1.2 with Trac 1.3 being in development. When using a different version, your milage my vary when it comes to plug-in compatibility.

A TRAC Environment

The general concept of TRAC is that one server can host multiple separate TRAC environments, for example one per project or product line. Each environment has its own Wiki and tickets as well as various configuration options. Plug-ins can be installed globally or on a per-environment level which keeps everything nice and tidy and makes it easier to move to a new server, etc.

Tickets can be organised within milestones or versions, which are two completely orthogonal things in a standard TRAC installation (more on that later). Each ticket also has a severity, a component and additional fields can be added and are sometimes required for specific plug-ins to work. The workflow of tickets (new, approved, assigned, closed, verified, …) can be also be customised but in general default works quite well.

The Wiki should feel comfortable to anyone that has ever worked with a markup system. What’s great is that one can use markup to link to milestones, tickets, commits and other things within the environment. The wiki-syntax can also heavily be extended by plug-ins.

As you may have noticed, TRAC is very flexible and a lot depends on how you want to use it. There will be some advise on that later on. For now, the goal shall be to setup a TRAC environment and get it up and running.

Trac Screenshot Ticket View
Ticket View in TRAC

Installation

Getting the base TRAC installation is easy. Open up Terminal and run

sudo easy_install Trac

This will put (among other things) two binaries into your /use/local/bin folder:

  • trac-admin: The admin console tool to create, administrate and upgrade TRAC environments (more on that later)
  • tracd: The standalone trac server. TRAC is usually hosted as a module inside Apache but can be run as a standalone processes as well.

Creating the Environment

A new environment is created by using

trac-admin /path/to/myproject initenv

On macOS, I usually use /Users/<username>/Documents/Trac/<projectname> but it can be pretty much anywhere. Enter the project name and just confirm that database question. We will have to adapt some things in conf/trac.ini but that can come later.

What you also want to do is add a user for yourself that can serve as TRAC admin:

trac-admin /path/to/projenv permission add <username> TRAC_ADMIN

Launching

TRAC is a server-based application and it is accessed via the web browser, no client needed. So the first choice is how to serve it, as

  • an Apache module – or –
  • a standalone application

While the second one is less secure/robust according to the documentation, I’ll pick that route because I usually used it in closed environments within a single company and therefore no risks of hacking attacks and the likes.

You don’t necessarily need to have a separate server, it’s just as well to run it on your own machine if no one else needs to access it. For sake of simplicity, I’ll assume you have a Mac and want to have it running on your own machine to try it out. Moving things to a server later on is pretty easy.

Using tracd can have some weird effects (especially when running as a service on Windows and you need to shut it down a lot because you want to mess with plug-ins) which is why I would advise to use a slight variation of the second route and directly use python to start TRAC’s standalone.py script. It is part of the TRAC source and you can download the 1.2 version from the repository. I usually store it in /Users/<username>/Documents/Trac so I have my environments and everything else TRAC-related in one place.

Create a new file called trac.sh and add

#/bin/bash
python /Users/<username>/Documents/Trac/standalone.py --port 8000 --auth="*,/Users/<username>/Documents/Trac/users.htdigest,Trac" /Users/<username>/Documents/Trac/<projectname>

Make the file executable by using

chown a+x trac.sh

This launches TRAC on port 8000 with the specified environment. If you want to host multiple environments, just add their path as well. The user.htdigest file is for storing passwords and will come to that later.

Open a browser on http://127.0.0.1:8000/<projectname> and you’ll see your TRAC environment.

Authentication

There are various methods that can be used for user authentication. The easiest is to us an htdigest file. First, add a new user

trac-admin /Users/<username>/Documents/Trac/<projectname> add <newuser>

Then call with the same username

htdigest -c /Users/<username>/Documents/Trac/users.htdigest Trac <newuser>

This will create an entry in the digest file which stores a hashed version of the users’s password.

Plug-Ins and Optional Stuff

Before we get to configuration, let’s install a couple of helpful things. The TRAC community usually posts their plug-ins on TRAC hacks where you can find many, many more. Be aware that the quality of plug-ins can vary greatly. For example, the RevTree plug-in mentioned below at one point had a bug in it that called random.seed() and thus messed up the way session tokens were generated which caused log-in mixups. Took me a couple of days to track that one down…

Note that it sometimes may require a restart of the TRAC server or an upgrade of the database (using trac-admin) to get a plug-in running.

SVN Bindings

Most of my projects are still in SVN (but GIT works equally well with TRAC). If we want to connect TRAC with an SVN repository, we need to install the Python SVN bindings. The easiest way on macOS to do this is to install Homebrew.

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

Then we can use brew to install the SVN bindings for us as shown in this Stackoverflow post:

$ brew install subversion --with-python
$ mkdir -p ~/Library/Python/2.7/lib/python/site-packages
$ echo $(brew --cellar)/subversion/1.9.5_1/lib/svn-python > ~/Library/Python/2.7/lib/python/site-packages/svn.pth

(note: the version number in the path, i.e. “1.9.5_1” is dependent on the latest version of the SVN bindings when you install it. In the original post it was 1.8.5, at the time of writing 1.9.5_1. Use “cd $(brew –cellar)” to go to the brew folder and check out what version you installed).

Extended Version Plug-In

Extended Version is a plug-in that let’s you group milestones within versions. This is the way most companies I have seen think in: There are milestones (or feature), some are mandatory for a certain version, others might not be associated with a version until they are out of an early development/prototyping phase.

Note that the plug-in currently needs some work to run with TRAC 1.2. But this is a great opportunity to show how basic plug-in development works! Download the source from the plug-in website on Trac Hacks. In the trunk, apply the latest patch that I attached to the ticket. Go into the directory where setup.py lies and run

python setup.py bdist_egg

which will compile and bundle everything into a Python egg. In your TRAC, go to the Admin Tab, Plug-Ins and there you can upload and install the egg into TRAC. You should also check out the document of a plug-in on its website. Most come with some form of configuration options that you can set in trac.ini to change their behaviour.

RevTree Plug-In

This plug-in produces some of the nicest and most helpful branch-visualisations I have ever seen. Problem is that the official trac-hack repo is not maintained and it currently doesn’t work with TRAC 1.2. There is a fork here that almost  works (there is a missing comma in setup.py after “templates/*.html” which results in a KeyError exception) but it changed the database schema and I wasn’t able to have it produce results with my existing TRAC environment.

I have started fixing the original version on trac-hacks instead and will post results here when done.

Trac Menu Plug-In

Another goody is the Trac Menu Plug-In which lets you re-organize the TRAC menu bar hierarchical. Again, this unfortunately does not seem to work with TRAC 1.2 right now and I’ll try to patch it soon.

Honorable Mentions

The following are plug-ins which I do not consider essential but which are of great use:

  • TOC Macro Plug-In: Adds the [[TOC]] macro to the wiki markup which generates a table of contents for the page it is inserted in. This has ended up in most wiki pages I have written.
  • NoteBox Plug-In: Adds a simple macro to add note/warning/error boxes inside a wiki page. Very helpful when writing larger documentation.
  • Full Blog Plug-In: I’m a big proponent of internal blogs to spread news throughout a company or team. It’s just better to have things achieved then sending mails to all team members.
  • Subcomponent Plug-In: We use this very successfully in an old company of mine. Allows you to hierarchically order components (e.g. UI/Windows, UI/Mac, …)
  • Tags Plug-In: Adds a tag-cloud and tagging capability to the environment.
  • Downloads Plug-In: Adds a Download section to your TRAC which can be tagged or referenced from within the Wiki
  • Autocomplete User Plug-In: Autocompletes user names, quite handy when assigning tickets to users.
  • Clone Ticke Plug-In: I personally didn’t have problems filling out tickets manually, but ex-colleagues of mine were a big fan of this one to save time.
  • DoxyGen Plug-In: Basically adds a menu entry that links to your existing DoxyGen documentation and adds doxygen to the wiki markup.
  • Gantt Calendar Plug-In: I used this very successfully for project planning and vacation management (add tickets for team member vacation). If I remember correctly, the official version had some problem and there was an unofficial version from a Japanese guy that you’ll probably find with some googling.
  • Private Wiki Plug-In: This lets you restrict access to certain sub-wiki parts. Great if you want to put things in the TRAC that that 2-week intern should see.
  • Screenshots Plug-In: Adds a gallery.

Configuration

Now comes the important part: configuring TRAC for how you want to use it. Most of this can be done via the Admin-panel inside TRAC.

  • In Basic Settings: Set the default handler to WikiModule. This just made the most sense to me, especially if you write a nice intro page with links to the most important parts.
  • In Permissions: Remove all rights given to anonymous. As trac admin, you automatically have all rights. But you can create groups and assign them individual rights like “the source should only be visible to members of the developer group”. You have to figure out which groups work for your company but in general it’s a good idea to start with the least amount of rights and then add on demand.
  • In Components: Add components for relevant areas of your code. These can be attributed to tickets and make searches easier. So it is usually a good idea to not have too many components but enough that you can for example see what hot spots you have if you look at all open tickets grouped by component. For example, the animation subsystem might be one component, the user interface another, and so on.
  • In Priorities: I found it helpful to redefine priority names such that there is no question into what group a ticket belongs. I mean, what really is “normal” and what is “major?”. What I used successfully is:
    • “blocks development”: This actively blocks someone and must be solved as soon as possible
    • “essential for milestones”: All of these need to be solved or otherwise the milestone cannot be considered complete.
    • “normal”: This is stuff that is relevant and one would usually expect to be done for a milestone. But if time gets short, they could be dropped to a later release without the milestone feeling incomplete.
    • “optional”: This is purely optional. It might be a nice idea to do if there is still time but nobody will miss them if not.
    • “to be discussed”: This proved very helpful when set as the default. If someone creates a new ticket, it should be this priority until the owner of the milestone or project owner has evaluated the priority. By having this artificial priority, it allowed us to create tickets for everything, every bug or idea no matter how unimportant it seemed. The milestone owner would at least consider it and the file correctly.
  • In Ticket Types: Most people will intuitively create too many types but it usually boils down to what level of separation actually presents value. You could argue that every ticket is a task after all:
    • “bug”: This is a bug, something that should not be. It implies that it can either be solved without major changes or is a fundamental flaw that should immediately be considered.
    • “enhancement”: This is something that enhanced existing functionality as opposed to adding new stuff.
    • “task”: This is the default work item, it’s just part of feature development.
    • “testing”: Something needs to be verified or a unit test written, but it does not require any coding per se.
  • In Versions: What works great is to use a 3 digit versioning schema (e.g. 1.0.3). This way you can separate between major (once a year or so, breaks or introduces a lot of things) and minor (adds new features but keeps compatibility for the most) or bugfix (no new feature, just bugs) releases.
  • In Repository: add your SVN (or other) repository.

SVN Integration

One of the most interesting aspects of TRAC is the way it interacts with a version control system. You can configure it such that you can close tickets with an SVN commit message or link bug tickets and the commits that fixed them.

To do this, you need to setup your repository inside TRAC. However, TRAC also needs to know when the repository changes. This is done using post-commit hooks which have to be added to your SVN repository:

Go to your SVN repository and the subfolder “hooks”. Create a copy of post-commit.tmpl and name it “post-commit”. Inside it, remove all the content and simply add:

#!/bin/sh
/usr/local/bin/trac-admin /Users/<username>/Documents/Trac/<projectname> changeset added "$1" "$2"

This way every time a commit is done, TRAC is called and it can cache the required information about the commit in its database. You also need to activate to plug-ins that already come with TRAC:

  • CommitTicketReferenceMacro
  • CommitTicketUpdater

If you unfold the latter entry in the plug-ins list, you’ll see a summary of the command syntax. The most important are “refs #5” to add the commit message as a comment to ticket 5 and “closes #6” to do the same to ticket 6 but also close it.

When you initially activate the binding, it makes sense to once tell TRAC to sync with the repository.

trac-admin /Users/<username>/Documents/Trac/<projectname> repository resync "*"

This will force TRAC to pull the commits into its own cache.

Using the Wiki

Here are some tips for using the Wiki:

  • When editing a page, there is a small check box that says side-by-side editing. Activate it to get a live preview of your text. Using this helps with user acceptance, especially for those that are not used to write markup.
  • Check out the macro help page (follow the formatting help link on the edit page). What is great about trac is that this help page is dynamically created and  each plug-in you have installed will automatically add its documentation to this page.
  • Images are integrated by attaching them to a page and then using the [[Image(…)]] macro.
  • The wiki content is version controlled inside the TRAC database, attachments are not!
  • Use sub-wikies (e.g. a name and slash before the actual wiki page name) to organise your content. Add links to the TRAC menu that directly lead there (e.g. one for “user manual”, one for “dev docu”, …)

Configuring trac.ini

For completeness sake, here is the configuration file I’ll currently use. Some things might need adjustment for your paths or depend on the plug-ins you have installed. But it should serve as a reference. If tried to mark the interesting bits.

# -*- coding: utf-8 -*-

[attachment]
max_size = -1 #disables size limitation for attachments
max_zip_size = -1 # disables size limitation for attachments
render_unsafe_content = disabled

[browser]
color_scale = enabled
downloadable_paths = /trunk,/branches/*,/tags/*
hide_properties = svk:merge
intermediate_color = 
intermediate_point = 
newest_color = (255, 136, 136)
oldest_color = (136, 136, 255)
oneliner_properties = trac:summary
render_unsafe_content = disabled
wiki_properties = trac:description

[changeset]
easy_install http = //trac-hacks.org/svn/extendedversionplugin/trunk
max_diff_bytes = 10000000
max_diff_files = 0
wiki_format_messages = enabled

[components]
extendedversion.* = enabled
extendedversion.db.extendedversionssetup = enabled
extendedversion.milestone.milestoneversion = enabled
extendedversion.roadmap.releasesmodule = enabled
extendedversion.version.visibleversion = enabled
mergeinfoenhancer.enhancer.mergeinfoenhancermodule = enabled
notebox.macro.noteboxmacro = enabled
revtree.* = enabled
revtree.api.revtreesystem = enabled
revtree.enhancer.simpleenhancermodule = enabled
revtree.optimizer.defaultrevtreeoptimizer = enabled
revtree.web_ui.revtreemodule = enabled
tracmenus.web_ui.menumanagermodule = disabled
tracopt.ticket.commit_updater.committicketreferencemacro = enabled
tracopt.ticket.commit_updater.committicketupdater = enabled
tracopt.versioncontrol.svn.* = enabled
tractoc.* = enabled

[extended_version]
milestone_stats_provider = DefaultTicketGroupStatsProvider
navigation_item = roadmap
roadmap_navigation = enabled
show_milestone_description = disabled
show_milestones_in_overview = enabled
show_tickets_in_overview = enabled
version_stats_provider = DefaultTicketGroupStatsProvider

[gitweb-repositories]
projects_base = 
projects_list = 
projects_url =

[header_logo]
alt = 
height = 87
link = 
src = 
width = -380

[inherit]
htdocs_dir = 
plugins_dir = 
templates_dir =

[logging]
log_file = trac.log
log_level = DEBUG
log_type = file

[mainnav] # This is the configuration for the menu plug-in
browser.order = 4
browser.parent = sourcegrp
maingrp = enabled
maingrp.href = /wiki
maingrp.label = Main
maingrp.order = 10
maingrp.parent = top
newticket.order = 6
newticket.parent = ticketgrp
query = enabled
query.href = /query
query.label = Custom Query
query.order = 2
query.parent = ticketgrp
revtree.parent = sourcegrp
roadmap.order = 3
search = disabled
search.order = 7
sourcegrp = enabled
sourcegrp.href = /browser
sourcegrp.label = Source Code
sourcegrp.order = 40
sourcegrp.parent = top
ticketgrp = enabled
ticketgrp.href = /report/1
ticketgrp.label = Tickets
ticketgrp.order = 30
ticketgrp.parent = top
tickets.label = View Reports
tickets.order = 5
tickets.parent = ticketgrp
timeline.order = 2
timeline.parent = maingrp
versions.order = 20
wiki.order = 1
wiki.parent = maingrp

[metanav]
about.order = 5
help.order = 4
login.order = 1
logout.order = 2
prefs.order = 3

[milestone]
stats_provider = DefaultTicketGroupStatsProvider

[mimeviewer]
max_preview_size = 262144
mime_map = text/x-dylan:dylan,text/x-idl:ice,text/x-ada:ads:adb
mime_map_patterns = text/plain:README|INSTALL|COPYING.*
tab_width = 8
treat_as_binary = application/octet-stream,application/pdf,application/postscript,application/msword,application/rtf

[notification]
admit_domains = 
ambiguous_char_width = single
batch_subject_template = $prefix Batch modify: $tickets_descr
email_sender = SmtpEmailSender
ignore_domains = 
mime_encoding = none
sendmail_path = sendmail
smtp_always_bcc = 
smtp_always_cc = 
smtp_default_domain = 
smtp_enabled = disabled
smtp_from = trac@localhost
smtp_from_author = disabled
smtp_from_name = 
smtp_password = 
smtp_port = 25
smtp_replyto = trac@localhost
smtp_server = localhost
smtp_subject_prefix = __default__
smtp_user = 
ticket_subject_template = $prefix #$ticket.id: $summary
use_public_cc = disabled
use_short_addr = disabled
use_tls = disabled

[notification-subscriber]
always_notify_cc = CarbonCopySubscriber
always_notify_previous_updater = TicketPreviousUpdatersSubscriber
always_notify_updater = TicketUpdaterSubscriber

[project]
admin = 
admin_trac_url = .
descr = Modeler
footer = Visit the Trac open source project at<br /><a href="http://trac.edgewall.org/">http://trac.edgewall.org/</a>
icon = common/trac.ico
name = Modeler
url =

[query]
default_anonymous_query = status!=closed&cc~=$USER
default_query = status!=closed&owner=$USER
items_per_page = 100
ticketlink_query = ?status=!closed

[report]
items_per_page = 100
items_per_page_rss = 0

[repositories]
.dir = /Users/myusername/.SVN/Modeler # The path to the SVN repository

[revisionlog]
default_log_limit = 100
graph_colors = ['#cc0','#0c0','#0cc','#00c','#c0c','#c00']

[revtree]
abstime = enabled
branch_re = ^(?P<branch>branches/[^/]+|trunk|tags)(?:/(?P<path>.*))?$
contexts = 
revbase = 1
scale = 1.0
style = compact
trunks = trunk

[roadmap]
stats_provider = DefaultTicketGroupStatsProvider

[search]
min_query_length = 3

[svn]
authz_file = 
authz_module_name =

[ticket]
default_cc = 
default_component = application
default_description = 
default_keywords = 
default_milestone = 
default_owner = < default >
default_priority = to be discussed
default_resolution = fixed
default_severity = 
default_summary = 
default_type = task
default_version = 
max_comment_size = 262144
max_description_size = 262144
preserve_newlines = default
restrict_owner = disabled
workflow = ConfigurableTicketWorkflow

[ticket-workflow]
accept = new,assigned,accepted,reopened -> accepted
accept.operations = set_owner_to_self
accept.permissions = TICKET_MODIFY
create = <none> -> new
create.default = 1
create_and_assign = <none> -> assigned
create_and_assign.label = assign
create_and_assign.operations = may_set_owner
create_and_assign.permissions = TICKET_MODIFY
leave = * -> *
leave.default = 1
leave.operations = leave_status
reassign = new,assigned,accepted,reopened -> assigned
reassign.operations = set_owner
reassign.permissions = TICKET_MODIFY
reopen = closed -> reopened
reopen.operations = del_resolution
reopen.permissions = TICKET_CREATE
resolve = new,assigned,accepted,reopened -> closed
resolve.operations = set_resolution
resolve.permissions = TICKET_MODIFY

[timeline]
abbreviated_messages = enabled
changeset_collapse_events = disabled
changeset_long_messages = disabled
changeset_show_files = 0
default_daysback = 30
max_daysback = 90
newticket_formatter = oneliner
ticket_show_details = disabled

[trac]
auth_cookie_lifetime = 0
auth_cookie_path = 
auto_preview_timeout = 2.0
auto_reload = disabled
backup_dir = db
base_url = http://127.0.0.1:8000
check_auth_ip = disabled
database = sqlite:db/trac.db
debug_sql = disabled
default_charset = utf-8
default_dateinfo_format = relative
genshi_cache_size = 128
htdocs_location = 
ignore_auth_case = disabled
jquery_location = 
jquery_ui_location = 
jquery_ui_theme_location = 
mysqldump_path = mysqldump
never_obfuscate_mailto = disabled
permission_policies = ReadonlyWikiPolicy,DefaultPermissionPolicy,LegacyAttachmentPolicy
permission_store = DefaultPermissionStore
pg_dump_path = pg_dump
resizable_textareas = enabled
secure_cookies = disabled
show_email_addresses = disabled
show_ip_addresses = disabled
timeout = 20
use_base_url_for_redirect = disabled

[versioncontrol]
allowed_repository_dir_prefixes = 
default_repository_type = svn

[wiki]
ignore_missing_pages = disabled
max_size = 262144
render_unsafe_content = disabled
safe_schemes = cvs,file,ftp,git,irc,http,https,news,sftp,smb,ssh,svn,svn+ssh
split_page_names = disabled

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*