[jbpm-commits] JBoss JBPM SVN: r4403 - in jbpm4/trunk/modules: examples/src/test/java/org/jbpm/examples/task/swimlane and 3 other directories.

do-not-reply at jboss.org do-not-reply at jboss.org
Fri Apr 3 06:45:05 EDT 2009


Author: tom.baeyens at jboss.com
Date: 2009-04-03 06:45:02 -0400 (Fri, 03 Apr 2009)
New Revision: 4403

Modified:
   jbpm4/trunk/modules/examples/src/test/java/org/jbpm/examples/task/candidates/TaskCandidatesTest.java
   jbpm4/trunk/modules/examples/src/test/java/org/jbpm/examples/task/swimlane/TaskSwimlaneTest.java
   jbpm4/trunk/modules/examples/src/test/resources/org/jbpm/examples/task/candidates/process.jpdl.xml
   jbpm4/trunk/modules/examples/src/test/resources/org/jbpm/examples/task/swimlane/process.jpdl.xml
   jbpm4/trunk/modules/userguide/src/main/docbook/en/modules/ch05-Jpdl.xml
Log:
documenting the task assignment examples

Modified: jbpm4/trunk/modules/examples/src/test/java/org/jbpm/examples/task/candidates/TaskCandidatesTest.java
===================================================================
--- jbpm4/trunk/modules/examples/src/test/java/org/jbpm/examples/task/candidates/TaskCandidatesTest.java	2009-04-03 03:32:16 UTC (rev 4402)
+++ jbpm4/trunk/modules/examples/src/test/java/org/jbpm/examples/task/candidates/TaskCandidatesTest.java	2009-04-03 10:45:02 UTC (rev 4403)
@@ -39,16 +39,16 @@
 
     deploy("jbpm-TaskCandidatesTest.jpdl");
 
-    if(identityService.findGroupById("sales-test-group")==null)
+    if(identityService.findGroupById("sales-dept")==null)
     {
       // create johndoe and joesmoe as members of the sales group
-      identityService.createGroup("sales-test-group");
+      identityService.createGroup("sales-dept");
 
       identityService.createUser("johndoe", "johndoe", "John", "Doe");
-      identityService.createMembership("johndoe", "sales-test-group");
+      identityService.createMembership("johndoe", "sales-dept");
 
       identityService.createUser("joesmoe", "joesmoe", "Joe", "Smoe");
-      identityService.createMembership("joesmoe", "sales-test-group");
+      identityService.createMembership("joesmoe", "sales-dept");
     }
   }
 

Modified: jbpm4/trunk/modules/examples/src/test/java/org/jbpm/examples/task/swimlane/TaskSwimlaneTest.java
===================================================================
--- jbpm4/trunk/modules/examples/src/test/java/org/jbpm/examples/task/swimlane/TaskSwimlaneTest.java	2009-04-03 03:32:16 UTC (rev 4402)
+++ jbpm4/trunk/modules/examples/src/test/java/org/jbpm/examples/task/swimlane/TaskSwimlaneTest.java	2009-04-03 10:45:02 UTC (rev 4403)
@@ -37,13 +37,13 @@
     super.setUp();
     deploy("jbpm-TaskSwimlaneTest.jpdl");
 
-    if(identityService.findGroupById("sales-test-group")==null)
+    if(identityService.findGroupById("sales-dept")==null)
     {
       // create johndoe and joesmoe as members of the sales group
-      identityService.createGroup("sales-test-group");
+      identityService.createGroup("sales-dept");
 
       identityService.createUser("johndoe", "johndoe", "John", "Doe");
-      identityService.createMembership("johndoe", "sales-test-group");
+      identityService.createMembership("johndoe", "sales-dept");
     }
   }
 

Modified: jbpm4/trunk/modules/examples/src/test/resources/org/jbpm/examples/task/candidates/process.jpdl.xml
===================================================================
--- jbpm4/trunk/modules/examples/src/test/resources/org/jbpm/examples/task/candidates/process.jpdl.xml	2009-04-03 03:32:16 UTC (rev 4402)
+++ jbpm4/trunk/modules/examples/src/test/resources/org/jbpm/examples/task/candidates/process.jpdl.xml	2009-04-03 10:45:02 UTC (rev 4403)
@@ -7,7 +7,7 @@
   </start>
 
   <task name="review" 
-        candidate-groups="sales-test-group"
+        candidate-groups="sales-dept"
         g="96,16,127,52">
  
      <transition to="wait" />

Modified: jbpm4/trunk/modules/examples/src/test/resources/org/jbpm/examples/task/swimlane/process.jpdl.xml
===================================================================
--- jbpm4/trunk/modules/examples/src/test/resources/org/jbpm/examples/task/swimlane/process.jpdl.xml	2009-04-03 03:32:16 UTC (rev 4402)
+++ jbpm4/trunk/modules/examples/src/test/resources/org/jbpm/examples/task/swimlane/process.jpdl.xml	2009-04-03 10:45:02 UTC (rev 4403)
@@ -3,7 +3,7 @@
 <process name="TaskSwimlane" xmlns="http://jbpm.org/4/jpdl">
 
   <swimlane name="sales representative"
-            candidate-groups="sales-test-group" />
+            candidate-groups="sales-dept" />
 
   <start g="20,20,48,48">
     <transition to="enter order data" />

Modified: jbpm4/trunk/modules/userguide/src/main/docbook/en/modules/ch05-Jpdl.xml
===================================================================
--- jbpm4/trunk/modules/userguide/src/main/docbook/en/modules/ch05-Jpdl.xml	2009-04-03 03:32:16 UTC (rev 4402)
+++ jbpm4/trunk/modules/userguide/src/main/docbook/en/modules/ch05-Jpdl.xml	2009-04-03 10:45:02 UTC (rev 4403)
@@ -526,6 +526,8 @@
 &lt;/process&gt;</programlisting>
     </section>
 
+    <!-- ### END ########################################################### -->
+    
     <section id="end">
       <title><literal>end</literal></title>
       <para>Ends the execution.
@@ -688,6 +690,8 @@
         respectively.</para>
       </section>
     </section>
+
+    <!-- ### JAVA ########################################################## -->
       
     <section id="java">
       <title><literal>java</literal></title>
@@ -813,6 +817,8 @@
       </para>
     </section>
 
+    <!-- ### TASK ########################################################## -->
+
     <section id="task">
       <title><literal>task</literal></title>
 
@@ -843,18 +849,11 @@
                 <entry>userId referring to the person that is responsible for 
                 completing this task.</entry>
               </row>
-              <row>
-                <entry><literal>assignee-lang</literal></entry>
-                <entry>expression language</entry>
-                <entry>juel</entry>
-                <entry>optional</entry>
-                <entry>expression language used in the assignee attribute</entry>
-              </row>
             </tbody>
           </tgroup>
         </table>
-	      <figure id="process.task">
-	        <title>The task example process</title>
+	      <figure id="process.task.assignee">
+	        <title>The task assignee example process</title>
 	        <mediaobject><imageobject><imagedata align="center" fileref="images/process.task.png"/></imageobject></mediaobject>
 	      </figure>
 	      <programlisting>&lt;process name=&quot;TaskAssignee&quot;&gt;
@@ -864,7 +863,7 @@
   &lt;/start&gt;
 
   &lt;task name=&quot;review&quot; 
-        assignee=&quot;#{order.owner}&quot;&gt;
+        <emphasis role="bold">assignee=&quot;#{order.owner}&quot;</emphasis>&gt;
  
      &lt;transition to=&quot;wait&quot; /&gt;
   &lt;/task&gt;
@@ -906,7 +905,8 @@
           variable.</para>
           <programlisting>Map&lt;String, Object&gt; variables = new HashMap&lt;String, Object&gt;(); 
 variables.put(&quot;order&quot;, new Order(&quot;johndoe&quot;));
-Execution execution = executionService.startProcessInstanceByKey(&quot;TaskAssignee&quot;, variables);</programlisting>
+Execution execution = executionService
+    .startProcessInstanceByKey(&quot;TaskAssignee&quot;, variables);</programlisting>
         <para>Then the task list for <literal>johndoe</literal> can be obtained like this.</para>
         <programlisting>List&lt;Task&gt; taskList = taskService.findAssignedTasks(&quot;johndoe&quot;);</programlisting>
         <para>Note that it is also possible to put plain text like 
@@ -920,10 +920,301 @@
         <para>A task that will be offered to a group of users.  One of the users should then 
         take the task in order to complete it.
         </para>
-        <para>TODO</para>
+        <table><title><literal>task</literal> attributes:</title>
+          <tgroup cols="5" rowsep="1" colsep="1">
+            <thead>
+              <row>
+                <entry>Attribute</entry>
+                <entry>Type</entry>
+                <entry>Default</entry>
+                <entry>Required?</entry>
+                <entry>Description</entry>
+              </row>
+            </thead>
+            <tbody>
+              <row>
+                <entry><literal>candidate-groups</literal></entry>
+                <entry>expression</entry>
+                <entry></entry>
+                <entry>optional</entry>
+                <entry>resolves to a comma separated list of groupIds.
+                All the people in the groups will be candidates for this 
+                task.</entry>
+              </row>
+              <row>
+                <entry><literal>candidate-users</literal></entry>
+                <entry>expression</entry>
+                <entry></entry>
+                <entry>optional</entry>
+                <entry>resolves to a comma separated list of userIds.
+                All the users will be candidates for this task.</entry>
+              </row>
+            </tbody>
+          </tgroup>
+        </table>
+        <figure id="process.task.candidates">
+          <title>The task candidates example process</title>
+          <mediaobject><imageobject><imagedata align="center" fileref="images/process.task.png"/></imageobject></mediaobject>
+        </figure>
+        <para>Here's an example process using task candidates:</para>
+        <programlisting>&lt;process name=&quot;TaskCandidates&quot;&gt;
+
+  &lt;start&gt;
+    &lt;transition to=&quot;review&quot; /&gt;
+  &lt;/start&gt;
+
+  &lt;task name=&quot;review&quot; 
+        <emphasis role="bold">candidate-groups=&quot;sales-dept&quot;</emphasis>&gt;
+ 
+     &lt;transition to=&quot;wait&quot; /&gt;
+  &lt;/task&gt;
+  
+  &lt;state name=&quot;wait&quot;/&gt;
+
+&lt;/process&gt;
+        </programlisting>
+        <para>After starting, a task will be created.  The task will not show up in anyone's
+        personal task list.  Following task lists will be empty.
+        </para>
+        <programlisting>taskService.getAssignedTasks(&quot;johndoe&quot;);
+taskService.getAssignedTasks(&quot;joesmoe&quot;);</programlisting>
+        <para>But the task will show up in the takable task list of all members of the <literal>sales-dept</literal>
+        group.   
+        </para>
+        <para>The in our example, the <literal>sales-dept</literal> has two members: johndoe and joesmoe</para>
+        <programlisting>identityService.createGroup(&quot;sales-dept&quot;);
+
+identityService.createUser(&quot;johndoe&quot;, &quot;johndoe&quot;, &quot;John&quot;, &quot;Doe&quot;);
+identityService.createMembership(&quot;johndoe&quot;, &quot;sales-dept&quot;);
+
+identityService.createUser(&quot;joesmoe&quot;, &quot;joesmoe&quot;, &quot;Joe&quot;, &quot;Smoe&quot;);
+identityService.createMembership(&quot;joesmoe&quot;, &quot;sales-dept&quot;); </programlisting>
+        <para>So after the process is created, the task will appear in both the 
+        takable tasks for users johndoe and joesmoe</para>
+        <programlisting>taskService.findTakableTasks("johndoe");
+taskService.findTakableTasks("joesmoe");</programlisting>
+        <para>Candidates must take a task before they can work on it. This will prevent 
+        that two candides start working on the same task.  The user interface must only 
+        offer the action 'Take' for the tasks in the takable task list.    
+        </para>
+        <programlisting>taskService.takeTask(task.getDbid(), &quot;johndoe&quot;);</programlisting>
+        <para>When a user takes a task, the assignee of that task will be set to the given 
+        user.  The task will disappear from all the candidate's takable task list and 
+        it will appear in the user's assigned tasks.
+        </para>
+        <para>Users are only allowed to work on tasks in their personal task list.  This 
+        should be enforced by the user interface.</para>
+        <para>Similarly, the attribute <literal>candidate-users</literal> can be used that 
+        resolves to a comma separated list of userIds.  The <literal>candidate-users</literal>  
+        attribute can be used in combination with other assignment options.
+        </para>
       </section>
+
+      <section id="taskassignmenthandler">
+        <title><literal>task</literal> assignment handler</title>
+        <para>An <literal>AssignmentHandler</literal> can be used to calculate the 
+        assignee and the candidates for a task programmatically. 
+        </para>
+        <programlisting>public interface <emphasis role="bold">AssignmentHandler</emphasis> extends Serializable {
+
+  /** sets the actorId and candidates for the given assignable. */
+  void assign(Assignable assignable, OpenExecution execution) throws Exception;
+}</programlisting>
+        <para><literal>Assignable</literal> is a common interface for Tasks and
+        Swimlanes.  So AssignmentHandlers can be used for tasks as well as swimlanes 
+        (see later).
+        </para>
+        <para><literal>task-handler</literal> is a sub element of the task element.</para>      
+        <table><title><literal>task-handler</literal> attributes:</title>
+          <tgroup cols="5" rowsep="1" colsep="1">
+            <thead>
+              <row>
+                <entry>Attribute</entry>
+                <entry>Type</entry>
+                <entry>Default</entry>
+                <entry>Required?</entry>
+                <entry>Description</entry>
+              </row>
+            </thead>
+            <tbody>
+              <row>
+                <entry><literal>class</literal></entry>
+                <entry>swimlane (string)</entry>
+                <entry></entry>
+                <entry>optional</entry>
+                <entry>refers to a swimlane that is declared in the process</entry>
+              </row>
+            </tbody>
+          </tgroup>
+        </table>
+        <para>Let's look at the task assignment example process.</para>
+        <programlisting>&lt;process name=&quot;TaskAssignmentHandler&quot; xmlns=&quot;http://jbpm.org/4/jpdl&quot;&gt;
+
+  &lt;start g=&quot;20,20,48,48&quot;&gt;
+    &lt;transition to=&quot;review&quot; /&gt;
+  &lt;/start&gt;
+  
+  &lt;task name=&quot;review&quot; g=&quot;96,16,127,52&quot;&gt;
+    <emphasis role="bold">&lt;assignment-handler class=&quot;org.jbpm.examples.task.assignmenthandler.AssignTask&quot;&gt;
+      &lt;field name=&quot;assignee&quot;&gt;
+        &lt;string value=&quot;johndoe&quot; /&gt;
+      &lt;/field&gt;
+    &lt;/assignment-handler&gt;</emphasis>
+    &lt;transition to=&quot;wait&quot; /&gt;
+  &lt;/task&gt;
+
+  &lt;state name=&quot;wait&quot; g=&quot;255,16,88,52&quot; /&gt;
+  
+&lt;/process&gt;</programlisting>
+        <para></para>
+      </section>
+
+      <section id="taskswimlanes">
+        <title><literal>task</literal> swimlanes</title>
+        <para>Multiple tasks in a process should be assigned to the same 
+        user or candidates.  Multiple tasks in a process can be associated to a 
+        single swimlane.  The process instance will remember the candidates and user 
+        that performed the first task in the swimlane.  And subsequent tasks in the 
+        same swimlane will be assigned to those user and candidates. 
+        </para>
+        <para>A swimlane can also be considered as a process role.  In some 
+        cases, this might boil down to authorization roles in the 
+        identity component.  But bare in mind that it is not always the 
+        same thing.</para>
+        <table><title><literal>task</literal> attributes:</title>
+          <tgroup cols="5" rowsep="1" colsep="1">
+            <thead>
+              <row>
+                <entry>Attribute</entry>
+                <entry>Type</entry>
+                <entry>Default</entry>
+                <entry>Required?</entry>
+                <entry>Description</entry>
+              </row>
+            </thead>
+            <tbody>
+              <row>
+                <entry><literal>swimlane</literal></entry>
+                <entry>swimlane (string)</entry>
+                <entry></entry>
+                <entry>optional</entry>
+                <entry>refers to a swimlane that is declared in the process</entry>
+              </row>
+            </tbody>
+          </tgroup>
+        </table>
+        <para>Swimlanes can be declared inside a process element:</para>
+        <table><title><literal>swimlane</literal> attributes:</title>
+          <tgroup cols="5" rowsep="1" colsep="1">
+            <thead>
+              <row>
+                <entry>Attribute</entry>
+                <entry>Type</entry>
+                <entry>Default</entry>
+                <entry>Required?</entry>
+                <entry>Description</entry>
+              </row>
+            </thead>
+            <tbody>
+              <row>
+                <entry><literal>name</literal></entry>
+                <entry>swimlane (string)</entry>
+                <entry></entry>
+                <entry><emphasis role="bold">required</emphasis></entry>
+                <entry>Name for this swimlane.  This is the 
+                name that will be referenced by task swimlane attributes.
+                </entry>
+              </row>
+              <row>
+                <entry><literal>assignee</literal></entry>
+                <entry>expression</entry>
+                <entry></entry>
+                <entry>optional</entry>
+                <entry>userId referring to the person that is responsible for 
+                completing this task.</entry>
+              </row>
+              <row>
+                <entry><literal>candidate-groups</literal></entry>
+                <entry>expression</entry>
+                <entry></entry>
+                <entry>optional</entry>
+                <entry>resolves to a comma separated list of groupIds.
+                All the people in the groups will be candidates for this 
+                the tasks in this swimlane.</entry>
+              </row>
+              <row>
+                <entry><literal>candidate-users</literal></entry>
+                <entry>expression</entry>
+                <entry></entry>
+                <entry>optional</entry>
+                <entry>resolves to a comma separated list of userIds.
+                All the users will be candidates for the 
+                tasks in this swimlane.</entry>
+              </row>
+            </tbody>
+          </tgroup>
+        </table>
+        <figure id="process.task.swimlane">
+          <title>The task swimlane example process</title>
+          
+          <!-- KOEN: volgende image moet aangepast worden naar  
+                     images/process.task.swimlane.png 
+                     nadat je die hebt toegevoegd aan de images directory -->
+
+          <mediaobject><imageobject><imagedata align="center" fileref="images/process.task.png"/></imageobject></mediaobject>
+        </figure>
+        <para>The task swimlane example has the following process file :</para>
+        <programlisting>&lt;process name=&quot;TaskSwimlane&quot; xmlns=&quot;http://jbpm.org/4/jpdl&quot;&gt;
+
+  <emphasis role="bold">&lt;swimlane name=&quot;sales representative&quot;
+            candidate-groups=&quot;sales-dept&quot; /&gt;</emphasis>
+
+  &lt;start&gt;
+    &lt;transition to=&quot;enter order data&quot; /&gt;
+  &lt;/start&gt;
+  
+  &lt;task name=&quot;enter order data&quot;
+        <emphasis role="bold">swimlane=&quot;sales representative&quot;</emphasis>&gt;
+
+    &lt;transition to=&quot;calculate quote&quot;/&gt;
+  &lt;/task&gt;
+
+  &lt;task 
+      name=&quot;calculate quote&quot; 
+      <emphasis role="bold">swimlane=&quot;sales representative&quot;</emphasis>&gt;
+  &lt;/task&gt;
+
+&lt;/process&gt;</programlisting>
+        <para>In this example we create the following information in the identity 
+        component:</para>
+        <programlisting>identityService.createGroup(&quot;sales-dept&quot;);
+
+identityService.createUser(&quot;johndoe&quot;, &quot;johndoe&quot;, &quot;John&quot;, &quot;Doe&quot;);
+identityService.createMembership(&quot;johndoe&quot;, &quot;sales-dept&quot;);</programlisting>
+        <para>After starting a new process instance, user <literal>johndoe</literal> will 
+        be a candidate for task <literal>enter order data</literal>.  Again like in the 
+        previous task candidates example, John Doe can now take this task like this:
+        </para>
+        <programlisting>taskService.takeTask(taskDbid, &quot;johndoe&quot;);</programlisting>
+        <para>Taking the task will make Lit<literal>johndoe</literal> the assignee for 
+        the task.  And since this task is coupled to the swimlane 
+        <literal>sales representative</literal>, assignee <literal>johndoe</literal> will 
+        also be propagated as the assignee in the swimlane.</para>
+        <para>Next, John Doe can complete the task like this:</para>
+        <programlisting>taskService.completeTask(taskDbid);</programlisting>
+        <para>Completing the task will bring the process execution to the 
+        next task, which is <literal>calculate quote</literal>.  Also 
+        this task is linked to the swimlane.  Therefore, the task will be 
+        assigned to <literal>johndoe</literal>.  Also the candidate users 
+        and candidate groups of the initial assignment will be copied from 
+        the swimlane to the task.  This is relevant in case user <literal>johndoe</literal> 
+        would release the task and offer it back to the other candidates.
+        </para>
+      </section>
     </section>
 
+    <!-- ### SCRIPT ######################################################## -->
+
     <section id="script">
       <title><literal>script</literal></title>
       <para>A script activity evaluates a script.  Scripts can be specified in any language for 
@@ -1111,6 +1402,8 @@
       </para>
     </section>
 
+    <!-- ### ESB ########################################################### -->
+
     <section id="esb">
       <title><literal>esb</literal></title>
       <para>An <literal>esb</literal> activity sends a message to a service over the ESB.  
@@ -1200,6 +1493,8 @@
       </para>
     </section>
 
+    <!-- ### HQL ########################################################### -->
+
     <section id="hql">
       <title><literal>hql</literal></title>
       <para>With the<literal>hql</literal> activity, a HQL query can be performed 
@@ -1300,6 +1595,8 @@
 &lt;/process&gt;</programlisting>
     </section>
 
+    <!-- ### SQL ########################################################### -->
+
     <section id="sql">
       <title><literal>sql</literal></title>
       <para>The <literal>sql</literal> activity is exactly the same as the
@@ -1356,4 +1653,100 @@
     </section>
   </section>
 
+  <section id="usercode">
+    <title>User code</title>
+    <para>Various elements in the jPDL process language refer to a an 
+    object on which an interface method will be invoked.  See for example
+    <xref linkend="taskassignmenthandler" />.  This section describes the 
+    attributes and sub elements of those type of user code objects. 
+    </para>
+      <table><title>attributes:</title>
+        <tgroup cols="5" rowsep="1" colsep="1">
+          <thead>
+            <row>
+              <entry>Attribute</entry>
+              <entry>Type</entry>
+              <entry>Default</entry>
+              <entry>Required?</entry>
+              <entry>Description</entry>
+            </row>
+          </thead>
+          <tbody>
+            <row>
+              <entry><literal>class</literal></entry>
+              <entry>classname</entry>
+              <entry></entry>
+              <entry><emphasis role="bold">required</emphasis></entry>
+              <entry>The fully qualified classname.</entry>
+            </row>
+          </tbody>
+        </tgroup>
+      </table>
+      <table><title>sub elements:</title>
+        <tgroup cols="3" rowsep="1" colsep="1">
+          <thead>
+            <row>
+              <entry>Element</entry>
+              <entry>Multiplicity</entry>
+              <entry>Description</entry>
+            </row>
+          </thead>
+          <tbody>
+            <row>
+              <entry><literal>field</literal></entry>
+              <entry>0..*</entry>
+              <entry>describes a configuration value to be injected directly in 
+              a memberfield before this user class is used.</entry>
+            </row>
+            <row>
+              <entry><literal>property</literal></entry>
+              <entry>0..*</entry>
+              <entry>describes a configuration value to injected through a setter 
+              method before this user object is used.</entry>
+            </row>
+          </tbody>
+        </tgroup>
+      </table>
+      <table><title><literal>field</literal> attributes:</title>
+        <tgroup cols="5" rowsep="1" colsep="1">
+          <thead>
+            <row>
+              <entry>Attribute</entry>
+              <entry>Type</entry>
+              <entry>Default</entry>
+              <entry>Required?</entry>
+              <entry>Description</entry>
+            </row>
+          </thead>
+          <tbody>
+            <row>
+              <entry><literal>name</literal></entry>
+              <entry>string</entry>
+              <entry></entry>
+              <entry><emphasis role="bold">required</emphasis></entry>
+              <entry>the name of the field</entry>
+            </row>
+          </tbody>
+        </tgroup>
+      </table>
+      <table><title><literal>field</literal> sub elements:</title>
+        <tgroup cols="3" rowsep="1" colsep="1">
+          <thead>
+            <row>
+              <entry>Element</entry>
+              <entry>Multiplicity</entry>
+              <entry>Description</entry>
+            </row>
+          </thead>
+          <tbody>
+            <row>
+              <entry><literal>string</literal></entry>
+              <entry>0..1</entry>
+              <entry>represents a string value</entry>
+            </row>
+          </tbody>
+        </tgroup>
+      </table>
+  </section>
+
 </chapter>




More information about the jbpm-commits mailing list