|
2 | 2 | Customising Roundup |
3 | 3 | =================== |
4 | 4 |
|
5 | | -:Version: $Revision: 1.78 $ |
| 5 | +:Version: $Revision: 1.79 $ |
6 | 6 |
|
7 | 7 | .. This document borrows from the ZopeBook section on ZPT. The original is at: |
8 | 8 | http://www.zope.org/Documentation/Books/ZopeBook/current/ZPT.stx |
@@ -2895,6 +2895,136 @@ achieve this:: |
2895 | 2895 | </table> |
2896 | 2896 |
|
2897 | 2897 |
|
| 2898 | +Blocking issues that depend on other issues |
| 2899 | +------------------------------------------- |
| 2900 | + |
| 2901 | +We needed the ability to mark certain issues as "blockers" - that is, |
| 2902 | +they can't be resolved until another issue (the blocker) they rely on |
| 2903 | +is resolved. To achieve this: |
| 2904 | + |
| 2905 | +1. Create a new property on the issue Class, ``blockers=Multilink("issue")``. |
| 2906 | + Edit your tracker's dbinit.py file. Where the "issue" class is defined, |
| 2907 | + something like:: |
| 2908 | + |
| 2909 | + issue = IssueClass(db, "issue", |
| 2910 | + assignedto=Link("user"), topic=Multilink("keyword"), |
| 2911 | + priority=Link("priority"), status=Link("status")) |
| 2912 | + |
| 2913 | + add the blockers entry like so:: |
| 2914 | + |
| 2915 | + issue = IssueClass(db, "issue", |
| 2916 | + blockers=Multilink("issue"), |
| 2917 | + assignedto=Link("user"), topic=Multilink("keyword"), |
| 2918 | + priority=Link("priority"), status=Link("status")) |
| 2919 | + |
| 2920 | +2. Add the new "blockers" property to the issue.item edit page, using |
| 2921 | + something like: |
| 2922 | + |
| 2923 | + <th nowrap>Waiting On</th> |
| 2924 | + <td> |
| 2925 | + <span tal:replace="structure python:context.blockers.field(showid=1, |
| 2926 | + size=20)" /> |
| 2927 | + <span tal:replace="structure python:db.issue.classhelp('id,title')" /> |
| 2928 | + <span tal:condition="context/blockers" tal:repeat="blk context/blockers"> |
| 2929 | + <br>View: <a tal:attributes="href string:issue${blk/id}" |
| 2930 | + tal:content="blk/id"></a> |
| 2931 | + </span> |
| 2932 | + |
| 2933 | + You'll need to fiddle with your item page layout to find an appropriate |
| 2934 | + place to put it - I'll leave that fun part up to you. Just make sure it |
| 2935 | + appears in the first table, possibly somewhere near the "superseders" |
| 2936 | + field. |
| 2937 | + |
| 2938 | +3. Create a new detector module (attached) which enforces the rules: |
| 2939 | + |
| 2940 | + - issues may not be resolved if they have blockers |
| 2941 | + - when a blocker is resolved, it's removed from issues it blocks |
| 2942 | + |
| 2943 | + The contents of the detector should be something like this:: |
| 2944 | + |
| 2945 | + def blockresolution(db, cl, nodeid, newvalues): |
| 2946 | + ''' If the issue has blockers, don't allow it to be resolved. |
| 2947 | + ''' |
| 2948 | + if nodeid is None: |
| 2949 | + blockers = [] |
| 2950 | + else: |
| 2951 | + blockers = cl.get(nodeid, 'blockers') |
| 2952 | + blockers = newvalues.get('blockers', blockers) |
| 2953 | + |
| 2954 | + # don't do anything if there's no blockers or the status hasn't changed |
| 2955 | + if not blockers or not newvalues.has_key('status'): |
| 2956 | + return |
| 2957 | + |
| 2958 | + # get the resolved state ID |
| 2959 | + resolved_id = db.status.lookup('resolved') |
| 2960 | + |
| 2961 | + # format the info |
| 2962 | + u = db.config.TRACKER_WEB |
| 2963 | + s = ', '.join(['<a href="%sissue%s">%s</a>'%(u,id,id) for id in blockers]) |
| 2964 | + if len(blockers) == 1: |
| 2965 | + s = 'issue %s is'%s |
| 2966 | + else: |
| 2967 | + s = 'issues %s are'%s |
| 2968 | + |
| 2969 | + # ok, see if we're trying to resolve |
| 2970 | + if newvalues['status'] == resolved_id: |
| 2971 | + raise ValueError, "This issue can't be resolved until %s resolved."%s |
| 2972 | + |
| 2973 | + def resolveblockers(db, cl, nodeid, newvalues): |
| 2974 | + ''' When we resolve an issue that's a blocker, remove it from the |
| 2975 | + blockers list of the issue(s) it blocks. |
| 2976 | + ''' |
| 2977 | + if not newvalues.has_key('status'): |
| 2978 | + return |
| 2979 | + |
| 2980 | + # get the resolved state ID |
| 2981 | + resolved_id = db.status.lookup('resolved') |
| 2982 | + |
| 2983 | + # interesting? |
| 2984 | + if newvalues['status'] != resolved_id: |
| 2985 | + return |
| 2986 | + |
| 2987 | + # yes - find all the blocked issues, if any, and remove me from their |
| 2988 | + # blockers list |
| 2989 | + issues = cl.find(blockers=nodeid) |
| 2990 | + for issueid in issues: |
| 2991 | + blockers = cl.get(issueid, 'blockers') |
| 2992 | + if nodeid in blockers: |
| 2993 | + blockers.remove(nodeid) |
| 2994 | + cl.set(issueid, blockers=blockers) |
| 2995 | + |
| 2996 | + |
| 2997 | + def init(db): |
| 2998 | + # might, in an obscure situation, happen in a create |
| 2999 | + db.issue.audit('create', blockresolution) |
| 3000 | + db.issue.audit('set', blockresolution) |
| 3001 | + |
| 3002 | + # can only happen on a set |
| 3003 | + db.issue.react('set', resolveblockers) |
| 3004 | + |
| 3005 | + Put the above code in a file called "blockers.py" in your tracker's |
| 3006 | + "detectors" directory. |
| 3007 | + |
| 3008 | +4. Finally, and this is an optional step, modify the tracker web page URLs |
| 3009 | + so they filter out issues with any blockers. You do this by adding an |
| 3010 | + additional filter on "blockers" for the value "-1". For example, the |
| 3011 | + existing "Show All" link in the "page" template (in the tracker's |
| 3012 | + "html" directory) looks like this:: |
| 3013 | + |
| 3014 | + <a href="issue?:sort=-activity&:group=priority&:filter=status&:columns=id,activity,title,creator,assignedto,status&status=-1,1,2,3,4,5,6,7">Show All</a><br> |
| 3015 | + |
| 3016 | + modify it to add the "blockers" info to the URL (note, both the |
| 3017 | + ":filter" *and* "blockers" values must be specified):: |
| 3018 | + |
| 3019 | + <a href="issue?:sort=-activity&:group=priority&:filter=status,blockers@blockers=-1&:columns=id,activity,title,creator,assignedto,status&status=-1,1,2,3,4,5,6,7">Show All</a><br> |
| 3020 | + |
| 3021 | +That's it. You should now be able to se blockers on your issues. Note that |
| 3022 | +if you want to know whether an issue has any other issues dependent on it |
| 3023 | +(ie. it's in their blockers list) you can look at the journal history |
| 3024 | +at the bottom of the issue page - look for a "link" event to another |
| 3025 | +issue's "blockers" property. |
| 3026 | + |
| 3027 | + |
2898 | 3028 | ------------------- |
2899 | 3029 |
|
2900 | 3030 | Back to `Table of Contents`_ |
|
0 commit comments