Anbu
Anbu

Reputation: 36

Controlling build task flow in Team Build 2015

Is it possible to control the flow of a build centrally in TFS2015 build vNext?

Say, I want some business tasks (custom tasks) to be executed before and after the build, but do not want user to be able to remove or change the position of these task in the build definition editor.

Or is there a way to create a build definition template to achieve the same by not exposing the tasks?

Note: I don't want to use XAML build definitions as it doesn't have new xPlat build capabilities etc.

Upvotes: 1

Views: 261

Answers (2)

jlo-gmail
jlo-gmail

Reputation: 5038

At a minimum, I think the feature described by jessehouwing should be included. I have built custom tasks to do this, I have to hope there is a plan but MS has not had enough time to fix this. Source for included tasks is available at: https://github.com/Microsoft/vsts-tasks/tree/master/Tasks

This is a good reference article: http://www.colinsalmcorner.com/post/developing-a-custom-build-vnext-task-part-1

I took the CmdLine source and modified it to include a If Condition property. I created a build variable with a default value of false, and checked off Allow at Queue Time, then placed the variable in the If Condition property of the task. I modified the powershell script:

If ($ifCondition -eq "true" -Or $ifCondition -eq "True" -Or $ifCondition -eq 1 -Or $ifCondition -eq -1)
{
    Write-Host "Creating process"
    ...
}

When I queue a build, if I change the variable to 1,-1, true or True the process executes; otherwize it does not.

task.json

{
  "id": "3A056A74-E34F-4767-8DCD-3F9461F4BCEC",<<<---BE SURE TO CHANGE THIS
  "name": "CmdLineEx",
  "friendlyName": "Command Line Ex (Conditional)",
  "description": "Run a command line with arguments",
  "helpMarkDown": "[More Information](http://go.microsoft.com/fwlink/?LinkID=613735)",
  "category": "Utility",
  "visibility": [
    "Build",
    "Release"
  ],
  "author": "Microsoft Corporation",
  "version": {
    "Major": 1,
    "Minor": 0,
    "Patch": 22
  },
  "groups": [
    {
      "name": "advanced",
      "displayName": "Advanced",
      "isExpanded": false
    }
  ],
  "inputs": [
    {
      "name": "filename",
      "type": "string",
      "label": "Tool",
      "defaultValue": "",
      "required": true,
      "helpMarkDown": "Tool name to run.  Tool should be found in your path.  Optionally, a fully qualified path can be supplied but that relies on that being present on the agent.<br/> Note: You can use **$(Build.SourcesDirectory)**\\\\ if you want the path relative to repo."
    },
    {
      "name": "arguments",
      "type": "string",
      "label": "Arguments",
      "defaultValue": "",
      "helpMarkDown": "Arguments passed to the tool",
      "required": false
    },
    {
      "name": "ifCondition",
      "type": "string",
      "label": "If Condition",
      "defaultValue": "",
      "helpMarkDown": "Performs task if this property is set (true, True, 1, -1).",
      "required": false
    },
    {
      "name": "workingFolder",
      "type": "filePath",
      "label": "Working folder",
      "defaultValue": "",
      "required": false,
      "groupName": "advanced"
    },
    {
      "name": "failOnStandardError",
      "type": "boolean",
      "label": "Fail on Standard Error",
      "defaultValue": "false",
      "required": false,
      "helpMarkDown": "If this is true, this task will fail if any errors are written to the StandardError stream.",
      "groupName": "advanced"
    }
  ],
  "instanceNameFormat": "Run $(filename)",
  "execution": {
    "Node": {
      "target": "task.js",
      "argumentFormat": ""
    },
    "PowerShell": {
      "target": "$(currentDirectory)\\task.ps1",
      "argumentFormat": "",
      "workingDirectory": "$(currentDirectory)"
    }
  },
  "messages": {
    "CmdLineReturnCode": "%s exited with return code: %d",
    "CmdLineFailed": "%s failed with error: %s"
  }
}

task.ps1

param (
    [string]$filename,
    [string]$arguments,
    [string]$ifCondition,
    [string]$workingFolder,
    [string]$failOnStandardError
)


Write-Host "filename = $filename"
Write-Host "arguments = $arguments"
Write-Host "ifCondition = $ifCondition" 
Write-Host "workingFolder = $workingFolder" 
Write-Host "failOnStandardError = $failOnStandardError" 


#########################################################################
If ($ifCondition -eq "true" -Or $ifCondition -eq "True" -Or $ifCondition -eq 1 -Or $ifCondition -eq -1)
{

    Write-Host "Creating process"

    $pinfo = New-Object System.Diagnostics.ProcessStartInfo
    $pinfo.FileName = $filename
    $pinfo.RedirectStandardError = $true
    $pinfo.RedirectStandardOutput = $true
    $pinfo.UseShellExecute = $false
    $pinfo.Arguments = $arguments


    $p = New-Object System.Diagnostics.Process
    $p.StartInfo = $pinfo
    $p.StartInfo.WorkingDirectory = $workingFolder

    Write-Host "Executing process..."
    $p.Start() | Out-Null

    $stdout = $p.StandardOutput.ReadToEnd()
    $stderr = $p.StandardError.ReadToEnd()

    $p.WaitForExit(300 * 1000)
    Write-Host "Executing process complete"


    Write-Host  $stdout
    Write-Host  -Message ("Exit code : {0}" -f $p.ExitCode) -Verbose

    if ( $p.ExitCode -eq 1)
    {
        Write-Error -Message ("Stderr : {0}" -f $stderr)
    }

}
#########################################################################

upload.bat

tfx build tasks upload --task-path ./ --overwrite
pause

Again, at a minimum, I think the feature described by jessehouwing should be included.

Upvotes: 0

jessehouwing
jessehouwing

Reputation: 114461

No this is not possible. If they are custom tasks they could set and check a variable to ensure they're running in the correct order, but that's something you'd have to implement yourself.

There is currently nothing in the build framework or agent infrastructure to enforce or partially specify a build template which can be extended only in specific places.

Nor is it possible to register something like a "finalizer" from a step earlier in the workflow.

Upvotes: 2

Related Questions