Skip to content

Instantly share code, notes, and snippets.

@digitaldelirium
Created August 2, 2016 21:53
Show Gist options
  • Save digitaldelirium/af098a2384ff29f48c04087105491576 to your computer and use it in GitHub Desktop.
Save digitaldelirium/af098a2384ff29f48c04087105491576 to your computer and use it in GitHub Desktop.
Windows TFS Ansible Module
#!powershell
#
#
# Author: Ian Cornett
# Version: 0.1
# Version History:
#
# Purpose: Queue TFS Build from Ansible and return workable JSON dictionary for polling
#
#
# WANT_JSON
# POWERSHELL_COMMON
[PSObject]$params = Parse-Args -arguments $args
[PSObject]$result = New-Object -TypeName PSObject -ArgumentList @{
win_tfs_url = New-Object -TypeName PSObject
response = $null
changed = $false
log = $null
}
[Uri]$tfsUri = ''
#setup TFS Connection Properties
$url = Get-AnsibleParam -obj $params -name 'url' -failifempty $true
$skip_certificate_validation = Get-AnsibleParam -name 'skip_certificate_validation' -default $false
$skip_certificate_validation = $skip_certificate_validation | ConvertTo-Bool
# setup TFS build properties
$collectionName = Get-AnsibleParam -obj $params -name 'collection' -failifempty $false
$projectName = Get-AnsibleParam -obj $params -name 'project' -failifempty $true
$buildDef = Get-AnsibleParam -obj $params -name 'buildId' -failifempty $true
# setup authtentication if needed
$username = Get-AnsibleParam -obj $params -name 'username' -failifempty $false
$password = Get-AnsibleParam -obj $params -name 'password' -failifempty $false
# setup proxy if needed
$proxy_url = Get-AnsibleParam -obj $params -name 'proxy_url' -failifempty $false
$proxy_user = Get-AnsibleParam -obj $params -name 'proxy_user' -failifempty $false
$proxy_pass = Get-AnsibleParam -obj $params -name 'proxy_pass' -failifempty $false
if($skip_certificate_validation)
{
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {
$true
}
}
[PSObject]$requestBody = @{
definition = @{
id = $buildDef
}
reason = 'Manual'
priority = 'Normal'
}
# Kick off TFS Build using REST
function Invoke-TfsBuild
{
param
(
[Object]
[Parameter(Mandatory = $true)]
$url,
[Object]
[Parameter(Mandatory = $true)]
$projectName,
[Object]
[Parameter(Mandatory = $true)]
$result,
[Object]
[Parameter(Mandatory = $true)]
$requestBody,
[Object]
$username,
[Object]
$password,
[Object]
$collectionName,
[Object]
$proxy_url,
[Object]
$proxy_user,
[Object]
$proxy_pass
)
# Logging Passed Parameters
$results.log += "Entered Invoke-TfsBuild`r`n"
$results.log += "Passed Parameters:`nUrl:`t$($url.ToString())`nCollection:`t$($collectionName.ToString())`n Project:`t$($projectName.ToString())`n"
$results.log += "User:`t$($username.ToString())`nProxy Url:`t$($proxy_url.ToString())`nProxy User:`t$($proxy_user.ToString())`nRequest Params:`t$($requestBody.ToString())"
[Object]$proxyCreds = $null
[Object]$tfsCreds = $null
[Object]$response = $null
# Create HashTable variable to store request params
[hashtable]$requestParams = [ordered]@{
Method = 'Post'
ContentType = 'application/json'
}
# If collectionName is null, set to DefaultCollection
if(-not $collectionName)
{
$collectionName = 'DefaultCollection'
}
#Build up TFS URI
$tfsUri = "$($url.toString())/$($collectionName.ToString())/$($projectName.ToString())/_apis/build/builds?api-version=2.0"
$result.win_tfs_url = $tfsUri
# Set up request parameters to be passed to TFS
try
{
# Content
$requestParams.Add('Uri', $tfsUri.ToString())
# Check to see if we're using a proxy, if so set up any necessary creds. Do the same for user/pass for TFS
if ($proxy_url)
{
$requestParams.Add('Proxy', $proxy_url)
if ($proxy_user -and $proxy_pass)
{
# Cast password to Secure String
$sec_proxy_pass = $proxy_pass | ConvertTo-SecureString -AsPlainText -Force
# Instantiate proxyCreds
$proxyCreds = New-Object -TypeName PSCredential -ArgumentList ($proxy_user, $sec_proxy_pass)
$requestParams.Add('ProxyCredential', $proxyCreds)
}
}
if ($username -and $password)
{
#Create secure string for creating PSCredential object
$sec_password = $password | ConvertTo-SecureString -Force -AsPlainText
$tfsCreds = New-Object -TypeName PSCredential -ArgumentList ($username, $sec_password)
$requestParams.Add('Credential', $tfsCreds)
}
else
{
$requestParams.Add('UseDefaultCredential', $true)
}
$requestParams.Add('Body', $($requestBody | ConvertTo-Json))
$result.Add('Args',$requestParams)
$result.log += "Build Request Parameters:`n$($requestParams.ToString())"
}
catch
{
Fail-Json -obj $result -message "Error occurred while setting up request parameters! `r`nArgs: $($result.Args)"
}
# Attempt TFS Build
try
{
$request.log += "Requesting Build...`r`n"
# Queue TFS Build
$result.response = Invoke-RestMethod @requestParams
$result.changed = $false
$result.log += "Build Successfully Submitted`n`r"
}
catch
{
Fail-Json -obj $result -message "Error queueing build at: $($tfsUri.ToString()) `nUsing TFS Credential: $($username.ToString())"
}
}
# Monitor Build Progress
function Get-TfsBuildStatus
{
param
(
[Object]
[Parameter(Mandatory = $true)]
$url,
[Object]
$username,
[Object]
$password,
[Object]
$collectionName,
[Object]
[Parameter(Mandatory = $true)]
$projectName,
[Object]
$proxy_url,
[Object]
$proxy_user,
[Object]
$proxy_pass,
[Object]
[Parameter(Mandatory = $true)]
$result
)
$results.log += "Entered Get-TfsBuildStatus`r`n"
$results.log += "Passed Parameters:`nUrl:`t$($url.ToString())`nCollection:`t$($collectionName.ToString())`n Project:`t$($projectName.ToString())`n"
$results.log += "User:`t$($username.ToString())`nProxy Url:`t$($proxy_url.ToString())`nProxy User:`t$($proxy_user.ToString())`nRequest Params:`t$($requestBody.ToString())"
#Create BuildId, BuildNumber, and ReleaseName hashtable for easy recall
[hashtable]$buildInfo = @{
Id = $result.response.id
buildNumber = $result.response.buildNumber
releaseName = $result.response.definition.name
buildState = $null
buildResult = $null
}
# Build URI for Monitoring Build status and create buildStatus response object
[Uri]$buildUri = "$($url.toString())/$($collectionName.ToString())/$($projectName.ToString())/_apis/build/builds/$($buildId.ToString())/timeline?api-version=2.0"
[Object]$buildStatus = New-Object PSObject
# Create Hashtable for passing parameters as necessary
[Hashtable]$requestParams = @{}
$requestParams.Add('Method','Get')
$requestParams.Add('ContentType','application/json')
# If collectionName is null, set to DefaultCollection
if(-not $collectionName)
{
$collectionName = 'DefaultCollection'
}
$requestParams.Add('Uri', $buildUri.ToString())
# Check to see if we're using a proxy, if so set up any necessary creds. Do the same for user/pass for TFS
if ($proxy_url)
{
$requestParams.Add('Proxy', $proxy_url)
if ($proxy_user -and $proxy_pass)
{
# Cast password to Secure String
$sec_proxy_pass = $proxy_pass | ConvertTo-SecureString -AsPlainText -Force
# Instantiate proxyCreds
$proxyCreds = New-Object -TypeName PSCredential -ArgumentList ($proxy_user, $sec_proxy_pass)
$requestParams.Add('ProxyCredential', $proxyCreds)
}
}
if ($username -and $password)
{
#Create secure string for creating PSCredential object
$sec_password = $password | ConvertTo-SecureString -Force -AsPlainText
$tfsCreds = New-Object -TypeName PSCredential -ArgumentList ($username, $sec_password)
$requestParams.Add('Credential', $tfsCreds)
}
else
{
$requestParams.Add('UseDefaultCredential', $true)
}
# Get Build Status with REST Call
try
{
$buildStatus = Invoke-RestMethod @requestParams
# Loop through REST calls
while ($buildStatus.records.state -ne 'completed')
{
# Call REST method until state is completed, Sleep 10 seconds between calls
Start-Sleep -Seconds 10
$buildStatus = Invoke-RestMethod @requestParams
}
$buildInfo.buildResult = $buildStatus.records[0].result
$buildInfo.buildState = $buildStatus.records[0].state
}
catch
{
$result.changed = $false
Fail-Json -obj $result -message "Error while trying to monitor build status $($_.Exception.Message) `r`n$($_.Exception.StackTrace)"
}
finally
{
# Add Build Information to result, to allow for recall
$result.Add('build_info',$buildInfo)
if ($buildInfo.buildResult -eq 'succeeded')
{
$result.changed = $true
}
else
{
$result.changed = $false
# Iterate through results object looking for failed and details
$failedTask = $buildStatus.records |
Where-Object {
$_.result -ne 'succeeded'
} |
Select-Object -Property name, result, resultCode, details
Fail-Json -obj $result -message "TFS Build process failed! `nTask Name: $($failedTask.name) `nTask Result: $($failedTask.result) Result Code: $($failedTask.resultCode) `nDetails: $($failedTask.details)"
}
}
Exit-Json -obj $result
}
# Kick off the TFS Build and Monitor Progress
try
{
# Load buildParams with required params for execution
[hashtable]$buildParams = @{
url = $url
projectName = $projectName
result = $result
requestBody = $requestBody
}
# Build Request optional Params
# Proxy Support
if ($proxy_url)
{
$buildParams.Add('proxy_url',$proxy_url)
if ($proxy_user -and $proxy_pass)
{
$buildParams.Add('proxy_user',$proxy_user)
$buildParams.Add('proxy_pass',$proxy_pass)
}
}
if ($collectionName)
{
$buildParams.Add('collectionName',$collectionName)
}
if ($username -and $password)
{
$buildParams.Add('username',$username)
$buildParams.Add('password',$password)
}
# Kick off build
$results.log += "`tQueueing Build`v`r`n"
Invoke-TfsBuild @buildParams
$results.log += "Build Successfully Queued`n"
}
catch
{
Fail-Json -obj $result -message "Error when attempting to invoke TFS build $($result.log.ToString()) `n$($_.Exception.Message)`r`n$($_.Exception.StackTrace)"
}
try
{
# Get TFS Build Status
Get-TfsBuildStatus -url $url -collectionName $collectionName -projectName $projectName -username $username -password $password -result $result -proxy_url $proxy_url -proxy_user $proxy_user -proxy_pass $proxy_pass
}
catch
{
Fail-Json -obj $result -message "Error trying to monitor build status! Last known build state: $($result.build_info.buildState)`r`n$($_.Exception.StackTrace)"
}
Exit-Json -obj $result
#!/usr/bin/python
# -*- coding: utf-8 -*-
DOCUMENTATION = '''
---
module: win_tfsbuild
version_added: "0.1"
short_description: Queue TFS Build via REST
description:
- The M(win_tfsbuild) module queues a build for TFS or Visual Studio Online builds via POST to REST endpoint.
options:
url:
description:
- The root URI of the TFS/VSO instance. In case of connecting to Visual Studio Online, the CollectionName
variable needs to be left blank to use the DefaultCollection. eg: http://tfs.yourdomain.com:8080/tfs or
https://<youraccount>.visualstudio.com.
required: true
default: null
username:
description:
- If authentication is required, the username required to authenticate.
required: false
default: null
password:
description:
- If username is provided, the password required to authenticate.
required: false
default: null
collection:
description:
- If your TFS instance is an On Prem instance, you need to specify a Collection name that will be hosting your
project. In an enterprise situation, you may have multiple collections.
required: false
default: null
project:
description:
- Enter the name of your TFS/VSO project which you wish to build.
required: true
default: null
buildId:
description:
- The id number of the build definition that you're trying to invoke
required: true
default: null
proxy_url:
description:
- Proxy URL to connect to external path, if required.
required: false
default: null
proxy_user:
description:
- User name to authenticate to the proxy, if required.
required: false
default: null
proxy_pass:
description:
- Password required to authenticate to the proxy, if required.
required: false
default: null
skip_certificate_validation:
description:
- Boolean value to skip validating the certificate in cases of self-signed certificate.
required: false
default: false
author: "Ian Cornett (@iancornett)"
'''
EXAMPLES = '''
# Queue a build
- win_tfsbuild: url=https://foo.visualstudio.com [email protected] password=myPassword project=MyProject buildId=123
'''
RETURN = '''
win_tfs_url:
description:
- The URI of the initial build request
returned: success
build_info:
description:
- The resulting information from the build request
response:
description:
- The response of the initial build request
'''
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment