Thursday, June 14, 2012

"He's NOT the Messiah!"

This isn't strictly an Evergreen post, though I did the work in the context of my role as the Chief Bug Wrangler for Evergreen/Open-ILS.

Release days are always busy for me, since one of my tasks is to go through the various milestones leading up to the release and changing all of the "Fix Committed" bug to "Fix Released." In addition, I have to create a new milestone for the next bug fix release and move any remaining bugs to that new milestone. Of these two tasks, the first is generally the most time consuming.

I have been looking for a way to automate some of this, and last night, I finally hit pay dirt.

I had installed the python-launchpadlib from Canonical on my Ubuntu laptop and decided last night to use that to automate the bug closing. I found this lovely conrtib script that looked like it would do the job, but after about 45 minutes of fooling around with it, I couldn't get it to work. (For those who care, the lp_project.getMilestone() call at line 66 kept returning an empty value.)

So, then I decided to try python-launchpadlib-toolkit, which comes with the lovely close-fix-committed-bugs script. I browsed its source code and decided that I really wanted something slightly different, so after a few minutes of tinkering, I came up with this:

# Copyright 2010 Bryce Harrington <>
# Copyright 2012 Jason Stephenson <>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see .

import sys
import lpltk

if len(sys.argv) < 3:
  print 'Usage: %s <project-name> <milestone>...' % sys.argv[0]

project_name = sys.argv[1]

  lp          = lpltk.LaunchpadService()
  project     = lp.load_project(project_name)
  sys.stderr.write("Could not connect to launchpad\n")

for series in project.series:
  for milestone in series.all_milestones:
    for mstone_name in sys.argv[2:]:
      if == mstone_name:
        for bugtask in milestone.searchTasks(status = "Fix Committed"):
          print "%7s  %s-->Fix Released  %-40s" %(,
          bugtask.status = "Fix Released"


I call it, and it works like a charm for closing bugs. To use it, you simply run it from the command line with the Launchpad Project, Evergreen in our case, as the first argument followed by the milestones whose bugs you want to close:

$ Evergreen 2.2.0 2.2.0beta2 2.2.0beta1 2.2.0rc1

That's all there is to it!

Now the milestones don't have to be a millstone hanging 'round my neck! ("And, there was much rejoicing!")


  1. Great post, Jason!

    An alternate search strategy that might be faster (unverified) is to use project.searchTasks() directly.

    bugtasks = project.searchTasks(
    status = 'Fix Committed',
    milestone = list_of_milestone_names # accepts scalar or array

    * Note, when you search this way you have to specify the fully-qualified milestone name:

    In theory, this fetches less data from the server.

    Keep 'em coming!

    1. I basically tried that.

      I made my script by copying close-fix-committed-bugs and modifying it. The code that looked up milestones with project.searchTasks(status =, milestone=) didn't work for me. You'll notice in close-fix-commited-bugs they're using the entry from series.active_milestones.

      Anyway, I just experimented until I got something that worked for me. I know it could be more efficient, but doing it this way is far more efficient for me than manually editing 130+ bugs!

  2. Hi

    I am the original author of It seems as though it fell behind the times a bit and also got caught out by a Launchpad bug.

    Anyway I fixed it and added a couple of features. There's a pending merge proposal that should land soon: