Worklogger

Automatic timesheet entry

As you may know, part of the daily responsibilities of the software-workers is to log their time. (And many other professions too, I’m sure.) This implies reporting time with a certain level of detail so that our managers (sometimes, ourselves) can properly bill each customer for the work done.

The problem with this is that it is a pretty repetitive task, and not only that, each customer will have requirements of their own, like using their own system for time tracking, to separate the work in tickets, to receive a summary by email, etc.

I created Worklogger to be a swiss-army-knife solution to these variables.

Some background

I’ve always been a fan of automating these menial tasks – I don’t want them to distract me from my daily activities. And furthermore, at some point, I was logging the same work four times because our different customers wanted different systems. It became a task that would take, in average, about 2 hours a week. A lot can be done in 2 hours, but there I was, filling in timesheets.

I decided to create Worklogger in a configurable fashion, so that not only it was useful to me, but to others who might be in a similar situation. You can check a draft of the configuration in here.

How it works

If you know Zappier or IFTTT, you probably already have an idea. It’s an input-transformation-output approach, with a few extra additions. Here is a very high-level pseudocode of what the application does:

// reads worklogs from configured inputs
var worklogs = readWorklogsFrom(configuredInputs);

// applies transformations if the condition for them is met
foreach (var transformation in configuredTransformations) {
    foreach (var worklog in worklogs) {
        if (transformation.configuredCondition.isSatisfiedBy(worklog) {
            transformation.applyTo(worklog);
        }
    }
}

// sends the worklogs to their outputs if the condition for them is met
foreach (var output in configuredOutputs) {
    foreach (var worklog in worklogs) {
        if (output.configuredCondition.isSatisfiedBy(worklog) {
            output.send(worklog);
        }
    }
}

If you could read this, you’ve already been introduced to several concepts that the system uses. Still, an explanation is useful:

Inputs

Inputs are where the worklogs originate from. After all, you need to start somewhere, right? It might be a JIRA worklog, a timetracker output file, or a manual input. I currently use Google Calendar as my timetracker, and that is supported too.

Currently supported:

  • Google Calendar: reads entries from a Google account, supporting several calendars at a time

Conditions

Conditions are just filters, because sometimes you don’t want everything to go to the same place. This makes sense: you may be working for different customers and the billing information for one has nothing to do with the second customer. Conditions will allow you to apply transformations or send worklogs to outputs only if they match the condition.

Currently supported:

  • true: Mostly used internally, but this condition will evaluate to true for all worklogs. It means it won’t be filtering anything.
  • hasTag: Used to filter worklogs that have a particular tag, or for which the tag has a certain value.

Transformations

Transformations will mostly modify worklogs, which will allow you to properly filter them in the outputs. Think of transformations as any massaging you need to do to the data before it goes out.

Currently supported:

  • addTags: will add tags to the worklogs, with a fixed value or extracting some text from the worklog text

Outputs

Outputs will send your resulting worklogs to wherever you need them. Of course, they can be filtered too. Outputs may be tied to several formatters too – formatters will prepare the worklogs in a way that the output can use it. For instance, you may think of email as an output, but different formats for the email (like summary or detail) being generated by different formatters.

Currently supported:

  • TextFile: sends details for the worklogs to a text file.
    • SummaryTextFileFormatter: generates a summary of the worklogs, and can group them by several levels and generate totals
  • HarvestApp: sends worklogs as time entries in HarvestApp.com
  • JiraWorklog: sends worklogs as … well, worklogs (they use the same name too) in JIRA. Notice this is slightly different as what the JIRA Tempo plugin uses.
  • Logger: will output the contents to the logger, in whatever way it is configured (useful for debugging and an output of the execution)

How I use it

I’ve got two customers. One of them wants the information in HarvestApp and the other one wants, in addition, worklogs sent to their own JIRA instance. At the same time, I want an output of what was sent (to ensure everything works fine) and I want to get a summary for my whole month, so I can bill these customers.

As such, I have two configuration files: one that is used daily to send the worklogs to their destination, and one that runs monthly to get the summary to me. I execute them with a cron job like so:

This will:

  • Log hours each day at noon, so that I have enough time from the day before and during this day to adjust the calendar in the right way
    • Send Client1 hours to their JIRA instance, using the JiraTicket tag, that I extract from the description. So a calendar entry “[ABC-123] Working” with half an hour duration becomes a half an hour worklog in ticket ABC-123. I filter this output to only those entries that have the client tag set to Client1.
    • Send Client2 + Client1 entries to Harvest, so no filter there. I use the HarvestProject and HarvestTask tags to set the right project and task assigned to me.
    • I also use the logger output because the results of the execution are sent to me by email, so I can properly double check what was generated.
  • Log hours every month’s first day at 8 AM.
    • It also uses the Logger output so I can see the results in my email.
    • It uses a TextFile output (should be email really, but I haven’t coded that yet) that will summarize the results and aggregate totals by client, project and JIRA ticket.

Future of Worklogger

Since I’ve got the basics of what I personally needed, I do not plan on working heavily on it anymore. However, pressure from the community or might change that (I love to help). Also, I designed it in a way so that it can be adapted to new scenarios, so I plan on continuing usage for it and modifying it as I need it.

Most of my ideas that didn’t make it into my very-basic version are in the issues listing for the project. Of course, contributions are heartwarmingly welcome. I did mark which issues could be easier for newcomers (good-first-issue and help-wanted tags), and I have also marked which items should be more important for an official 1.0 release (v1.0 milestone).

Feel free to look around and leave questions, ideas, suggestions or complaints.