TFS 2010 API:队列同步构建并获取每个排队构建的状态:“在代理上运行(等待构建代理)”

时间:2012-02-16 09:52:41

标签: c# tfs tfs2010 build-agent

是否可以同步排队?

我试过这样的事情:

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上运行)。我想等待每个子构建过程,以便在子构建过程失败时我可以中止主构建过程。

有什么想法吗?

更新

  

服务'XXX - Agent1'有一个例外:异常消息:   操作未在指定的超时00:00:30内完成。   分配给此操作的时间可能是a的一部分   更长的超时。 (输入FaultException`1)

     

异常堆栈跟踪:at   Microsoft.TeamFoundation.Build.Machine.BuildAgentService.TerminateWorkflow(TerminatingException   前)

工作流程:

enter image description here

2 个答案:

答案 0 :(得分:1)

由于您只拥有一个额外的构建代理,我认为使用这样一个复杂的模块并不会给您带来太大的影响。

我将实施两个独立的活动:
一个活动将新构建排队后,将BuildDetailBuildDefinition作为输出作为输出。
我将在XAML的循环内调用此活动。这将对构建代理#2中的所有构建进行排队。

第二项活动将检查构建代理#2&amp;的状态。等待代理再次变为空闲。
一旦这样做,我将检查应该在Agent#2中成功运行的每个构建定义,例如:if(buildDefinition.LastGoodBuildUri != buildDefinition.LastBuildUri) <这种方法看起来有点不利,事实上构建不会在第一次打破“子”构建时失败/停止。
在我看来,这实际上是一个优势:如果不止一个失败,你马上就会知道。

答案 1 :(得分:1)

我创建了一个特殊的模板,用于按顺序启动构建。基本模板:

获取构建,QueueBuild,MonitorBuild

获取构建是默认模板中的活动。它是我模板中的第一个活动,只在开始时调用一次。

QueueBuild 是在codeplex从TFSExtensions获取的活动。我创建了一个包含IQueueBuild对象的变量,该对象是我计划开始的每个构建的QueueBuild活动的结果。我将Result设置为此变量。我打电话给我的是CurrentQueueBuild。在每个QueueBuild活动启动构建之后,此变量将由活动更新到当前构建队列。

MonitorBuild 是我制作的大部分“同步”的序列:

首先是一个检查CurrentQueueBuild是否为null的活动(CurrentQueueBuild Is Nothing)。如果是,我抛出一个例外,因为我不能拥有它。

其次是While活动(称为'while building')。它的条件是'CurrentQueueBuild.Status = BuildStatus.InProgress'。在While的主体中,我有另一个包含InvokeMethod活动的序列(TargetObject = CurrentQueueBuild,MethodName = Refresh,我添加了QueryOptions类型的In参数设置为QueryOptions.All)。我按照InvokeMethod设置延迟活动设置为等待5秒。

最后,我写了一条构建消息来记录状态。这显然是可选的。

总而言之,我开始了5个版本,每个版本我都有 QueueBuild 活动,然后按照上面的说明将 Monitor Build 活动放在一起。

希望这有助于某人。