Redmine Plugin Spec

So I’ve started on the previously discussed Redmine plugin to replace Backlogs, and got a feel for what’s possible in Redmine 2 (I want to deploy this to the current instance and disable Backlogs before we upgrade). So now, I want to lay out a spec for the things I’ve heard people want, and make sure I hit most of the requirements (we can, of course, iterate on the plugin in future :P). To be clear, we want to:

  • unblock the upgrade path for Redmine (by removing Backlogs)
  • standardise on one place for release/version data

EDIT: Now on version 2 of the spec, re-using the Version field


  • A “Found In Release” field
    • This should be has_many multi-select, so that we can mark a bug as being present in multiple releases
  • A “Fixed In Release” field
    • This should be has_many multi-select, so that we can show which versions the fix has been backported to
  • A “Targeted For Release” field
    • Single-valued, show the current target for an open bug
    • Updated to $next-release over the API via the release-notes script
      • Could potentially use the Fixed-In release on Status=open bugs
      • Otherwise reuse the Target Version field from Redmine Core
  • API endpoints for tool-belt and release-notes
    • Seems to mostly involve gathering issues for a given release and then using/updating the data for those issues
  • Storage for old Version Sprint / Backlog bug data?


The Version field is most suitable for this, however over time that’s ended up being used for Sprint/Backlog data. I’d like to reclaim this for it’s intended purpose (versions of Foreman or a Plugin).

  • Add two has_and_belongs_to_many relationships between Issues and Versions
    • One to hold fixed_in relationships
    • One to hold found_in relationships
  • Add two tables to hold the HABTM data
    • The show page needs to display the multiple versions selected
    • The edit form needs multi-select inputs (found-in should filter on status == 'open')
  • The issues API is very hard to extend from a plugin (would probably involve alias_method_chain) so we should probably write a new API and update the external tooling
    • /releases/id/fixedin/issues.json should return the list of matching issues with fixed_in.includes? release
      • This would allow the changelog / release-notes updates to be simplified
    • /releases/id/targetversion/issues.json should return issues.where(:release_id ==
      • Simplifies the mass-update at the start of a new cycle
    • /releases/id/foundin/issues.json - not sure if we need it, but for completeness…
  • Permisisons - it’s easy to accidentally unselect in a multiple_select field (if you don’t Ctrl-click)
    • Should default to append-only
    • Developers / admins can overwrite the entire array of versions on submit


  • Do we need a separate Target Version field?
    • Fixed-in could read “targeted for” if Status == Open
    • Could be hard to mass-update from the tooling when we start a new release
  • The “Target Version” for a project is a single-select field
    • This fits the Target Version usecase above
    • Second option if this doesn’t work through the fixed-in / targetted for field
  • The “Found in Release” custom field is currently used for some data (although it’s not multi-select)
    • Presumably we’d want to write a one-time migration for this to Versions, and remove the custom field?
    • Likewise obsoletes the “found in Katello release” field as Versions can be per-project?
  • The Versions from Foreman are shared with subprojects, so Katello would see them. To avoid this we could:
    • Move Katello to a top-level project (I can’t see a problem with this), or
    • Don’t share versions with children, and re-create the versions per-child (e.g. the installer, the proxy, etc)

Current code:

Update, so reusing the Version field is very nice, and very lightweight, easy to maintain. This is definitely my preferred direction. Here’s some nice screenshots:


This has some consequences. To keep that multiple-select manageable, we’d want to remove all the non-actual-release entries such as sprints and backlogs We’d need to either:

  • Confirm no-one is actively using Versions for this, or
  • Find some other way to store this data

If we need to keep it, then perhaps a few custom fields (one per backlog?) would work? I can look at a simple model/view to store the data in for now, but ideally I’d like to avoid that.

@dLobatog @iNecas @Walden @bbuckingham @Anurag @thomasmckay are any of you actively using the Sprint/Backlog Version entries?

I’m going to update the initial spec to represent current reality now…

In our team, we’re not actively using this at the moment. However, one thing that we would like to get is being albe to mark an issue as triaged. Putting the issue to ‘Team Ivan Backlog’ was how were using this in the past. I think Katello team is using similar approach.

– Ivan

The OpenSCAP project uses a boolean custom field for this:
Show: image
Edit: image

It’s trivial to open this up to everyone, if that would suffice? This could also be non-boolean if we need more fine-grained data.

1 Like

Can we support mentioning users in comments?

I don’t think that fits in the scope of this plugin (which is just to copy the minimum functionality that we need from Backlogs). However, once we get to Redmine 3, this plugin seems like a good option for that :slight_smile:

So, after yesterday’s demo, I found that Redmine can actually already do all of what I showed in my plugin via Custom Fields :man_facepalming:. The approach hasn’t changed though, it’s still a case of “migrate data to custom fields, remove backlogs”. Here’s my current proposal:

  • Custom fields can do multi select, so lets use that
  • Can use Target Version, or hide it and use single-valued Fixed-in to indicate a target release
    • We can play with this, the data is easy to migrate around
  • A small plugin added to enhance the Version show page, and possible add some API extensions we might still need (TBC)

In terms of migrating data, my plan would look like this:

  • Sprint & Backlog data (currently seen here:
    • create custom field “Backlog” as a list-select
    • One value per team, multiselect allowed
    • Migrate issue.fixed_version_id (displayed as Target Version) => the new custom_field
      • Repeat this for each backlog that needs migrating
cf = CustomField.where(name: 'Backlog').first
version = Version.find(name: 'Team Tom - Iteration 16').first #example
issues = Issue.where(fixed_version_id:
issues.each do |i|
  CustomValue.create(customized_type: 'Issue', custom_field_id:, value:, customized_id:

PAUSE HERE - we’ll want to ensure all backlogs are correct via the custom field and team leads are happy with this part of the workflow. Then:

  • Clean up old Versions, create missing releases as needed (e.g. 1.17.1 isn’t there right now)
    • We already have “Found in Release”
      • Rename to “Found in Releases”
      • Make multivalued to match “Fixed in”
      • No migration needed
  • Create “Fixed in Releases” custom field
    • Migrate issue.release_id (Backlogs field) to Fixed In Release
cf = CustomField.where(name: 'Fixed In Release').first
issues.all do |i|
  next if i.release_id.nil?
  CustomValue.create(customized_type: 'Issue', custom_field_id:, value: i.release_id.to_s, customized_id:

This completes the data migration (I think), although we may need to re-set fixed_version_id on closed issues to be the lowest value of the Fixed in Release custom field mutli-select. This can be investigated later as it’s not so critical (only historical).

Then we can update the plugins:

  • Add version_extensions plugin to enhance the version page with fixed/found issues
  • Remove backlogs

The version_extensions plugin just enhances the Version page to show the related custom fields:

However we can iterate on this plugin to add any other Version-related api/ui extras we need.

I’ll leave this here for a week, for comments, and then we’ll see about actually starting this migration some time soon :slight_smile:

Wondering if we can close all Team* versions in RM now:

Assuming they are not used anymore.

Given we’re close to agreeing the complete switch over, we may as well do the whole thing in one pass - I don’t want to make changes to someone else’s workflow before I’ve got that agreement. But I’m not opposed to people closing their own stuff earlier if they wish too :wink:

1 Like