简体   繁体   中英

Check a file into TFS using Powershell

As part of my continuous integration build I am creating an SQL script. This SQL script has to be checked back in to TFS after it is generated. I'm using the TFS Powertools in Powershell.

The code I used on my machine was:

Add-TfsPendingChange -Add -Item $filename | New-TfsChangeSet

This worked fine on my dev box because the folder I was in is mapped to a TFS workspace. When I move it to my build server it no longer works because TeamCity doens't map it's checkouts to a workspace it just pulls the files down.

How do I check files into a specific folder in TFS without being in a mapped workspace? Is that even possible?

I worked on something to do this for our continuous delivery project using GO. I got it working using a combination of PowerShell and the .NET assemblies provider with Team Explorer. I could not get it working purely in PowerShell (although there may be a way!)

The following script will check-in whatever is contained in the material path which is supplied as a parameter into the specified server path (also a parameter). You can also specify credentials to use and a url for the TFS server.

This code requires either Visual Studio or the TFS Team Explorer client to be installed. You need to provide the directory location of the assemblies to the script in the AssemblyPath parameter. If these assemblies are not found then the script will error and show which ones are missing.

NOTE: The code has not been checked for a while so there may be typos etc. If you have any problems let me know and I will try to help.

[CmdletBinding(PositionalBinding=$false)]
Param(
    [Parameter(Mandatory)] [string] $ServerUrl,
    [Parameter(Mandatory)] [string] $ServerPath,
    [Parameter(Mandatory=$False)] [string] $Domain = "",
    [Parameter(Mandatory=$False)] [string] $Username = "",
    [Parameter(Mandatory=$False)] [System.Security.SecureString] $Password,
    [Parameter(Mandatory)] [string] [ValidateScript({($_ -eq $null) -or (Test-Path -Path $_ -PathType Container)})] $MaterialPath,
    [Parameter(Mandatory)] [string] [ValidateScript({ Test-Path -Path $_ -PathType Container})] $AssemblyPath
)

<#
    .SYNOPSIS
    Responsible for checking in files into Source Control
    .DESCRIPTION
#>

$clientDllName = "Microsoft.TeamFoundation.Client.dll"
$commonDllName = "Microsoft.TeamFoundation.Common.dll"
$versionControlClientDllName = "Microsoft.TeamFoundation.VersionControl.Client.dll"
$versionControlClientCommonDllName = "Microsoft.TeamFoundation.VersionControl.Common.dll"


#Create global variables to hold the value of Debug and Verbose action preferences which can then be used for all module function calls and passed into the remote session.
$verboseParameter = $PSCmdlet.MyInvocation.BoundParameters["Verbose"]
if ($verboseParameter -ne $null)
{
    $Global:Verbose = [bool]$verboseParameter.IsPresent
}
else
{
    $Global:Verbose = $false
}
$debugParameter = $PSCmdlet.MyInvocation.BoundParameters["Debug"]
if ($debugParameter -ne $null)
{
    $Global:Debug = [bool]$debugParameter.IsPresent
}
else
{
    $Global:Debug = $false
}

$scriptName = $(Split-Path -Leaf $PSCommandPath)

#Ensure any errors cause failure
$ErrorActionPreference = "Stop"

Write-Host "Running script ""$scriptName"" as user ""$env:USERDOMAIN\$env:USERNAME"""

#Check assembly path is a valid directory
If (Test-Path -Path $AssemblyPath -PathType Container)
{
    Write-Host "Loading required assemblies from assembly path ""$AssemblyPath"""

    $clientDllPath = Join-Path -Path $AssemblyPath -ChildPath $clientDllName
    $commonDllPath = Join-Path -Path $AssemblyPath -ChildPath $commonDllName
    $versionControlClientDllPath = Join-Path -Path $AssemblyPath -ChildPath $versionControlClientDllName
    $versionControlClientCommonDllPath = Join-Path -Path $AssemblyPath -ChildPath $versionControlClientCommonDllName

    If (!Test-Path -Path $clientDllPath -PathType Leaf)
    {
        Throw "Required assembly ""$clientDllName"" not found at path ""$clientDllPath"""
    }
    If (!Test-Path -Path $commonDllPath -PathType Leaf)
    {
        Throw "Required assembly ""$commonDllName"" not found at path ""$commonDllPath"""
    }
    If (!Test-Path -Path $versionControlClientDllPath -PathType Leaf)
    {
        Throw "Required assembly ""$versionControlClientDllName"" not found at path ""$versionControlClientDllPath"""
    }
    If (!Test-Path -Path $versionControlClientCommonDllPath -PathType Leaf)
    {
        Throw "Required assembly ""$versionControlClientCommonDllName"" not found at path ""$versionControlClientCommonDllPath"""
    }

    #Load the Assemblies
    [Reflection.Assembly]::LoadFrom($clientDllPath) | Out-Null
    [Reflection.Assembly]::LoadFrom($commonDllPath)| Out-Null
    [Reflection.Assembly]::LoadFrom($versionControlClientDllPath) | Out-Null
    [Reflection.Assembly]::LoadFrom($versionControlClientCommonDllPath) | Out-Null

    #If the credentials have been specified then create a credential object otherwise we will use the default ones
    If ($Username -and $Password)
    {

        $creds = New-Object System.Net.NetworkCredential($Username,$Password,$Domain)
        Write-Host "Created credential object for user ""$($creds.UserName)"" in domain ""$($creds.Domain)"""

        $tfsProjectCollection = New-Object Microsoft.TeamFoundation.Client.TFSTeamProjectCollection($ServerUrl, $creds)
    }
    else
    {
        Write-Host "Using default credentials for user ""$Env:Username"""
        $tfsProjectCollection = New-Object Microsoft.TeamFoundation.Client.TFSTeamProjectCollection($ServerUrl)
    }

    $versionControlType = [Microsoft.TeamFoundation.VersionControl.Client.VersionControlServer]
    $versionControlServer = $tfsProjectCollection.GetService($versionControlType)

    Write-Host "Version control server authenticated user: $($versionControlServer.AuthenticatedUser)"

    #Create a local path in the temp directory to hold the workspace
    $LocalPath = Join-Path -Path $env:TEMP -ChildPath $([System.Guid]::NewGuid().ToString())
    $null = New-Item -Path $LocalPath -ItemType Directory

    #Create a "workspace" and map a local folder to a TFS location
    $workspaceName = "PowerShell Workspace_{0}" -f [System.Guid]::NewGuid().ToString()
    $workspace = $versionControlServer.CreateWorkspace($workspaceName, $versionControlServer.AuthenticatedUser)
    $workingfolder = New-Object Microsoft.TeamFoundation.VersionControl.Client.WorkingFolder($ServerPath,$LocalPath)
    $result = $workspace.CreateMapping($workingFolder)
    $result = $workspace.Get() #Get the latest version into the workspace

    Write-Host "Copying files from materials path ""$MaterialPath"" to temporary workspace path ""$LocalPath"""
    robocopy $MaterialPath $LocalPath /s | Out-Null

    $checkInComments = "Files automatically checked in by PowerShell script ""$scriptName"""

    #Submit file as a Pending Change and submit the change
    $result = $workspace.PendAdd($LocalPath,$true)
    $pendingChanges = $workspace.GetPendingChanges()

    Write-Host "Getting pending changes"

    #Only try to check in if there are changes
    If ($pendingChanges -ne $null)
    {
        If ($pendingChanges.Count -gt 0)
        {
            $changeSetId = $workspace.CheckIn($pendingChanges,$checkInComments)

            Write-Host "Successfully checked in ""$($pendingChanges.Count)"" changes using changeset id ""$changeSetId"""
        }
        else
        {
            Write-Host "No changes to check-in"
        }
    }
    else
    {
        Write-Host "No changes to check-in"
    }

    Write-Host "Deleting workspace and temporary folders"
    $result = $workspace.Delete()
    $null = Remove-Item -Path $LocalPath -Recurse -Force
}
else
{
    Write-Error "The path to required assemblies ""$AssemblyPath"" cannot be found"
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM