2012-02-16 55 views
5

是否可以同步排隊構建?TFS 2010 API:隊列同步構建並獲取每個排隊構建的狀態:「在代理上運行(等待構建代理)」

我想是這樣的:

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; 
      } 
     } 
    } 
} 

所以我試圖等待只要構建完成或取消,但這不起作用,因爲子構建的構建代理正在等待整個時間。

我有一個主構建過程(在代理1上運行),它調用13個子構建過程(全部在代理2上運行)。我想等待每個子構建過程,以便在子構建過程失敗時放棄主構建過程。

任何想法?

UPDATE:

服務 'XXX - 劑1' 有一個例外:異常消息: 操作沒有的00:00:30在規定的超時時間內完成。 分配給此操作的時間可能是 較長超時的一部分。 (類型FaultException`1)

異常堆棧跟蹤:在 Microsoft.TeamFoundation.Build.Machine.BuildAgentService.TerminateWorkflow(TerminatingException EX)

的工作流程:

enter image description here

+1

所以,你說所有你的程序要求構建失敗開始?或者你不能訂購多個版本? – pantelif 2012-02-16 11:01:21

+1

它掛在第一個排隊的子版本上。 「Run On Agent(正在等待構建代理)。子構建的構建代理具有狀態:」執行工作流程「。主構建的構建代理狀態爲:」準備就緒「 – Rookian 2012-02-16 11:35:57

+1

我發現代理沒有編譯代理「掛起」零星 – Rookian 2012-02-17 09:10:33

回答

1

由於您擁有的只是一個額外的構建代理,因此我認爲它並不能爲您帶來如此複雜的模塊。

我將執行兩個單獨的活動:
一個活動將輸入BuildDetailBuildDefinition作爲退出,一旦新的構建已經排隊。
我會在XAML的一個循環內調用這個活動。這會將構建代理#2中的所有構建排隊。

第二項活動將檢查構建代理#2的狀態&等待代理再次變爲空閒狀態。
一旦這樣做了,我會檢查應該在代理#2中成功運行的每個構建定義,如下所示:
if(buildDefinition.LastGoodBuildUri != buildDefinition.LastBuildUri)

這種方法看起來有什麼缺點,是構建不會失敗/停止在第一次打破「孩子」構建。
在我看來,這實際上是一個優勢:如果不止一個失敗,你會立即知道。

+0

我確實發現了這個問題,我的主版本選擇了錯誤的構建代理,但我不知道爲什麼會這樣,因爲我設置了主構建定義來使用一個特定的代理 – Rookian 2012-02-20 13:34:00

1

我創建了一個特殊的模板來開始構建。基本的模板:

獲取構建,QueueBuild,MonitorBuild

獲取生成是在默認模板的活動。這是我模板中的第一個活動,並且在開始時只調用一次。

QueueBuild是從codeplex的TFSExtensions獲得的活動。我創建了一個變量,它包含一個IQueueBuild對象,該對象是我計劃啓動的每個構建的QueueBuild活動的結果。我將Result設置爲這個變量。我叫我的CurrentQueueBuild。在每個QueueBuild活動啓動構建之後,該活動將該變量更新爲當前構建隊列。

MonitorBuild是我做的,做了大部分「同步」的序列:

首先是檢查活動,如果CurrentQueueBuild爲空(CurrentQueueBuild爲Nothing)。如果是我拋出一個例外,因爲我不能這樣做。

其次是一個雖然活動(稱爲'建設')。它的條件是'CurrentQueueBuild.Status = BuildStatus.InProgress'。在While的正文中,我有另一個包含InvokeMethod活動的序列(TargetObject = CurrentQueueBuild,MethodName = Refresh,並且我添加了QueryOptions類型的參數設置爲QueryOptions.All)。我遵循InvokeMethod並將延遲活動設置爲等待5秒鐘。

最後,我寫了一個構建消息來記錄狀態。這顯然是可選的。

所以包裹起來,我有5個構建我揭開序幕,併爲每一個我有一個QueueBuild活動後跟一個監視器建立活動如上所述放在一起。

希望這可以幫助別人。

+1

這不是被接受的答案嗎?這是一個非常簡單的解決方案,可能是一個令人討厭的問題。 – JohnZaj 2014-06-19 15:00:18

相關問題