2012-02-16 8 views
5

Czy można kolejkować kompilacje synchronicznie?TFS 2010 API: Kolejka buduje się synchronicznie i pobiera stan każdej budowanej w kolejce kompilacji: "Uruchom na agencie (oczekiwanie na agenta budowania)"

Próbowałem coś takiego:

CodeActivity:

[BuildActivity(HostEnvironmentOption.Agent)] 
public sealed class QueueNewBuild : CodeActivity<BuildResult> 
{ 
    // The Team Project that the build definition belongs to. 
    [RequiredArgument] 
    public InArgument<IBuildDetail> BuildDetail { get; set; } 

    // The build definition to queue 
    [RequiredArgument] 
    public InArgument<String> BuildDefinition { get; set; } 

    protected override BuildResult Execute(CodeActivityContext context) 
    { 
     // Obtain the runtime value of the input arguments 
     var buildDefinitionName = context.GetValue(BuildDefinition); 
     var buildDetail = context.GetValue(BuildDetail); 

     // Obtain the Team Project for the current build definition. 
     var tfsProject = buildDetail.BuildDefinition.TeamProject; 

     var configurationServerUri = buildDetail.BuildServer.TeamProjectCollection.Uri.ToString(); 

     var server = new TfsTeamProjectCollection(new Uri(configurationServerUri)); 
     server.EnsureAuthenticated(); 
     var buildServer = server.GetService<IBuildServer>(); 
     var buildDefinition = buildServer.GetBuildDefinition(tfsProject, buildDefinitionName); 

     var queuedBuild = buildServer.QueueBuild(buildDefinition); 

     var buildStatusWatcher = new BuildStatusWatcher(queuedBuild.Id); 
     buildStatusWatcher.Connect(buildServer, tfsProject); 

     do 
     { 
     } while (buildStatusWatcher.Status != QueueStatus.Completed && buildStatusWatcher.Status != QueueStatus.Canceled); 

     buildStatusWatcher.Disconnect(); 

     return new BuildResult 
     { 
      WasSuccessfully = buildStatusWatcher.Build.CompilationStatus == BuildPhaseStatus.Succeeded, 
      BuildDetail = buildStatusWatcher.Build 
     }; 
    } 
} 

BuildResult:

public class BuildResult 
{ 
    public bool WasSuccessfully { get; set; } 
    public IBuildDetail BuildDetail { get; set; } 
} 

BuildStatusWatcher:

public class BuildStatusWatcher 
{ 
    private IQueuedBuildsView _queuedBuildsView; 
    private readonly int _queueBuildId; 
    private QueueStatus _status; 
    private IBuildDetail _build; 

    public BuildStatusWatcher(int queueBuildId) 
    { 
     _queueBuildId = queueBuildId; 
    } 

    public IBuildDetail Build 
    { 
     get { return _build; } 
    } 

    public QueueStatus Status 
    { 
     get { return _status; } 
    } 

    public void Connect(IBuildServer buildServer, string tfsProject) 
    { 
     _queuedBuildsView = buildServer.CreateQueuedBuildsView(tfsProject); 
     _queuedBuildsView.StatusChanged += QueuedBuildsViewStatusChanged; 
     _queuedBuildsView.Connect(10000, null); 
    } 

    public void Disconnect() 
    { 
     _queuedBuildsView.Disconnect(); 
    } 

    private void QueuedBuildsViewStatusChanged(object sender, StatusChangedEventArgs e) 
    { 
     if (e.Changed) 
     { 
      var queuedBuild = _queuedBuildsView.QueuedBuilds.FirstOrDefault(x => x.Id == _queueBuildId); 
      if (queuedBuild != null) 
      { 
       _status = queuedBuild.Status; 
       _build = queuedBuild.Build; 
      } 
     } 
    } 
} 

Próbuję więc czekać tak długo, jak kompilacja jest ukończona lub anulowana, ale to nie działa, ponieważ agent budowy sub-kompilacji czeka cały czas.

Mam jeden proces budowania wzorca (działa na agencie 1), który wywołuje 13 proces kompilacji podrzędnej (wszystkie działają na agencie 2). I chcę poczekać na każdy proces kompilacji podrzędnej, abym mógł przerwać proces budowania nadrzędnego, gdy proces podrzędny kompiluje się.

Wszelkie pomysły?

UPDATE:

Service 'XXX - Agent1' miał wyjątek: Komunikat wyjątku: Operacja nie ukończyć w wyznaczonym timeout 00:00:30. Czas przydzielony na tę operację mógł być częścią dłuższego limitu czasu wynoszącego . (Typ FaultException`1)

Wyjątek Śledzenie stosu: w Microsoft.TeamFoundation.Build.Machine.BuildAgentService.TerminateWorkflow (TerminatingException ex)

Workflow:

enter image description here

+1

A więc, mówisz, że WSZYSTKO, w której programowo żądana kompilacja się nie uruchamia? Lub, że nie możesz zamówić wielu Buildów? – pantelif

+1

Powoduje zawieszenie się podczas pierwszej kolejki sub-kompilacji. "Uruchom na agencie (oczekiwanie na agenta kompilacji) Agent budujący kompilację podrzędną ma stan:" Wykonanie przepływu pracy "Stan kompilacji agenta dla głównej kompilacji to:" Gotowy " – Rookian

+1

Uznałem, że agent nie Agent budowania "zawiesza się" sporadycznie .. – Rookian

Odpowiedz

1

Ponieważ wszystko, co masz, jest jednym dodatkowym agentem, myślę, że nie przyniesie Ci to zbyt wiele do zastosowania takiego złożonego modułu.

Wdrażałbym dwie oddzielne czynności:
Jedna czynność, która przyjmuje jako dane wejściowe BuildDetail i BuildDefinition jako wyjście, gdy nowa kolejka zostanie umieszczona w kolejce.
Chciałbym wywołać tę aktywność w pętli w XAML. Spowoduje to umieszczenie w kolejce wszystkich kompilacji w agencie kompilacji nr 2.

Drugie działanie będzie sprawdzać stan agenta kompilacji # 2 & czekać, aż agent ponownie stanie się bezczynny.
Po wykonaniu tej czynności sprawdziłbym każdą definicję kompilacji, która powinna działać poprawnie w Agent # 2, z czymś podobnym:
if(buildDefinition.LastGoodBuildUri != buildDefinition.LastBuildUri)

To, co może wydawać się wadą tego podejścia, to fakt, że kompilacja NIE zawiedzie/zatrzymaj się przy pierwszych łamiących się kompilacjach "potomnych".
Moim zdaniem, jest to w rzeczywistości zaleta: jeśli więcej niż jedna się nie powiedzie, natychmiast się zorientujesz.

+0

Znalazłem problem .. Błędny agent kompilacji został wybrany przez moją główną kompilację, ale nie wiem, dlaczego tak się dzieje, ponieważ skonfigurowałem definicję głównej konstrukcji do użycia konkretnego agenta – Rookian

1

Stworzyłem specjalny szablon do otwierania kompilacji w kolejności. Podstawowy szablon:

Pobierz build, QueueBuild, MonitorBuild

Get Build jest działalnością, która znajduje się w domyślnym szablonie. Jest to pierwsze działanie w moim szablonie i jest wywoływane tylko raz na początku.

KolejkaBuild to aktywność uzyskana z TFSExtensions w codeplex. Tworzę zmienną przechowującą obiekt IQueueBuild będący wynikiem działania QueueBuild dla każdej kompilacji, którą planuję uruchomić. Ustawiłem Wynik dla tej zmiennej. Nazwałem mój CurrentQueueBuild. Po każdym działaniu QueueBuild rozpoczyna się kompilacja, zmienna ta jest aktualizowana do bieżącej kolejki kompilacji o działanie.

MonitorBuild jest sekwencją, że zrobiłem to robi większość 'synchronizacji':

Pierwszy to działalność, która sprawdza, czy CurrentQueueBuild jest null (CurrentQueueBuild Is Nothing). Jeśli to jest, wyrzucam wyjątek, ponieważ nie mogę tego mieć.

Drugie działanie typu "While" (zwane "While building"). Jego stan to "CurrentQueueBuild.Status = BuildStatus.InProgress". W treści The While Mam kolejną sekwencję zawierającą aktywność InvokeMethod (TargetObject = CurrentQueueBuild, MethodName = Refresh i dodałem parametr parametru QueryOptions do QueryOptions.All). Postępuję zgodnie z InvokeMethod z aktywnością opóźnienia ustawioną na oczekiwanie 5 sekund.

Wreszcie piszę komunikat kompilacji, aby zarejestrować status. To oczywiście jest opcjonalne.

Tak, aby zakończyć, mam 5 buduje ja skopać i dla każdego z nich mam aktywność QueueBuild następnie przez Monitorze Budowanie aktywność umieścić razem, jak opisano powyżej.

Mam nadzieję, że to komuś pomaga.

+1

Jak to NIE jest zaakceptowaną odpowiedzią? To było bardzo proste rozwiązanie tego, co może być nieprzyjemnym problemem. – JohnZaj

Powiązane problemy