Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TFS 2010 API: Queue builds synchronously and get the state of each queued build: "Run On Agent (waiting for build agent)"

Is it possible to queue builds synchronously?

I tried something like this:

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

So I am trying to wait as long as the build is completed or canceled, but this does not work, because the build agent of the sub build is waiting the whole time.

I have one master build process (runs on agent 1) which invokes 13 sub build process (all run on agent 2). And I want to wait for each sub build process so that I can abort the master build process when a sub build process fails.

Any ideas?

UPDATE:

Service 'XXX - Agent1' had an exception: Exception Message: The operation did not complete within the allotted timeout of 00:00:30. The time allotted to this operation may have been a portion of a longer timeout. (type FaultException`1)

Exception Stack Trace: at Microsoft.TeamFoundation.Build.Machine.BuildAgentService.TerminateWorkflow(TerminatingException ex)

The workflow:

enter image description here

like image 862
Rookian Avatar asked Nov 04 '22 05:11

Rookian


1 Answers

Since all you have is one additional Build Agent, I think it doesn't bring you much to employ such a complex module.

I would implement two separate Activities:
One Activity that takes as input a BuildDetail and a BuildDefinition as exits once a new build has been queued.
I would invoke this activity within a loop in the XAML. This would queue all builds in build agent #2.

The second activity would check on the Status of build agent #2 & wait the agent to become idle again.
Once it does so, I would check for each build definition that is supposed to have ran successfully in Agent #2 with something like that:
if(buildDefinition.LastGoodBuildUri != buildDefinition.LastBuildUri)

What might seem as a disadvantage with this approach, is fact that build will NOT fail/stop at the very first breaking "child" builds.
In my opinion, that is actually an advantage: If more than one fails, you 'll know immediately.

like image 114
pantelif Avatar answered Nov 15 '22 13:11

pantelif