OSDN Git Service

add contrib dir
[tortoisegit/TortoiseGitJp.git] / contrib / issue-tracker-plugins / issue-tracker-plugins.txt
1 Issue Tracker Plugins\r
2 =====================\r
3 \r
4 What is this for?\r
5 -----------------\r
6 \r
7 Imagine the following scenario:\r
8 \r
9  1. Marvin the manager assigns a ticket or task to Dave, the developer, using\r
10     the issue-tracking or task-management software.\r
11  2. Dave looks at his list of tasks using the issue-tracking software's front\r
12     end (i.e. a web-dashboard). He picks something to work on this morning.\r
13  3. Dave fires up Visual Studio; hacks on some code; does some work toward\r
14     the task.\r
15  4. Dave brings up TSVN's commit dialog. He types in a comment that lists,\r
16     depending on coding standards:\r
17      a) The ticket/task number of what he's been working on.\r
18      b) Some comments about what he's changed.\r
19  5. He clicks OK, and his changes are committed to the repository.\r
20  6. The issue-tracking software monitors the SVN repository, watching for\r
21     commits.It sees Dave's commit message, extracts the information from it,\r
22     and updates the ticket appropriately.\r
23  7. Marvin looks in the task-management software, and can monitor the\r
24     project's progress.\r
25 \r
26 As it stands, TSVN supports (most of) this admirably. For example, with the\r
27 Trac integration, I can put "See #43" or "Fixes #99" somewhere in the commit\r
28 message, and Trac's post-commit hook will update the tickets accordingly.\r
29 \r
30 However:\r
31  1. Dave has to keep the issue-tracker front-end open in order to look up the\r
32     ticket numbers.\r
33  2. Some issue trackers want more information (e.g. time spent, time\r
34     remaining), and it needs to be formatted more rigidly.\r
35 \r
36 So, the user story looks like this:\r
37 \r
38  "From the TSVN commit dialog, the user should be able to display up a list of\r
39   assigned tickets from the issue-tracker associated with that repository. The\r
40   user should be able to pick one or more tasks from this list."\r
41   \r
42  "This will populate the commit message with the information required by the\r
43   issue-tracker's SVN server-side post-commit hook."\r
44 \r
45  "This functionality should be available from the commit dialog, because the\r
46   user may wish to choose which files to commit based on which ticket they\r
47   select, or he may wish to refresh his memory about what's changed before\r
48   selecting the appropriate ticket."\r
49 \r
50 \r
51 Implementing an issue tracker plugin\r
52 ------------------------------------\r
53 \r
54 To write an integration plugin, you implement the IBugTraqProvider COM\r
55 interface, and register your object as implementing the "TortoiseSVN BugTraq\r
56 Providers" component category. This registration makes it easy for the\r
57 settings dialog to find a list of available plugins.\r
58 \r
59 The IBugTraqProvider interface is documented in the inc\IBugTraqProvider.idl\r
60 file.\r
61 \r
62 The component category is defined (in C++) as follows:\r
63 \r
64 // {3494FA92-B139-4730-9591-01135D5E7831}\r
65 DEFINE_GUID(CATID_BugTraqProvider, \r
66                         0x3494fa92, 0xb139, 0x4730, 0x95, 0x91, 0x1, 0x13, 0x5d, 0x5e, 0x78, 0x31);\r
67 \r
68 \r
69 Example Plugins\r
70 ---------------\r
71 \r
72 There are two example plugins in this folder.\r
73 \r
74  - ExampleAtlPlugin, written in C++, using ATL.\r
75  - ExampleCsPlugin, written in C#.\r
76  \r
77 They get the list of available "issues" from a hard-coded list, rather than a\r
78 database or web service, but this should be sufficient to demonstrate the\r
79 plugin API.\r
80 \r
81 \r
82 Licensing and GPL compatibility\r
83 -------------------------------\r
84 \r
85 TortoiseSVN is licensed under the GNU General Public License (see the file\r
86 LICENSE for details).\r
87 \r
88 There is a specific exception for plugins that implement the issue tracker\r
89 plugin interfaces; these do not need to be GPL-licensed.\r
90 \r
91 \r
92 The IBugTraqProvider interface\r
93 ------------------------------\r
94 \r
95 In the contrib\issue-tracker-plugins\inc directory, you'll find the following\r
96 files:\r
97 \r
98  * IBugTraqProvider.idl\r
99    This is a copy of the src\IBugTraqProvider\IBugTraqProvider.idl file; it's\r
100    provided for reference; you'll probably use the files below.\r
101    \r
102  * IBugTraqProvider_h.h, IBugTraqProvider_i.c\r
103    These are the files you'll probably use if you implement a plugin in C++.\r
104 \r
105  * Interop.BugTraqProvider.dll\r
106    Interop Assembly for implementing plugins in .NET. It's not a Primary\r
107    Interop Assembly (PIA).\r
108    The source code for this project is in the Interop.BugTraqProvider folder.\r
109 \r
110 The interface is documented in the .IDL file.\r
111 \r
112 \r
113 Walkthrough: Creating an issue tracker plugin in C#\r
114 ---------------------------------------------------\r
115 \r
116 (This assumes a basic familiarity with creating Windows Forms applications).\r
117 \r
118 In Visual Studio 2005 or 2008, create a new "Class Library" project; give it a\r
119 name.\r
120 \r
121 Delete the "Class1" class; we'll create another one in a moment.\r
122 \r
123 Add a reference to the inc\Interop.BugTraqProvider.dll file.\r
124 \r
125 Create a new class named "MyPlugin".\r
126 \r
127 Derive MyPlugin from the Interop.BugTraqProvider.IBugTraqProvider interface,\r
128 and then implement the first two methods as follows:\r
129 \r
130 The ValidateParameters method should look like this:\r
131 \r
132     public bool ValidateParameters(IntPtr hParentWnd, string parameters)\r
133     {\r
134         return true;\r
135     }\r
136 \r
137 The GetLinkText method should look like this:\r
138 \r
139     public string GetLinkText(IntPtr hParentWnd, string parameters)\r
140     {\r
141         return "Choose Issue";\r
142     }\r
143 \r
144 We'll come back to GetCommitMessage shortly.\r
145 \r
146 The class also needs some attributes; it should look like this:\r
147 \r
148     [ComVisible(true),\r
149      Guid("PUT-GUID-HERE"),\r
150      ClassInterface(ClassInterfaceType.None)]\r
151     public class Provider : IBugTraqProvider\r
152     {\r
153                 // etc.\r
154 \r
155 (Replace "PUT-GUID-HERE" with a new GUID).\r
156 \r
157 Add a class to hold our example ticket data:\r
158 \r
159         internal class TicketItem\r
160         {\r
161                 private readonly int _ticketNumber;\r
162                 private readonly string _ticketSummary;\r
163 \r
164                 public TicketItem(int ticketNumber, string ticketSummary)\r
165                 {\r
166                         _ticketNumber = ticketNumber;\r
167                         _ticketSummary = ticketSummary;\r
168                 }\r
169 \r
170                 public int Number\r
171                 {\r
172                         get { return _ticketNumber; }\r
173                 }\r
174 \r
175                 public string Summary\r
176                 {\r
177                         get { return _ticketSummary; }\r
178                 }\r
179         }\r
180 \r
181 We can now implement the GetCommitMessage method as follows:\r
182 \r
183     public string GetCommitMessage(IntPtr hParentWnd, string parameters, string commonRoot, string[] pathList, string originalMessage)\r
184     {\r
185         List<TicketItem> tickets = new List<TicketItem>();\r
186         tickets.Add(new TicketItem(12, "Service doesn't start on Windows Vista"));\r
187         tickets.Add(new TicketItem(19, "About box doesn't render correctly in large fonts mode"));\r
188 \r
189         MyIssuesForm form = new MyIssuesForm(tickets);\r
190         if (form.ShowDialog() != DialogResult.OK)\r
191             return originalMessage;\r
192 \r
193         StringBuilder result = new StringBuilder(originalMessage);\r
194         if (originalMessage.Length != 0 && !originalMessage.EndsWith("\n"))\r
195             result.AppendLine();\r
196 \r
197         foreach (TicketItem ticket in form.TicketsFixed)\r
198         {\r
199             result.AppendFormat("Fixed #{0}: {1}", ticket.Number, ticket.Summary);\r
200             result.AppendLine();\r
201         }\r
202 \r
203         return result.ToString();\r
204     }\r
205 \r
206 This passes the list of open issues to the MyIssuesForm object, where the\r
207 user will be able to check those ones that she's fixed. These are available\r
208 through the TicketsFixed property.\r
209 \r
210 We use these to build a string that looks something like this:\r
211 \r
212 Fixed #12: Service doesn't start on Windows Vista.\r
213 \r
214 A commit message formatted like this will cause, (e.g.) Trac's post-commit\r
215 hook to close the tickets.\r
216 \r
217 Anything that the user has already entered into the commit message is left\r
218 there.\r
219 \r
220 Now we need a dialog box that displays the issues assigned to the\r
221 current user.\r
222 \r
223 Add a Windows Form item to your project. Name it "MyIssuesForm". Set the\r
224 following properties:\r
225 \r
226  StartPosition = CenterParent\r
227  MaximizeBox = False\r
228  MinimizeBox = False\r
229  ShowIcon = False\r
230  ShowInTaskbar = False\r
231 \r
232 Put the usual OK and Cancel buttons on it; arrange them and wire them up\r
233 properly.\r
234 \r
235 Add a ListView control to the form and arrange it appropriately. Set the\r
236 following properties:\r
237 \r
238  Checkboxes = True\r
239  FullRowSelect = True\r
240  View = Details\r
241  HeaderStyle = Nonclickable\r
242 \r
243 Change the class so that it looks like this:\r
244 \r
245         partial class MyIssuesForm : Form\r
246         {\r
247                 private readonly IEnumerable<TicketItem> _tickets;\r
248                 private readonly List<TicketItem> _ticketsAffected = new List<TicketItem>();\r
249 \r
250                 public MyIssuesForm(IEnumerable<TicketItem> tickets)\r
251                 {\r
252                         InitializeComponent();\r
253                         _tickets = tickets;\r
254                 }\r
255 \r
256                 public IEnumerable<TicketItem> TicketsFixed\r
257                 {\r
258                         get { return _ticketsAffected; }\r
259                 }\r
260 \r
261                 // etc.\r
262 \r
263 Then implement some event handlers in MyIssuesForm as follows:\r
264 \r
265         private void MyIssuesForm_Load(object sender, EventArgs e)\r
266         {\r
267             listView1.Columns.Add("");\r
268             listView1.Columns.Add("#");\r
269             listView1.Columns.Add("Summary");\r
270 \r
271             foreach(TicketItem ticketItem in _tickets)\r
272             {\r
273                 ListViewItem lvi = new ListViewItem();\r
274                 lvi.Text = "";\r
275                 lvi.SubItems.Add(ticketItem.Number.ToString());\r
276                 lvi.SubItems.Add(ticketItem.Summary);\r
277                 lvi.Tag = ticketItem;\r
278 \r
279                 listView1.Items.Add(lvi);\r
280             }\r
281 \r
282             listView1.Columns[0].Width = -1;\r
283             listView1.Columns[1].Width = -1;\r
284             listView1.Columns[2].Width = -1;\r
285         }\r
286 \r
287         private void okButton_Click(object sender, EventArgs e)\r
288         {\r
289             foreach (ListViewItem lvi in listView1.Items)\r
290             {\r
291                 TicketItem ticketItem = lvi.Tag as TicketItem;\r
292                 if (ticketItem != null && lvi.Checked)\r
293                     _ticketsAffected.Add(ticketItem);\r
294             }\r
295         }\r
296 \r
297 Registering your new C# class can be done by using RegAsm from the command\r
298 line, as follows:\r
299 \r
300         RegAsm bin\Debug\MyCsPlugin.dll /codebase /regfile:MyCsPlugin.reg\r
301 \r
302 You'll need to edit the .REG file, by adding another "Implemented Categories"\r
303 entry that looks like this:\r
304 \r
305 [HKEY_CLASSES_ROOT\CLSID\{PUT-GUID-HERE}\Implemented Categories\{3494FA92-B139-4730-9591-01135D5E7831}]\r
306 \r
307 Replace "PUT-GUID-HERE" with the same value you used earlier.\r
308 \r
309 Then, merge that .REG file into the registry, and your plugin is ready to go!\r