How to clone code from multiple sources in TFS 2017? - tfs

My code is in TFS repository but due to some reason few files are in Sharepoint/MS Teams, how can we clone code from both the sources in the build definition.
Get Sources task is the default which clones the specified TFS repository, is there a way to add or edit this task to clone code from Sharepoint at the same time.

You cannot edit the Get Sources task to clone code from sharepoint.
However, you can use a powershell task to download the files from the sharepoint.
For example, add a powershell task in your pipeline to run below inline scripts:
Using WebClient
$SharePointFile = "https://the.server/path/to/the/file.txt"
$Path = "$(Build.SourcesDirectory)\file.txt"
#User Information
$Username = "userName"
$Password = "password"
#Download Files
$client = New-Object System.Net.WebClient
$client.Credentials = New-Object System.Net.Networkcredential($UserName, $Password)
$client.DownloadFile($SharePoint, $Path)
$client.Dispose()
Using Invoke-WebRequest
$User = "userName"
$PWord = ConvertTo-SecureString -String "password" -AsPlainText -Force
$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User, $PWord
$url = 'https://the.server/path/to/the/file.txt'
$outfile = "$(Build.SourcesDirectory)\file.txt"
Invoke-WebRequest -Uri $url -OutFile $outfile -Credential $Credential
Above script will download the file from your sharepoint server to the source code folder $(Build.SourcesDirectory) on the agent machine (ie. c:\agent_work\1\s)
You can also use SharePoint Pnp PowerShell Framework to download the files in powershell task. See example in this blog.

Related

Declarative Jenkins with WithCredentials and Powershell

stage('Deployment') {
steps {
withCredentials([string(credentialsId: 'Test', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD')]) {
powershell '$pass = ConvertTo-SecureString -AsPlainText "${PASSWORD}" -Force'
powershell '$SecureString = "${pass}"'
powershell '$MySecureCreds = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList "${USERNAME}","${SecureString}"'
powershell 'New-PSSession -ComputerName 192.123.123.123 -Credential "${MySecureCreds}"'
}
powershell 'Copy-Item "${ARTIFACT_PATH}" -Destination "${DESTINATION_PATH}" -ToSession -Recurse -Force'
powershell 'Start-Process "iisreset.exe" -NoNewWindow -Wait'
powershell 'Remove-Website -Name WebCareRecord'
powershell 'Remove-WebAppPool WebCareRecord'
powershell 'Get-WebBinding -Port 85 -Name WebCareRecord | Remove-WebBinding'
powershell 'Start-Process "iisreset.exe" -NoNewWindow -Wait'
powershell 'New-WebAppPool -Name WebCareRecord'
powershell 'Set-ItemProperty "${POOL_PATH}" managedPipelineMode 0'
powershell 'Set-ItemProperty "${POOL_PATH}" managedRuntimeVersion ""'
powershell 'New-WebSite -Name WebCareRecord -Port 85 -PhysicalPath "${PHYSICAL_PATH}" -ApplicationPool WebCareRecord'
powershell 'Start-Process "iisreset.exe" -NoNewWindow -Wait'
}
}
I am trying to get the Jenkins credentials ID, secure it and use the same credentials to login into the remote server. After login to the remote server, copy the artifact from jenkins server to remote server. For this I am getting error
org.jenkinsci.plugins.credentialsbinding.impl.CredentialNotFoundException: Credentials 'Test' is of type 'Username with password' where 'org.jenkinsci.plugins.plaincredentials.StringCredentials' was expected.
There might be multiple problems, I've going through similar process now and feeling the pain to get it correctly in powershell within groovy, so this is what I've noticed so far:
You are creating a $pass variable in one powershell step, and then trying to access it in another powershell step, I don't think it will work that way, as another step might launch in different powershell session and that powershell variable is no longer there.?
I would try something like this:
stage('Deployment') {
steps {
withCredentials([string(credentialsId: 'Test', usernameVariable: 'USERNAME', passwordVariable: 'PASSWORD')]) {
powershell """
\$pass = ConvertTo-SecureString -AsPlainText $PASSWORD -Force
\$SecureString = \$pass
"""
}
}
}
So first of all you use multiline syntax """ so the different powershell statements are in the same session, and those variables are available across powershell commands.
Second, you escape powershell variables \$pass and \$SecureString, so groovy does not try to expand them, and you don't escape variables where you are actually referring to groovy variables like $PASSWORD.
Note that $PASSWORD does not have to be in quotes, since powershell parameters can accept strings without quotes, but if this was used in a method you should put it into quotes SomePowershellMethod("$GROOVYVAR").
In general I suggest to echo every variable while troubleshooting, to see if you are getting what you are expecting.
I like short and precise answer.
Use following :
stage('Deployment') {
steps {
withCredentials([usernamePassword(credentialsId: 'UatServer', passwordVariable: 'passVar', usernameVariable: 'userVar')]) {
powershell '''
$passVar = ConvertTo-SecureString "$($ENV:passVar)" -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential ("$ENV:userVar", $passVar)
$session = New-PSSession -ComputerName x.x.x.x -Credential $credential
Invoke-Command -Session $session -ScriptBlock {hostname}
'''
}
}
}

How to access variables relating to a TFS commit in build definition

I'm using the "Post to Slack" task as one of my build steps in TFS 2018 and I'm wondering how to access variables relating to that commit. I would like to include them as part of the Message field (something like "Commit: $(CommitMessage) link to changeset $(ChangesetLink)" but those variables don't exist). Here is where I need to reference the variables in TFS:
This document: link describes how to access build variables but it doesn't mention anything relating to the commit. I would like to access the commit message, associated commit changesets and the link to the changeset(s) associated with the commit. Does anyone know how to do this or know where I can find documentation for it? Thank you
Cruiser is right, no such Predefined variables in TFS, you can retrieve the needed information by REST API, then set corresponding variables using the Logging Commands.
Create a PowerShell script to set the avariables (Reference below
sample, you can also Use the OAuth token to access the REST API), then commit and push the script into TFS.
Add a PowerShell task before the "Post to Slack" task in your
definition to run the PS script
Use the variables $(commitID), $(CommitMessage) and
$(commitUrl) in "Post to Slack" task
Note: For Git it's commit, For TFVC it's changeset
You can use below script to set the variables:
Param(
[string]$collectionurl = "http://server:8080/tfs/DefaultCollection",
[string]$repoid = "389e8215-1fb2-4fdc-bd04-ebc8a8a4410e",
[string]$user = "username",
[string]$token = "password"
)
# Base64-encodes the Personal Access Token (PAT) appropriately
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))
$searchCriteria = "$" + "top=1"
$baseUrl = "$collectionurl/_apis/git/repositories/$repoid/commits?$searchCriteria"
$response = (Invoke-RestMethod -Uri $baseUrl -Method Get -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)})
#Retrieve values
$commitID = $response.value.commitID
$CommitMessage = $response.value.comment
$commitUrl = $response.value.remoteUrl
#Set variables
Write-Host "##vso[task.setvariable variable=commitID]$commitID"
Write-Host "##vso[task.setvariable variable=CommitMessage]$CommitMessage"
Write-Host "##vso[task.setvariable variable=commitUrl]$commitUrl"
UPDATE:
You can use this REST API to get the repository ID:
GET http://server:8080/tfs/DefaultCollection/{ProjectName}/_apis/git/repositories

tfsbuild delete/destroy - founds no builds for build specification

There are 100s of builds left in our build definition indefinitely, regardless of the retention settings: i want to delete builds with scripts, i am trying run from remote PC. our tfs server is 2015.2.
tfsbuild destroy /collection:http://tfsserver:8080/tfs/ProjectCollection /dateRange:01/01/2017~31/12/2017 /buildDefinition:teamProject\Builddefintion
output shows: No builds found for build specification. even though there are many builds meets the criteria. any help is appreciated. Thanks!
Tfsbuild delete/destroy only availabe for Xaml builds. And need to delete first then destroy.
For vNext builds, you can try to delete them with the REST API (Delete a build):
DELETE http://server:8080/tfs/DefaultCollection/ProjectName/_apis/build/builds/{build Id}?api-version=2.0
You can use below PowerShell script to delete all the builds which compeleted in the year 2017 for the specific build definiiton:
Param(
[string]$collectionurl = "http://server:8080/tfs/Collection",
[string]$projectName = "ProjectName",
[string]$builddefinitionID = "56",
[string]$keepForever = "true",
[string]$user = "username",
[string]$token = "password"
)
# Base64-encodes the Personal Access Token (PAT) appropriately
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $user,$token)))
#Get builds list which completed in the year 2017
$buildsUrl = "$($collectionurl)/$projectName/_apis/build/builds?definitions=$builddefinitionID&statusFilter=completed&api-version=2.0"
$builds = (Invoke-RestMethod -Uri $buildsUrl -Method Get -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)}).value | where({$_.finishTime -like '*2017*'})
#Delete the builds
foreach ($build in $builds.id)
{
$deleteurl = "$($collectionurl)/$projectName/_apis/build/builds/$build"+"?api-version=2.0"
$result = (Invoke-RestMethod -Uri $deleteurl -Method Delete -Headers #{Authorization=("Basic {0}" -f $base64AuthInfo)})
Write-Host "Builds deleted with the ID" : $build
}

Promote build with Jenkins API

Given a Jenkins build job with different promotion jobs (i.e., that promote builds to different environments), how can one trigger a specific promotion job for a specific build using the Jenkins API?
Combined answers from different sources to come up with this:
$Username = "Username"
$APItoken = '12345'
$Credential = "$($Username):$($APItoken)"
$EncodedCredential = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($Credential))
$BasicAuthValue = "Basic $EncodedCredential"
$Headers = #{
Authorization = $BasicAuthValue
}
Write-Output "Promoting build $LatestBuildNumber to Environment..."
Invoke-WebRequest -URI "http://jenkins.prd.company.com/job/jobname/buildnumber/promotion/forcePromotion?name=PromoteToEnvironment" -Headers $Headers
I know this is an old thread, but just to help the community.
Shell Solution using CURL:
user_name="jenkins_user"
user_token="token"
promotion_name="Test_Promote"
jenkins_url="http://build-server.com"
JOB_NAME="job_name"
JOB_NO="job-no"
url="--silent -u $user_name:$user_token $jenkins_url/job/$JOB_NAME/$JOB_NO/promotion/forcePromotion?name=$promotion_name"
curl $url
How to generate jenkins user token: https://jenkins.io/blog/2018/07/02/new-api-token-system/

VStest code coverage report in jenkins

I am setting CI for .Net project using Jenkins.
I used MSTest Plugin and VStestrunner plugin to run test.
Now I have .trx file and .Coverage file
I am facing problem in displaying code coverage report
Please help me is you know any plugin to do this.
I have struggled this for a long time, finally I found we can use "CodeCoverage.exe" "ReportGenarator.exe" and "Cobertura plugin" to show perfect coverage report.
"ReportGenarator.exe" can be get from https://github.com/danielpalme/ReportGenerator/releases
first use "CodeCoverage.exe" translate .coverage file to .xml file
"C:\Program Files (x86)\Microsoft Visual Studio 14.0\Team Tools\Dynamic Code Coverage Tools\CodeCoverage.exe" analyze -output:./TestResults/coverage.xml ./TestResults/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.coverage"
second use ReportGenarator.exe translate vstest xml format to Cobertura xml format
"ReportGenerator_4.4.7\net47\ReportGenerator.exe" -reports:./TestResults/coverage.xml -targetdir:./TestResults -reporttypes:cobertura
finally install cobertura plugin use it to collect xml file, here give a pipeline useage example
post {
always {
cobertura coberturaReportFile: './TestResults/Cobertura.xml'
}
}
the result just like this
To display the coverage report you need to convert it in XML format and use MSTest Plugin to publish the report. MSTest Plugin recommends (https://wiki.jenkins-ci.org/display/JENKINS/MSTest+Plugin) to use third party application to convert in XML format and powershell (you will need to install pugin for it) to run it.
However you can convert it with PowerShell only. There is example of script:
$coverageFile = $(get-ChildItem -Path .\TestResults -Recurse -Include *coverage)[0]
$xmlCoverageFile = ".\TestResults\vstest.coveragexml"
Add-Type -path "C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\PrivateAssemblies\Microsoft.VisualStudio.Coverage.Analysis.dll"
[string[]] $executablePaths = #($coverageFile)
[string[]] $symbolPaths = #()
$info = [Microsoft.VisualStudio.Coverage.Analysis.CoverageInfo]::CreateFromFile($coverageFile, $executablePaths, $symbolPaths);
$data = $info.BuildDataSet()
$data.WriteXml($xmlCoverageFile)
You maybe will need to fix the path to Microsoft.VisualStudio.Coverage.Analysis.dll according to your VS version.
Following ghking's answer, cobertura complains that the xml is not found although it's on the disk. I have to remove './' from the path, so that cobertura is able to find the file.
post {
always {
cobertura coberturaReportFile: 'TestResults/Cobertura.xml'
}
}
The complete script to do this is:
<#
.SYNOPSIS
Script to convert code coverage report into xml format that can then be published by external tools.
.DESCRIPTION
Covering code coverage statistics as part of quality improvement initiatives.
#>
Param(
[String] $InputCoveragePath =#("..\GeneratedFiles\Docs\Reports"),
[String] $OutputCoverageFileExtension =#(".coveragexml"),
[String] $CoverageAnalysisAssembly =#("Microsoft.VisualStudio.Coverage.Analysis.dll"),
[String[]] $ExecutablePaths =#(""),
[String[]] $SymbolPaths =#("")
)
$ScriptLocation = Split-Path $script:MyInvocation.MyCommand.Path -Parent
Write-Host $ScriptLocation
$RunAs32Bit = {
Param(
[String] $InputCoveragePath =#("..\GeneratedFiles\Docs\Reports"),
[String] $OutputCoverageFileExtension =#(".coveragexml"),
[String] $CoverageAnalysisAssembly =#("Microsoft.VisualStudio.Coverage.Analysis.dll"),
[String[]] $ExecutablePaths =#(""),
[String[]] $SymbolPaths =#(""),
[String] $ScriptLocation =#(".")
)
Write-Host "[CoverageConverter][Begin]: Coverage conversion started..."
Write-Host "[CoverageConverter][InputCoveragePath]: $InputCoveragePath"
Write-Host "[CoverageConverter][OutputCoverageFileExtension]: $OutputCoverageFileExtension"
Write-Host "[CoverageConverter][CoverageAnalysisAssembly]: $CoverageAnalysisAssembly"
Write-Host "[CoverageConverter][ExecutablePaths]: $ExecutablePaths"
Write-Host "[CoverageConverter][SymbolPaths]: $SymbolPaths"
Write-Host "[CoverageConverter][ScriptLocation]: $ScriptLocation"
Add-Type -path "$CoverageAnalysisAssembly"
$Result = 0
if($InputCoveragePath -and (Test-Path "$InputCoveragePath") )
{
[string[]] $coverageFiles = $(Get-ChildItem -Path $InputCoveragePath -Recurse -Include *coverage)
#($coverageFiles) | ForEach-Object {
$coverageFile = $_
$coverageFileOut = (Join-Path -Path $(Split-Path $_ -Parent) -ChildPath ($(Get-Item $_).BaseName + "$OutputCoverageFileExtension"))
Write-Host "If all OK the xml will be written to: $coverageFileOut"
$info = [Microsoft.VisualStudio.Coverage.Analysis.CoverageInfo]::CreateFromFile($coverageFile, $ExecutablePaths, $SymbolPaths);
if($info){
$data = $info.BuildDataSet()
$data.WriteXml($coverageFileOut)
}
}
}
else
{
Write-Host "Please specify a valid input coverage file."
$Result = 1
}
Write-Host "[CoverageConverter][End]: Coverage conversion completed with result $Result"
return $Result
}
#Run the code in 32bit mode if PowerShell isn't already running in 32bit mode
If($env:PROCESSOR_ARCHITECTURE -ne "x86"){
Write-Warning "Non-32bit architecture detected, processing original request in separate 32bit process."
$Job = Start-Job $RunAs32Bit -RunAs32 -ArgumentList ($InputCoveragePath, $OutputCoverageFileExtension, $CoverageAnalysisAssembly, $ExecutablePaths, $SymbolPaths, $ScriptLocation)
$Result = $Job | Wait-Job | Receive-Job
}Else{
$Result = Invoke-Command -ScriptBlock $RunAs32Bit -ArgumentList ($InputCoveragePath, $OutputCoverageFileExtension, $CoverageAnalysisAssembly, $ExecutablePaths, $SymbolPaths, $ScriptLocation)
}

Resources