Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can a Gated check-in be triggered programmatically?

I am getting errors using the Workspace.Checkin command in TFS because the files I am trying to check in are part of a Gated build definition. There are lots of people asking how to override a gated check-in using the TFS API. But a very different question is this: what if I actually want to perform the gated check-in, programmatically? How can I trigger this in TFS API?

What I want to do is:

  1. Perform a normal check-in operation of a set of pending changes
  2. Receive information about the gated build that was launched
  3. Either subscribe to a completion event for that build, or poll the build until it is complete.
  4. Continue if the build was successful, and changes were committed (get the resulting changeset if possible)
  5. Stop if the build was not successful, and report the error.

I could not find anything out there to answer this question; perhaps it is such an edge case that I'm the only one crazy enough to want to do this. That said, my need for this is legitimate. The only thing I can figure is that I would need to go through the lower-level functions of the gated check-in process: 1) Walk through the build definitions to see if the path of any of the files coincide with any of the paths in any of the gated builds. 2) If an intersection exists, create a shelveset of the pending changes 3) Queue a new build of the gated definition using the shelveset 4) Query the build definition and refresh the information until the build status is completed 5) If the build was successful, unshelve the pending changes, and then check-in using an override.

However, note that even if I do these steps, the resulting build won't look like a gated build at all. Policy override notifications will be sent, and the only way of letting someone know that a build was actually performed would be to include such information in the policy override comments. Is there a more direct way to do this that would make it look like any other gated build?

like image 763
paulyphonic Avatar asked Dec 16 '22 00:12

paulyphonic


2 Answers

Prompted by the post by Scordo I was able to figure out how to do this. Here is the code:

//Initialize connection to server
TfsTeamProjectCollection tpc = new TfsTeamProjectCollection(new Uri(ServerAddress));
try
{
    tpc.EnsureAuthenticated();
}
catch (Exception e)
{
    System.Environment.Exit(-1);
}
VersionControlServer vcServer = tpc.GetService<VersionControlServer>();
IBuildServer buildServer = tpc.GetService<IBuildServer>();

//.
//.
//Program logic goes here...
//.
//.

//Get the workspace and the respective changes
Workspace workspace = vcServer.TryGetWorkspace(LocalProjectPath);  
PendingChange[] changes = workspace.GetPendingChanges();  

//Perform the check-in
bool checkedIn = false;

//Either wait for the gated check-in or continue asynchronously...  
bool waitForGatedCheckin = true;  

//Attempt a normal check-in
try
{
    //First, see what policy failures exist, and override them if necessary
    CheckinEvaluationResult result = workspace.EvaluateCheckin(CheckinEvaluationOptions.All, 
    changes, changes, "Test", null, null);

    //Perform the check-in, with overrides if necessary, including Work Item policies
    //or include additional code to comply with those policies
    PolicyOverrideInfo override = null;
    if (result.PolicyFailures != null)
    {
        override = new PolicyOverrideInfo("override reason", result.PolicyFailures);
    }
    workspace.CheckIn(changes, comment, null, null, override);
    checkedIn = true;
}
catch (GatedCheckinException gatedException)
{
    //This exception tells us that a gated check-in is required.
    //First, we get the list of build definitions affected by the check-in
    ICollection<KeyValuePair<string, Uri>> buildDefs = gatedException.AffectedBuildDefinitions;

    if (buildDefs.Count == 1)
    {
        //If only one affected build definition exists, then we have everything we need to proceed
        IEnumerator<KeyValuePair<string, Uri>> buildEnum = buildDefs.GetEnumerator();
        buildEnum.MoveNext();
        KeyValuePair<string, Uri> buildDef = buildEnum.Current;
        String gatedBuildDefName = buildDef.Key;
        Uri gatedBuildDefUri = buildDef.Value;
        string shelvesetSpecName = gatedException.ShelvesetName;
        string[] shelvesetTokens = shelvesetSpecName.Split(new char[] { ';' });

        //Create a build request for the gated check-in build
        IBuildRequest buildRequest = buildServer.CreateBuildRequest(gatedBuildDefUri);  
        buildRequest.ShelvesetName = shelvesetTokens[0]; //Specify the name of the existing shelveset
        buildRequest.Reason = BuildReason.CheckInShelveset; //Check-in the shelveset if successful 
        buildRequest.GatedCheckInTicket = gatedException.CheckInTicket; //Associate the check-in

        //Queue the build request
        IQueuedBuild queuedBuild = buildServer.QueueBuild(buildRequest);

        //Wait for the build to complete, or continue asynchronously
        if (waitForGatedCheckin)
        {
            while (!queuedBuild.Build.BuildFinished)
            {
                //Get the latest status of the build, and pause to yield CPU
                queuedBuild.Refresh(QueryOptions.Process);  
                System.Threading.Thread.Sleep(1000)
            }
            if (queuedBuild.Build.Status == BuildStatus.Succeeded)
            {
                checkedIn = true;
            }
        }
    }
    else
    {
        //Determine a method for specifying the appropriate build definition
        //if multiple build definitions are affected
    }
}
catch (CheckinException checkinException)
{
    //Handle other checkin exceptions such as those occurring with locked files, 
    //permissions issues, etc.
}

if (checkedIn)
{
    //Additional logic here, if the check-in was successful
}
like image 102
paulyphonic Avatar answered Dec 28 '22 08:12

paulyphonic


I never did it before but this should help you a bit:

When you checkin changes using the workspace and this checkin is protected by a gated build, a GatedCheckinException is thrown. This Exceptions should have all the necessary information to create a shelveset and to trigger the correct build(s) with that shelveset. For Example the AffectedBuildDefinitions property should contain the builddefinitions which are gated build defnitions.

Hope that helps.

like image 35
Scordo Avatar answered Dec 28 '22 09:12

Scordo