resueltos - recursividad en c# pdf
TFS2010: recuperar todos los conjuntos de cambios asociados con una rama(recursiĆ³n completa) (3)
Finalmente se me ocurrió una solución simple. No estoy del todo contento con eso, ya que parece un algoritmo de fuerza bruta, pero al menos funciona.
Lo que hago es:
1) Obtenga la lista de cada conjunto de cambios que se aplica en la raíz de mis ramas de TFS (es decir, la "ruta principal" de Main Trunk
):
var allChangesets = vcs.QueryHistory(
"MySourcePath",
VersionSpec.Latest,
0,
RecursionType.Full,
null,
firstPossibleChangeset,
VersionSpec.Latest,
int.MaxValue,
true,
false).OfType<Changeset>().ToList();
2) Para cada conjunto de cambios recuperado, llamo a TrackMerges
para ver si el conjunto de cambios afecta de alguna manera a mis sucursales. TrackMerges
puede decirme si un conjunto de cambios especificado se aplica en las ramas que especifico como parámetro de la función (devolverá el ID de conjunto de cambios de destino en estas ramas). Si se aplica un conjunto de cambios en la rama de destino (en mi caso APP_A_1.3
) y no en la rama de origen ( APP_A_1.2
), significa que definitivamente es algo nuevo en mi rama APP_A_1.3
.
List<int> newChangesets = new List<int>();
foreach (var z in allChangesets.Where(y => y.ChangesetId > firstPossibleChangesetId))
{
var zz = vcs.TrackMerges(
new int[] { z.ChangesetId },
new ItemIdentifier("THE TRUNK PATH"), // The root of all branches
new ItemIdentifier[] { new ItemIdentifier(fromBranchPath), new ItemIdentifier(toBranchPath) },
null);
var targetInFromBranch = zz.Where(t => t.TargetItem.Item == fromBranchPath).FirstOrDefault();
var targetInToBranch = zz.Where(t => t.TargetItem.Item == toBranchPath).FirstOrDefault();
if (targetInToBranch != null && targetInFromBranch == null)
{
// Then the changeset is only applied on the ToBranch
newChangesets.Add(z.ChangesetId);
}
}
3) Ahora es muy sencillo obtener mi registro de cambios (la lista de elementos de trabajo) de la lista de "nuevos conjuntos de cambios":
// Now, gets associated work items!
Dictionary<int, WorkItem> dico = new Dictionary<int, WorkItem>();
foreach (int changesetId in newChangesets)
{
foreach (WorkItem zz in vcs.GetChangeset(changesetId).WorkItems)
{
this.AddWorkItemToDicRecursive(wis, dico, zz);
}
}
private void AddWorkItemToDicRecursive(WorkItemStore wis, Dictionary<int, WorkItem> dico, WorkItem workItem)
{
if (!dico.ContainsKey(workItem.Id))
{
dico.Add(workItem.Id, workItem);
foreach (WorkItemLink associatedItem in workItem.WorkItemLinks)
{
this.AddWorkItemToDicRecursive(wis, dico, wis.GetWorkItem(associatedItem.TargetId));
}
}
}
No creo que sea el mejor enfoque posible, pero funciona bien y sigue siendo simple. Además, no tuve que codificar nada (nombres de rama / jerarquía) por lo que no está tan mal IMO. Espero que ayude a alguien.
Esto sigue a mi pregunta anterior sobre TFS 2010 y la posibilidad de crear un registro de cambios.
Antes usaba etiquetas para identificar una versión del programa, pero como las etiquetas no son puntos fijos en el tiempo, ahora estoy usando sucursales.
Así es como se ve la jerarquía de ramas:
Como puede ver, hay dos aplicaciones diferentes que son ramas del troncal: APP_A
(aplicación A) y APP_B
(aplicación B). Ambos son casi idénticos, pero hay algunas diferencias funcionales.
Aquí está el proceso para crear una nueva versión de la aplicación (por ejemplo, la versión 1.3):
- El
Main trunk
se modifica (se agregan nuevas funcionalidades, correcciones de errores ...) - Desde el
Main trunk
modificado, se crea una nueva rama:Main trunk 1.3
-
APP_A
ramaAPP_A
podría modificarse, por lo que las funcionalidades únicas deAPP_A
funcionarán con la modificación de v1.3 -
APP_B
ramaAPP_B
podría modificarse, por lo que las funcionalidades únicas deAPP_B
funcionarán con la modificación de v1.3 -
Main trunk 1.3
se fusiona conAPP_A
yAPP_B
, de modo que las aplicacionesAPP_A
yAPP_B
reciben las modificaciones delMain trunk
- Desde la rama
APP_A
modificada, se crea una nueva rama:APP_A_1.3
- Desde la rama
APP_B
modificada, se crea una nueva rama:APP_B_1.3
Mi objetivo es poder generar un registro de cambios entre APP_A_1.3
y APP_A_1.2
.
Por changelog me refiero a una lista de WorkItems. Cada conjunto de cambios que está registrado está asociado con uno o más WorkItem (por ejemplo, un elemento de error). Me gustaría poder obtener la lista de todos los elementos de trabajo que se vincularon a un conjunto de cambios que ha afectado a APP_A_1.3
: estos conjuntos de cambios podrían provenir del Main trunk
(paso 1 anterior), la APP_A branch
(paso 3 anterior) o incluso la rama APP_A_1.3
sí misma (si las revisiones se registran después de que se haya creado la rama).
Para obtener esta lista de elementos de trabajo, traté de obtener la lista de todos los conjuntos de cambios que están "vinculados" a APP_A_1.2
( "vinculado" = el código que se registró en el conjunto de cambios ahora está en la rama APP_A_1.2
) y la lista de todos los conjuntos de cambios que están "vinculados" a APP_A_1.3
.
Luego, podré saber qué conjuntos de cambios están "vinculados" a APP_A_1.3
y no "vinculados" a APP_A_1.2
. De este subconjunto de conjuntos de cambios, obtendré todos los elementos de trabajo asociados y, por lo tanto, mi registro de cambios.
Aquí está mi problema: ¿cómo puedo obtener la lista de TODOS los conjuntos de cambios que están "vinculados" con una rama específica? Estoy usando la API TFS 2010 para el código C #.
La entrada de mi programa (que recuperaría todos los conjuntos de cambios para una rama específica) sería el nombre de la rama (por ejemplo, APP_A_1.2
), y la salida sería la lista de los siguientes conjuntos de cambios:
- Los conjuntos de cambios aplicados en
APP_A_1.2
ramifican - conjuntos de cambios aplicados en la rama
APP_A_1.2
antes de que se crearaAPP_A_1.2
- los conjuntos de cambios aplicados en
Main trunk 1.2
rama delMain trunk 1.2
antes de que se haya fusionado conAPP_A
- los conjuntos de cambios aplicados en
Main trunk
ramaMain trunk 1.2
antes de que se creara elMain trunk 1.2
He escrito las siguientes piezas de código para obtener todos esos conjuntos de cambios:
// Gets the list of all changesets ID from APP_A_1.2 branch
var branch1ChangeSets = myVersionControlServer.QueryHistory(
"$/PATH/APP_A_1.2/",
VersionSpec.Latest,
0,
RecursionType.Full,
null,
null,
null,
int.MaxValue,
false,
false).OfType<Changeset>().Select(z => z.ChangesetId).ToList();
Incluso si se especifica RecursionType.Full
, el código anterior solo devuelve los conjuntos de cambios que se registraron en la APP_A_1.2
rama APP_A_1.2
. Esto es idéntico al comando "Historial" en la vista del Explorador de código fuente en Visual Studio.
Entonces probé el siguiente código:
// Gets the list of all changesets ID from APP_A_1.2 branch
var branch1MergedChangeSets = myVersionControlServer.QueryMerges(
null,
null,
"$/PATH/APP_A_1.2/",
VersionSpec.Latest,
null,
null,
RecursionType.Full).Select(z => z.SourceVersion).ToList();
Esto devuelve los conjuntos de cambios que se registraron en la rama APP_A_1.2
+ aquellos que se registraron en la rama APP_A_1.2
antes de que se creara APP_A_1.2
. Mucho mejor, pero no suficiente. No puedo encontrar una manera de hacer que la recursión funcione con ramas que están "arriba" de APP_A
( Main trunk
en mi caso) ...
Alguien tiene una idea?
Además, cualquier idea mejor para obtener el registro de cambios entre dos sucursales es bienvenida ... Gracias.
Primero déjame primero hacer una pregunta. En la parte superior de la publicación, escribe: "Mi objetivo es poder generar un registro de cambios entre APP_A_1.3 y APP_A_1.2".
pero luego, cuando escribe qué cambios está buscando específicamente en su lista: los conjuntos de cambios se aplicaron en la rama APP_A_1.2. los propios conjuntos de cambios se aplicaron en la rama APP_A antes de que se crearan los conjuntos de cambios aplicados en la rama principal 1.2. en la rama del tronco principal antes de la creación del tronco principal 1.2
Esta no es una lista válida porque le proporcionará todos los cambios que contribuyeron a APP_A_1.3, APP_A_1.2, 1.1 y así sucesivamente al principio del repositorio.
No puedo probar mi enfoque en este momento, pero esto es lo que haría: - QueryHistory para que todos los cambios se registren directamente en la rama 1.3 - use QueryMergesExtended para seguir las fusiones en esta rama. QueryMergesExtended (http://msdn.microsoft.com/en-us/library/ff736485.aspx) se agregó en TFS 2010 específicamente para ser mucho más eficaz y robusto que QueryMerges y QueryMergesWithDetails, para admitir las herramientas de visualización de sucursales. no es necesario especificar la opción FollowRenames en QueryMergesExtended porque consulta las fusiones en la raíz de la rama: cuando obtiene la lista de cambios de origen (de APP_A), debe verificar que cada conjunto de cambios para ver si contiene cambios de combinación. Si es así, necesita consultar las combinaciones en app_a para esos conjuntos de cambios. Hazlo de forma recursiva hasta que entres en la jerarquía de toda la rama.
En el tema lateral, puede consultar más adelante en QueryMergeRelationships ( http://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.versioncontrol.client.versioncontrolserver.querymergerelationships.aspx ) que le presenta la lista de objetos ramificada en tfs 2010 (esto es lo que sucede cuando en Source Control Explorer selecciona la carpeta y hace clic en Convertir en rama). Sin embargo, si puede descubrir su sucursal de forma diferente (codifíquelos) de lo que no es necesario.
¡Espero que esto ayude!
Sí, trabajando en este problema yo también. Encontré un proyecto de codeplex que lo resuelve, cuando estás difiriendo las etiquetas, de todos modos.
Vea si esto ayuda: http://tfslabeldiff.codeplex.com/SourceControl/changeset/view/7075#158224
Me sorprendió lo difícil que era encontrar esto, pero en el mejor de los casos falta la documentación para TFS. ¡Parecía que debería ser obvio!