TFS 2015 build vNext update file version with commit id - tfs

Do you know how inject commit id into file version, so every assembly would heve version like 2.0.6565.0 where 6565 is related to C6565commit ID in TFS ?
It looks some power shell script is needed.

If your question is similar to your another post TFS 2015. the $(var.SourceLocation) variable is not available at gated-check in, that want to get the changeset id that hasn't checked in during gated check-in, then it's impossible in a single build.
If you don't use gated check in, then you can use $Env:BUILD_SOURCEVERSION in a powershell script to set the AssemblyVersion. Here is already a script at the website below, you can refer to it:
https://github.com/wulfland/ScriptRepository/blob/master/TFSBuild/TFSBuild/AssemblyVersion/Set-AssemblyVersion/Set-AssemblyVersion.ps1

Finally I created my own PS script based on this post.
The idea update version in all files with assembly info
$CommitId = ([string]$env:BUILD_SOURCEVERSION) -replace "[^0-9]+", ""
$AllVersionFiles = Get-ChildItem $SourceDir AssemblyInfo.cs -recurse
$regexToFindVersion = "Version\(""([0-9]+)\.([0-9]+).+"""
foreach ($file in $AllVersionFiles)
{
Write-Host "Processing " $file.FullName
(Get-Content $file.FullName) |
%{$_ -replace $regexToFindVersion, ('Version("$1.$2.0.' + $CommitId + '"') } |
Set-Content $file.FullName -Force
}
Full script can be found here.
The script must be placed before building project:

Related

Open .sln file from cmder?

Is it possible to launch devenv.exe and open a .sln file from cmder? After I clone a git repo from the command line, I'd like to quickly open the solution in Visual Studio without having to leave cmder.
Danny is correct, you simply type xxx.sln.
I'm a bit lazy and developed the script below to be able to type vs and it will find and open the first sln file it finds in the current directory.
Here are some example commands:
vs - Will open the first sln file it finds, if it doesn't find one it will just open Visual Studio without a solution. I default to opening with Visual Studio 2017. Just change the default case in the Get-VisualStudioCommand function if you'd rather default to a different version.
vs 15 - I have a bunch of versions of Visual Studio on my machine, so this will open similarly to vs, but will open with Visual Studio 2015.
vs 13 'helloWorld.sln' - this will open a specific sln file, i.e., helloWorld.sln. One of the projects I worked on recently had multiple solutions in the same directory.
vs -WhatIf -Verbose - this will show you what the script would do if it ran and will print out the Write-Verbose messages. Handy for debugging. I show and example of this in the image below.
For this solution, I'm assuming that you're using a PowerShell console. If so, you can define a .ps1 file that will run before the console opens via the -File option. It's like defining a different PowerShell profile with different commands per console window (very powerful).
See the image below where I show going to settings and modify the PowerShell:PowerShell task to execute PowerShell -NoExit -NoLogo -File C:\src\ps\Cmder\general_setup.ps1 -new_console:d:"C:\src"
Here is the image (note, although I use an alias for ls that outputs in PowerShell like a Linux ls command...this is a PowerShell console):
If you add the following script to the C:\src\ps\Cmder\general_setup.ps1 file (or wherever you want to put it)...you can then type in vs and it will execute. Notice in the Get-VisualStudioCommand function, I've put all the file paths...not the most elegant looking code, but if your file paths to devenv.exe are different than mine, just change them there.
Note, you could also get fancy and add a pass-through to the -ArgumentList or flag for the /SafeMode command to be able to open Visual Studio in safe mode when needed, I've just created these as a quick and dirty shortcut.
function Get-VisualStudioCommand
{
[CmdletBinding()]
param ( [AllowNull()][String] $vsVersion )
$vs10 = """${env:ProgramFiles(x86)}\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe"""
$vs13 = """${env:ProgramFiles(x86)}\Microsoft Visual Studio 12.0\Common7\IDE\devenv.exe"""
$vs15 = """${env:ProgramFiles(x86)}\Microsoft Visual Studio 14.0\Common7\IDE\devenv.exe"""
$vs17 = """${env:ProgramFiles(x86)}\Microsoft Visual Studio\2017\Professional\Common7\IDE\devenv.exe"""
switch ($vsVersion)
{
'10' {$vs10}
'13' {$vs13}
'15' {$vs15}
'17' {$vs17}
default {$vs17}
}
}
function Get-SolutionName
{
[CmdletBinding()]
param ( [AllowNull()][String] $Name )
if (!$Name)
{
$Name = Get-ChildItem -Filter *.sln
}
if ($Name)
{
$Name = ('"{0}"' -f $Name)
}
return $Name
}
function Start-VisualStudioProcess
{
[CmdletBinding(SupportsShouldProcess=$true)]
param([String]$Version, [String]$Sln)
$VsCommand = Get-VisualStudioCommand -vsVersion $Version
$Sln = Get-SolutionName -Name $Sln
Write-Verbose -Message ('Starting: command={0} solutionName={1}' -f $VsCommand, $Sln)
if ($PSCmdlet.ShouldProcess($VsCommand, 'Start-Process'))
{
if ($Sln)
{
Start-Process -FilePath $vsCommand -ArgumentList $sln
}
else
{
Start-Process -FilePath $vsCommand
}
}
}
Set-Alias -Name vs -Value Start-VisualStudioProcess
Let me know if you have any questions. I hope it helps.
Run this command in your prompt(cmd, cmder, etc.)
reg add "HKCU\Software\Microsoft\Command Processor" /v Autorun /d "doskey vs=for /f \"delims=\" %a IN ('dir /b *.sln') do start %a" /f
Write "vs" for open the first *.sln in folder of Solution and be happy!

Setting up Jenkins for Multiple Test Assemblies with Nunit

I have multiple Test Assemblies like Test-A.dll ,Test-B.dll ,Test-C.dll which contains Nunit test case.
My question is how to set up these Nunit Test case for these assemblies with wildcard chracter like Test-*.dll
According to this issue that is a TeamCity feature, not an NUnit one. So unless you write some custom solution you can't with Jenkins.
Edit: I got it working with the following Powershell step:
$tests = ''
Get-ChildItem -path "." -Recurse -Include "Test*.dll" | Where-Object {$_.DirectoryName -Match ".*\\bin\\Debug"} | foreach {$tests += ($_.toString() -ireplace ([regex]::Escape($env:WORKSPACE) + '\\'), ' ')}
$env:COMPLUS_Version='v4.0.30319'
Invoke-Expression "c:\PrivateWS\resources\NUnit-2.6.3\bin\nunit-console.exe $tests /result:nunit-result.xml"

Programatically delete [permenantly] a TFS work item

Whilst I'm aware that there is a command line tool to permenantly delete a TFS work item. (e.g. How to delete Work Item from Team Foundation Server)
Has anyone been able to achieve the same action programatically using the TFS 2010 API DLLs?
Shai Raiten has blogged about this here, where he makes use of DestroyWorkItems(ids).
It is advisable that you proceed with extra caution in your implementation, since this can severely mess your installation. One could argue that constructing such a tool deviates from best practices.
You can also use PowerShell to bulk delete work items:
Copy and paste below script in a PowerShell file (with .ps1
extension), update the variable values mentioned in the list #4 below
and run the command from a machine where witadmin tool is installed
(Generally available after visual studio installation). Open
PowerShell command window and execute the script.
Note: Account running below script should have team foundation administrator or collection administrator access.
########TFS Work Items Bulk Destroy Automation Script##########
#Notes:
#1) This script requires to setup file/folder path, validate the file/folders path before running the script
#2) start the powershell window as Administrator and run the script
#3) This script requires share and admin access on the destination server, make sure your account or the account under which script is
# executing is member of admin group on the destination server
#4) Update following:
# 4.1: $CollectionURL
# 4.2: $WitAdmin tool location
# For VS 2015, Default location is C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE
# For VS 2013, Default location is C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE
# 4.3: $WI_List
# 4.4: $logfile
####################
$CollectionURL = "http://tfs:8080/tfs/CollectionName"
$WitAdminLocation = "C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE"
$WI_List = Get-Content "C:\WI_List.txt"
$logfile="C:\log.txt"
$ExecutionStartTime = Get-Date
$WICount = 0
"## Starting WI Destroy # $ExecutionStartTime ##"| Out-File $logfile -Append
"Collection URL: $CollectionURL" | Out-File $logfile -Append
foreach ($WIID in $WI_List)
{
CD $WitAdminLocation
.\witadmin destroywi /collection:$CollectionURL /id:$WIID /noprompt
"WI ID: $WIID Destroyed" | Out-File $logfile -Append
$WICount = $WICount + 1
Write-Host "$WICount Work Items Deleted"
}
$ExecutionEndTime = Get-Date
"## WI Destroy Command Completed # $ExecutionEndTime ##"| Out-File $logfile -Append
$TotalExecutionTime = $ExecutionEndTime - $ExecutionStartTime
"Total Work Items Deleted: $WICount" | Out-File $logfile -Append
" Total Execution Time: $TotalExecutionTime" | Out-File $logfile -Append
##End of script##

How can I bulk rename files using PowerShell?

I'm trying to recursively rename a bunch of TFS folders using tf rename, PowerShell and a regular expression but I'm having some issues with PowerShell as I haven't spent much time with it. This is what I've put together so far to replace a leading 5 with 2.3.2 but it isn't working:
dir | foreach { tf rename $_ { $_.Name -replace '^5', '2.3.2' } }
Actual result:
Unrecognized command option 'encodedCommand'.
Unrecognized command option 'encodedCommand'.
Unrecognized command option 'encodedCommand'.
Unrecognized command option 'encodedCommand'.
...etc.
Update:
I got a little closer by doing the following instead:
dir | foreach { $newname = $_.Name -replace "^5", "2.3.2"; tf rename $_ $newname }
My next goal is to make this recurse subdirectories but this seems a bit more challenging (changing it to dir -recurse makes it quit after the parent folders for some reason).
I would first filter by 5* so you only process names that start with 5. Also, in this case since tf.exe isn't a PowerShell cmdlet, you don't want to use a scriptblock to determine a new name. Just use a grouping expression like so:
dir -filter 5* | foreach { tf rename $_ ($_.Name -replace '^5', '2.3.2')}
BTW, when you are trying to debug parameter passing to a native EXE like this it is immensely helpful to use the echoargs.exe utilty from the PowerShell Community Extensions. This is what it told me about your original approach:
6# dir -filter 5* | foreach { echoargs rename $_ { $_.Name -replace '^5', '2.3.2' } }
Arg 0 is <rename>
Arg 1 is <5foo.txt>
Arg 2 is <-encodedCommand>
Arg 3 is <IAAkAF8ALgBOAGEAbQBlACAALQByAGUAcABsAGEAYwBlACAAJwBeADUAJwAsACAAJwAyAC4AMwAuADIAJwAgAA==>
Arg 4 is <-inputFormat>
Arg 5 is <xml>
Arg 6 is <-outputFormat>
Arg 7 is <text>
Notes:
TFS has native cmdlets -- no need for tf.exe in most cases.
The time complexity of workspace operations depends on the number of pending renames already in the workspace. In TFS 2005/2008 it's significantly worse than linear. Bottom line, you should really consider batching up renames into multiple checkins if you have a large # of items, otherwise every single "tf rename" (or New-TfsPendingChange -Rename if using the cmdlets) will start taking minutes.
Try this:
dir . | foreach { $newname = $_.Name -replace "^5", "2.3.2"; tf rename $_ $newname }
Running the above commands requires the tf.exe to have been aliased as 'tf'.. or it did on my machine at least.
Run this command:
Set-Alias tf "C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer\tf.exe"
Update the path to tf.exe as appropriate
Also consider adding the line to your profile for future use
notepad $PROFILE

How can I use PowerShell to update build qualities on previous TFS Builds?

We are using TFSDeployer to listen to build quality changes and deploy to our staging environment when it transitions to "Staging".
I'd like to have it go ahead and update all of the other builds that have a currently build quality of "Staging" to be "Rejected".
This appears to be something that needs to happen inside the PowerShell script which looks like:
$droplocation = $TfsDeployerBuildData.DropLocation
ECHO $droplocation
$websourcepath = $droplocation + "\Release\_PublishedWebsites\CS.Public.WebApplication\"
$webdestinationpath = "\\vmwebstg\WebRoot\CreditSolutions\"
new-item -force -path $webdestinationpath -itemtype "directory"
get-childitem $webdestinationpath | remove-item -force -recurse
get-childitem $websourcepath | copy-item -force -recurse -destination $webdestinationpath
$configFile = $webdestinationpath + "web.development.config"
remove-item $configFile -force
$configFile = $webdestinationpath + "web.staging.config"
$configFileDest = $webdestinationpath + "web.config"
move-item $configFile $configFileDest -force
So, how can I do this?
First add the Get-tfs function to your script:
function get-tfs (
[string] $serverName = $(Throw 'serverName is required')
)
{
# load the required dll
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.Client")
$propertiesToAdd = (
('VCS', 'Microsoft.TeamFoundation.VersionControl.Client', 'Microsoft.TeamFoundation.VersionControl.Client.VersionControlServer'),
('WIT', 'Microsoft.TeamFoundation.WorkItemTracking.Client', 'Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore'),
('BS', 'Microsoft.TeamFoundation.Build.Common', 'Microsoft.TeamFoundation.Build.Proxy.BuildStore'),
('CSS', 'Microsoft.TeamFoundation', 'Microsoft.TeamFoundation.Server.ICommonStructureService'),
('GSS', 'Microsoft.TeamFoundation', 'Microsoft.TeamFoundation.Server.IGroupSecurityService')
)
# fetch the TFS instance, but add some useful properties to make life easier
# Make sure to "promote" it to a psobject now to make later modification easier
[psobject] $tfs = [Microsoft.TeamFoundation.Client.TeamFoundationServerFactory]::GetServer($serverName)
foreach ($entry in $propertiesToAdd) {
$scriptBlock = '
[System.Reflection.Assembly]::LoadWithPartialName("{0}") > $null
$this.GetService([{1}])
' -f $entry[1],$entry[2]
$tfs | add-member scriptproperty $entry[0] $ExecutionContext.InvokeCommand.NewScriptBlock($scriptBlock)
}
return $tfs
}
Next, instantiate the TFS object
$tfs = get-tfs http://YourTfsServer:8080
Then find the builds with a build quality of "Staging"
$builds = $tfs.BS.GetListOfBuilds("Test Project", "TestBuild") |
where {$_.BuildQuality -eq "Staging"}
Finally, update the quality of these builds
foreach ($build in $builds) { $tfs.BS.UpdateBuildQuality($build.BuildUri, "Rejected") }
(I haven't run this script yet, but you should be able to get it going without troubles)
More info on my blog: Using the Team Foundation Object Model with PowerShell
One last advice, if you update the Build quality from within the script that is running from TfsDeployer, you could end up with 2 script running at the same time if you have a mapping for the Staging --> Rejected transition!
This is not the full answer as I don't have much knowledge of TFSDeployer or indeed PowerScript. However the .NET API for Team Build is able to do this. You want to get hold of the IBuildDetail for the build. The easiest way to get this is if you have the BuildUri (which it sounds like you might) in which case a call to IBuildServer.GetBuild should get you the build you are interested in.
IBuildServer also has the QueryBuilds methods which you would be able to call to find the builds that are of interest to you, you would then set the Quality property on the IBuildDetails that you wanted to change, remembering to call the Save() method on each one.
Hope that gives you a start - sorry it isn't a more complete answer.

Resources