This guide is accurate for Foundation 3.0.1, Foundation 3.0, and Foundation 1.0 (RTC 2.0).
Overview
A project area represents a development project. A project area contains a multi-rooted hierarchy of team areas. (We sometimes refer to both project areas and team areas asprocess areas.)
A project area is associated with a team process. Part of the team process is a specification of the executable process. Teams specify their process by configuring operations, events, and data.
A project area may have a set of timelines. Each timeline may be broken down into a set of iterations. An iteration is an interval in the lifetime of the project. An iteration can be decomposed into sub iterations. One timeline can be marked as the project timeline. This is the overall timeline for the project and all its teams. Additional timelines can be defined and root team areas can be assigned to them. When a root team area is assigned to a specific timeline, that team and all child team areas will be governed by the specified timeline instead of the project timeline. (Conceptually, this timeline + team area association can be thought of as a kind of "sub-project" on its own schedule.)
The project area can also define a set of iteration types which can be assigned to iterations. A project's permissions and behavior can be customized for any given timeline, iteration, or iteration type.
The process template chosen when creating a project area declares the initial set of timelines, iterations, and iteration types, along with a default executable process. The process template may also define a set of initial setup actions which are run when a newly created project area is initialized.
An example executable process specification looks like this:
Each team area can override the permissions and behavior defined in the process specification by specifying a new configuration in its team customization. The actual executable process governing a team area is determined at runtime by the executable process of its project area patched by all overriding configurations. The search path for overriding configurations starts at the team area and goes up the team area hierarchy to the root. From the root it goes to the project area. Configurations can only be overridden if they are not marked as final in any node closer to the end of the search path.
(A detailed explanation of the runtime's search path can be found in the Process Behavior Lookup article.)
The specification of an overriding configuration in the team customization looks similar to the process specification with the difference that it only talks about the iterations and roles whose configurations it wants to override.
Components and Process
Components usually interact with the Team Process component in two ways:
- a component allows the team process to impact its behavior
- a component extends the set of choices that are available when configuring behavior
Components that allow the team process to impact their behavior can do so along three different lines corresponding to the three different kinds of configuration points:
- Operations when a component wants to allow teams to configure permissions or when the components wants to allow preparation steps such as precondition checking or automated followup actions. These additional contributions to the operation are called advisors and participants. Advisors are run in advance and determine whether or not an operation should be executed. Participants are run after an operation is executed and generally cause additional modifications to the repository related to the operation. (Note: In the user interface, advisors are called "preconditions" and participants are called "follow-up actions".)
- Configuration data when the component wants to allow the team process to provide XML data. The format of the configuration data is defined by the component. The component can access the data at any point in time and can do whatever it wants with it.
- Events when a component issues change events for which it wants to allow the process to define server side event handlers.
Components that want to extend the set of available behaviors may add new participants, advisors and event handlers.
Open up for Process Interaction
In order to open up for process interaction the following plug-ins are required:
- On the server
- com.ibm.team.process.common
- com.ibm.team.process.service
- On the client
- com.ibm.team.process.common
- com.ibm.team.process.client
Operations
A component can open up for process participation in operations on the server and on the client. Process can "advise and execute" operations or it can merely "advise" them. Simply advising an operation is intended to answer the question for the user "What would happen if I did this now?"
Process Execution of Operations
When process is asked to advise and execute an operation, it will first run all advisors which are configured for the operation. Conceptually, advisors decide whether or not an operation should proceed. Advisors report any problems in the form of errors. If no advisors report any errors, the process runtime will invoke the operation. After the operation completes, participants are invoked. If a participant fails for some reason, either throwing an uncaught exception or reporting an error, no further participants are executed. This is the same for both the client and server process.
There is an important difference between the client and server process, though. The server process runs the entire request to advise and execute an operation in a single transaction. All advisors, the operation, and all participants are run in this transaction and if any errors are detected or any exceptions thrown, the entire transaction is rolled back. But if a participant fails on the client, the operation and any participants which have already run will have already done their work. For this reason, we say that client-side participants (and advisors) may not cause modifications to the repository.
Process Advising of Operations
When process is asked to only advise an operation, it will first run all advisors which are configured for the operation. The advisors will produce their errors and then process will call the advise(...) method on the operation. AdvisableOperation#advise(...) is a method which subclasses may optionally implement if the operation has some code that it wants to perform to participate in the advising.
For example, a client-side operation may support performing server-side checks. The client-side operation would implement advise(...) to call a service method. The service implementation would then ask the server-side process to advise an operation and it would return the result to the client. The client's implementation of advise(...) would then return this result. A concrete example of this scenario can be seen in the implementation of
IExampleClientService#save(IExampleItem, boolean)
Defining Operations on the Server
- The component defines an operation configuration point:
- Please see ProcessExtensionSchemas to learn about how to define a schema.
- The component wraps its operation implementation into an
AdvisableOperation
and passes it to the server-side team process for a certain team or project area. Usually, the operation affects an item that is associated with an area. However, the component decides which area to use. - A process enabled server operation should include the operation report generated for the advisable operation into its response to the caller. This can be done by either extending the component specific server response to piggyback the operation report or by defining the service method to return a response of one of the operation response types provided by the process component.
The implementation of a server-side operation might look something like this:
public class MySaveOperation extends AdvisableOperation { private MyItem itemToSave; private MyItem saved; private IRepositoryItemService itemService; public MySaveOperation(MyItem itemToSave, IProcessArea processArea, IRepositoryItemService itemService) { super("com.ibm.example.service.mySaveOperation", itemToSave, processArea); this.itemToSave = itemToSave; this.itemService = itemService; } public IOperationReport run(IBehaviorConfiguration configuration, IProgressMonitor monitor) throws TeamRepositoryException { saved = (MyItem) service.saveItem(item, monitor); return null; // No nested report to return. } public MyItem getSavedItem() { return saved; } }
The component's service implementation would then invoke this operation:
public IItemsResponse saveItem(MyItem itemToSave) throws TeamRepositoryException { IProcessArea processArea = findProcessArea(itemToSave); // custom component logic IRepositoryItemService itemService = getService(IRepositoryItemService.class); IProcessServerService processService = getService(IProcessServerService.class); IServerProcess serverProcess = processService.getServerProcess(processArea); MySaveOperation operation = new MySaveOperation(itemToSave, processArea, itemService); IOperationReport report = serverProcess.adviseAndExecute(operation); IItemsResponse response = ProcessCommon.createItemsResponse(); response.setOperationReport(report); MyItem saved = operation.getSavedItem(); response.setClientItems(new IExampleItem[] { saved }; return response; }
Grouping Operations on the Server (Process Runnables)
This section is not something most components are expected to utilize.
A ProcessRunnable is most commonly defined on the client to support implementing a server-side only operation. However, they can also be a useful tool for the purpose of grouping multiple server-side operations so that they will be run in a single transaction and grouped together when they are presented to the user.
A service method can run any number of process-enabled operations inside the context of a process runnable and it need only return the single report generated for the runnable in order to transfer all of the nested reports to the client as well. This works because the process framework automatically appends reports together when they are called in the same thread.
For example, the Process component defines a process runnable on the server when saving multiple team areas. Each team area is potentially saved according to a different process so they must be saved in separate operations. But by using a process runnable, all of these operations are grouped together at runtime (in a single transaction) and in the client UI (Team Advisor view).
The implementation of a server-side process runnable might look something like this:
public class MyItemsSaveRunnable extends ProcessRunnable { private MyItem[] itemsToSave; private MyItem[] saved; private MyService service; public MyItemsSaveRunnable(MyItem[] itemsToSave, MyService service) { this.itemsToSave = itemsToSave; this.service = service; } public IOperationReport run(IProgressMonitor monitor) { saved = new MyItem[itemsToSave.length]; for (int i = 0; i < itemsToSave.length; i++) { // Invoke component logic which saves an item using an operation saved[i] = service.internalSaveItem(item); } return null; // server-side runnables don't return anything } public MyItem[] getSavedItems() { return saved; } }
The component service would then execute this runnable:
public IItemsResponse saveItems(final MyItem[] items) throws TeamRepositoryException { IProcessServerService processService = getService(IProcessServerService.class); MyItemsSaveRunnable runnable = new MyItemsSaveRunnable(items, this); IOperationReport report = processService.execute(runnable, "Save My Items"); MyItem[] saved = runnable.getSavedItems(); IItemsResponse response = ProcessCommon.createItemsResponse(); response.setOperationReport(report); reponse.setClientItems(saved); return response; }
Defining Operations on the Client
- The component defines an operation configuration point:
- Please see ProcessExtensionSchemas to learn about how to define a schema.
- The component wraps its operation into an
AdvisableOperation
and passes it to the client-side team process for a certain team or project area. Usually, the operation affects an item that is associated with an area. However, the component decides which area to use. - When the operation involves the call of a process-enabled server-side service method, your implementation of the advisable operation's
run
method should return the server side generated operation report. - The server-side team process will throw a
TeamOperationCanceledException
in the event that the operation is canceled by process. This exception is currently a subclass ofTeamRepositoryException
which carries anIOperationReport
. If anAdvisableOperation
calls a service method inrun()
and catchesTeamRepositoryException
(this is generally not recommended), the implementation should rethrow the exception if it is aTeamOperationCanceledException
.
The implementation of a client-side operation might look something like this:
public class MySaveOperation extends AdvisableOperation { private MyItem itemToSave; private MyItem saved; private MyService service; public MySaveOperation(MyItem itemToSave, IProcessArea processArea, MyService service) { super("com.ibm.example.client.mySaveOperation", itemToSave, processArea); this.itemToSave = itemToSave; this.service = service; } public IOperationReport run(IBehaviorConfigurationconfiguration, IProgressMonitor monitor) throws TeamRepositoryException { IItemsResponse serviceResponse = service.saveItem(itemToSave, monitor); // invoke the service method saved = (MyItem) response.getFirstClientItem; return response.getOperationReport(); // Return the nested server-side report. } public MyItem getSavedItem() { return saved; } }
The component's client library would then invoke this operation:
public MyItem saveItem(MyItem itemToSave, IProgressMonitor monitor) throws TeamRepositoryException { IProcessArea processArea = findProcessArea(itemToSave); // custom component logic MyService myService = (MyService) clientLibraryContext.getServiceInterface(IProcessService.class); IProcessClientService processService = repository.getClientLibrary(IProcessClientService.class); IClientProcess clientProcess = processService.getClientProcess(processArea, monitor); MySaveOperation operation = MySaveOperation(itemToSave, processArea, myService); clientProcess.adviseAndExecute(operation); return operation.getSavedItem(); }
Server-side Only Operations (Process Runnables)
If a component wishes to define a process-enabled operation on the server which in not invoked by a corresponding process-enabled operation on the client, a ProcessRunnable can be defined on the client which returns the server-side report to the process framework. By using a process runnable which returns the server-side report, a server-side only operation can be displayed to the end user by the process framework.
Process runnables are simply instantiated at runtime and passed to the process framework. They are not declared via an extension point, so they don't show up in the process specification. Process runnables do not allow for advisors, participants, or permission checking; they are just executed by the framework.
The implementation of a client-side process runnable might look something like:
public class MyItemSaveRunnable extends ProcessRunnable { private MyItem itemToSave; private MyItem saved; private MyService service; public MyItemSaveRunnable(MyItem itemToSave, MyService service) { this.itemToSave = itemToSave; this.service = service; } public IOperationReport run(IProgressMonitor monitor) throws TeamRepositoryException { IItemsResponse response = service.saveItem(item, monitor); saved = (MyItem) response.getFirstClientItem(); // Return the operation report from the server to the process framework. return response.getOperationReport(); } public MyItem getSavedItem() { return savedItem; } }
The component's client library would then execute this process runnable:
public MyItem saveItem(MyItem item, IProgressMonitor monitor) throws TeamRepositoryException { MyService service = clientLibraryContext.getServiceInterface(MyService.class); IProcessClientService processClient = (IProcessClientService) clientLibraryContext.getTeamRepository().getClientLibrary(IProcessClientService.class); MyItemSaveRunnable runnable = new MyItemSaveRunnable(item, service); processClient.execute(runnable, monitor); return runnable.getSavedItem(); }
Operation Actions (Process Permissions)
Operations can declare a set of actions which they may perform. A team can then configure their process to selectively grant permission to perform those actions. At runtime, an operation can report which actions it will perform and process can allow/disallow the operation based on the applicable permissions.
An operation's available actions are declared in the client or server extension. For example:
The team would then configure the permitted actions:
[...]Here, the process uses the special keyword "any" to specify that all "Modify" actions are allowed.[...]
An operation can report any path in its declared actions at runtime. In this example, the "Save Example Item" operation could return the following values as actions:
"Modify" "Modify/Description" "Modify/Name"
When process is asked to execute an operation, it asks it for the actions it will perform. These actions are then compared against the permissions which apply to the current logged in user. As long as the permitted action paths match the actions to be performed, process will execute the operation. Otherwise, the operation will be blocked and reported in the Team Advisor view.
Secondary Actions (Multi-Area Operations)
We say that an advisable operation is run relative to a process area and it can return a set of actions for the purpose of checking permissions. However, sometimes an operation needs to check permissions relative to more than just one process area and this is supported by allowing to specify "secondary" areas and actions.
This is important, for example, for an operation which moves an item from the context of one team area to another. In order to enforce a notion of ownership which is enforced by process permissions, such an operation would specify the source area as a secondary process area and return an appropriate action for this area, such as "remove".
Secondary areas are consulted only for permissions. Advisors and participants configured for secondary areas are not invoked.
An operation which moved an item from one team area to another and enforced permissions relative to both areas might look something like:
public class MyItemMoveOperation extends AdvisableOperation { IProcessArea sourceArea; public MyItemMoveOperation(MyItem itemToMove, IProcessArea targetArea, IProcessArea sourceArea) { // Use targetArea as the operation's primary area super("com.example.moveItem", itemToMove, targetArea); this.sourceArea = sourceArea; } public IOperationReport run(...) { [...] } public String[] getActions() { // Return actions for the operation's process area (targetArea) return new String[] { "add" }; } public IProcessArea[] getSecondaryAreas() { return new IProcessArea[] { sourceArea }; } public String[] getActions(IProcessArea secondaryArea) { if (secondaryArea.sameItemId(sourceArea)) { return new String[] { "remove" }; } return super.getActions(secondaryArea); } }
Process Data Validation (Configuration Source)
For operations which run on the client and server, the process framework provides a mechanism to validate that clients are running up-to-date process.
When a client-side operation is run, we pass in the
IBehaviorConfiguration
which configures the operation. This object carries an "operation configuration info" object which contains information about exactly which process configuration was used (see IBehaviorConfiguration#getOperationConfigurationInfo()
). The client-side operation can pass this IOperationConfigurationInfo over the wire in its service method.
On the server, we have API which takes one of these configuration info objects and validates that the configuration which was run on the client in sync with the current repository contents (
IServerProcess#validateSource(IOperationConfigurationInfo)
). If validation fails, an exception is thrown.
Back on the client, process catches this exception from the client-side operation, updates the client's process data, and re-runs the operation (if the operation supports this). Tying into this mechanism provides a seamless experience for the end user.
Configuration Data
A component can open up for configuration data on the server and on the client. Configuration data, independent of where it has been declared, can always be accessed on both the client and the server without limitation. Configuration data can only be defined in the project area and is global in nature. Configuration data should be used sparingly, only in situations where the data in question is really part of a project's process. In particular, components are warned against using configuration data for settings which should really be user preferences or which should be persisted as part of their component model and configured in their own editors.
Configuration Data on the Server
- The component defines a configuration data configuration-point (the element name "staticConfigurationData" is a holdover which will be changed to "configurationData" eventually):
- Please see ProcessExtensionSchemas to learn about how to define a schema.
- The component retrieves the configuration data from the server-side team process for the project area.
IProcessArea processArea = findProcessArea(parameter); IProcessServerService service = (IProcessServerService) getService(IProcessServerService.class); IServerProcess serverProcess = service.getServerProcess(processArea); IProcessConfigurationData data = serverProcess.getProjectConfigurationData("com.ibm.team.process.example.elementPreferences"); if (data != null) { IProcessConfigurationElement[] elements = data.getElements(); for (int i = 0; i < elements.length; i++) { IProcessConfigurationElement element = elements[i]; ... } }
Configuration Data on the Client
- The component defines a static configuration data configuration-point:
- Please see ProcessExtensionSchemas to learn about how to define a schema.
- The component retrieves the configuration data from the client-side team process for the project area.
IProcessArea processArea = findProcessArea(parameter); IProcessClientService processService = (IProcessClientService) repository.getClientLibrary(IProcessClientService.class); IClientProcess clientProcess = processService.getClientProcess(processArea, new SubProgressMontior(monitor, 1)); IProcessConfiguration data = clientProcess.getProjectConfigurationData("com.ibm.team.process.example.itemTypes", new SubProgressMontior(monitor, 1)); if (data != null) { IProcessConfigurationElement[] elements = data.getElements(); for (int i = 0; i < elements.length; i++) { IProcessConfigurationElement element = elements[i]; ... } }
Events
In order for a component's server part to allow process reaction to its change events, the component must define an event configuration point. The event's identifier corresponds to the value of
IChangeEvent#getCategory()
The process server-side component installs a scheduling task on the server which queries for new change events at a regular interval and dispatches them to the event handlers which have been configured by the team.
Associate Items with a Process Area
All of the scenarios above have forced the component to retrieve a client or server-side process relative to a process area. Usually, the process area is determined based on the items affected by a particular operation and those items' association to a team area.
A component defines the way in which its items are associated with a process area. The typical way to do this is by adding a field to the item which references a process area.
Extending the Choices of Process
In order to extend the choices of process the following plug-ins are required:
- On the client
- com.ibm.team.process.common
- com.ibm.team.process.client
- com.ibm.team.process.ide.ui
- On the server
- com.ibm.team.process.commmon
- com.ibm.team.process.service
Adding New Operation Advisors
Operation advisors are run before an operation is invoked to decide whether or not the operation should be executed. Advisors check conditions and report problems via the collector they are given at runtime. If an advisor reports a serious problem with an operation, the operation will not be executed (though subsequent advisors will still be checked).
Advisors may not make modifications to data which is persisted in the repository. If an advisor were to modify the data in the repository, its changes could invalidate the checks made by previous advisors which would potentially cause a team's desired preconditions to not be correctly enforced. Clients wishing to participate in operations by modifying data should implement a participant instead.
Client-side advisors support the notion of being optionally overrulable. If a team specifies that users can overrule an advisor, users have the freedom to ignore a particular advisor if they wish it. The support for overruling advisors is handled completely by the process framework. Advisor implementors do not need to do anything to support it. Note that at this time, onlyclient-side advisors support overruling.
Operation advisors can be provided for the client and the server side via the com.ibm.team.process.client.operationAdvisors and com.ibm.team.process.service.operationAdvisors extension points, respectively.
In order to provide a new advisor available in process definitions and process settings a component must:
- Implement a new advisor by implementing
com.ibm.team.process.common.advice.runtime.IOperationAdvisor
. - Provide an extension to the operation advisor extension point to declare the new advisor
- Optionally, a component may provide a schema which describes custom syntax for configuring the advisor. See ProcessExtensionSchemas for details.
This advisor requires that everything is great before something can be modified.
If a server-side advisor does not make reference to any services, providing an implementation of this interface via an extension declaration like the example above is sufficient. However, there are two additional requirements for server-side implementors who wish to access services:
- The implementation of this interface must also extend com.ibm.team.repository.service.AbstractService.
- The extension declaration of such an advisor must include an
extensionService
element which declares all of the services which the advisor requires.
The following example shows a definition of a server-side advisor which requires the repository item service and the process server service:
This advisor requires that everything is great before something can be modified.
Adding New Operation Participants
Operation participants run after an operation is invoked and may make modifications to the repository. In an operation fails (for example, because it is blocked by an advisor or if an exception occurs), its participants will not be invoked. On the server, participants are run in the same transaction as the operation in which they are participating.
If an participant throws an exception or reports a serious problem, subsequent participants will not be run. On the server, this will cause the entire operation transaction to be rolled back.
Operation participants can be provided for the client and the server side via the com.ibm.team.process.client.operationParticipants and com.ibm.team.process.service.operationParticipants extension points, respectively.
In order to provide a new participant which teams can configure for an operation a component must:
- Implement a new participant by implementing
com.ibm.team.process.common.advice.runtime.IOperationParticipant
. - Provide an extension to the operation participant extension point to declare the new participant
- Optionally, a component may provide a schema which describes custom syntax for configuring the participant. See ProcessExtensionSchemas for details.
This participant creates a receipt whenever something is modified.
If a server-side participant does not make reference to any services, providing an implementation of this interface via an extension declaration like the example above is sufficient. However, there are two additional requirements for server-side implementors who wish to access services:
- The implementation of this interface must also extend com.ibm.team.repository.service.AbstractService.
- The extension declaration of such a participant must include an
extensionService
element which declares all of the services which the participant requires.
The following example shows a definition of a server-side participant which requires the repository item service and the process server service:
This participant creates a receipt whenever something is modified.
Adding New Event Handlers
Event handlers can only be provided for the server side. In order to provide a new event handler which teams can configure for an event a component must:
- Implement a new event handler by implementing the interface
com.ibm.team.process.service.IChangeEventHandler
. - Declare an extension to the event handler extension point to provide the new event handler.
- Optionally, a component may provide a schema which describes custom syntax for configuring the handle. See ProcessExtensionSchemas for details.
Hooking in to Content Assist in the Process Editors
In addition to defining schema to describe the format of component specific data associated with a process related configuration point, component authors can register to provide completion proposals for attribute values when content assist is requested in the process editors.
For example, if your schema defines a new element "foo" with an attribute "type" and you want to provide the user with a list of valid values for the "type" attribute when content assist is requested, this mechanism will allow you to do that.
In order contribute your proposals, in one of your component's client-side plugins, you need to provide an extension to the
com.ibm.team.process.ide.ui.attributeValueProposalProviders
extension point. Via this extension, you will indicate which source types (specifications and/or customization) you support and the attributes for which you intend to provide values. In addition, you must specify a class which implements com.ibm.team.process.ide.ui.IAttributeValueProposalProvider
. This is the class which will be called to obtain the completion proposals. Please see the extension point description for additional details.
The following is an example extension which provides attribute value proposals for an attribute named "fooType" which appears on elements named "foo" in the "http://com.ibm.team.process.ide.ui.tests" namespace. Proposals are provide for both specification and customization source types:
The following is the code for the
TestAttributeValueProvider
class referenced by the extension.public class TestAttributeValueProvider implements IAttributeValueProposalProvider { public TestAttributeValueProvider() { } public IProcessCompletionProposal[] computeProposals(IProcessArea processArea, IProcessProposalContext context, IProgressMonitor monitor) { ArrayList proposals = new ArrayList(); switch (context.getSourceType()) { case IProcessProposalContext.SPECIFICATION_SOURCE_TYPE: if (processArea instanceof IProjectArea) { IProjectArea projectArea = (IProjectArea) processArea; List teamAreas = projectArea.getTeamAreas(); ITeamRepository repo = (ITeamRepository) projectArea.getOrigin(); IItemManager itemManager = repo.itemManager(); try { List items = itemManager.fetchCompleteItems(teamAreas, IItemManager.DEFAULT, monitor); for (Iterator iterator = items.iterator(); iterator.hasNext();) { ITeamArea teamArea = (ITeamArea) iterator.next(); if (teamArea != null) { proposals.add(ProcessCompletionProposalFactory.createProposal(context, teamArea.getName())); } } } catch (TeamRepositoryException e) { // just ignore for this test / example provider... } } else { proposals.add(ProcessCompletionProposalFactory.createProposal(context, "A1")); proposals.add(ProcessCompletionProposalFactory.createProposal(context, "B1")); proposals.add(ProcessCompletionProposalFactory.createProposal(context, "C1")); } break; case IProcessProposalContext.CUSTOMIZATION_SOURCE_TYPE: proposals.add(ProcessCompletionProposalFactory.createProposal(context, "A2")); proposals.add(ProcessCompletionProposalFactory.createProposal(context, "B2")); proposals.add(ProcessCompletionProposalFactory.createProposal(context, "C2")); break; } return (IProcessCompletionProposal[]) proposals.toArray(new IProcessCompletionProposal[proposals.size()]); } }
This particular provider provides a static list of proposals "A2", "B2", "C2" when invoked for the customization source type (e.g. when content assist is used in the Team Area editors 'customization' tab). When it is called for a specification source type and the process area provided is a project area (e.g. when content assist is used in the Project Area editor 'specification' tab) the proposals are the names of the team areas for the project area. When the provided process area is not a project area (i.e. content assist was invoked in the specification tab of a template editor), the proposals provided are "A1", "B1", "C1".
While this provider only provides for a single attribute, through the use of the namespace, element, and attribute configuration elements, a single provider can indicate its ability to provide for multiple attributes spanning multiple elements and/or namespaces.
Gotchas
The following are specific situations that we have discovered can be confusing for people who haven't yet totally absorbed the Team Process mindset.
- Operations may involve other operations and the two may involve different processes. For example:
- SCM stream HEAD is associated with team area Foo
- Workitem category UI is associated with team area Bar
- Deliver code to HEAD
- For the deliver operation, the advisors and participants configured in team area Foo will be run
- One of the deliver participants modifies a workitem whose category is UI
- For the workitem save operation, the advisors and participants configured in team area Bar will be run
댓글 없음:
댓글 쓰기