This commit is contained in:
gauravsaralms 2021-05-25 15:16:07 +05:30 коммит произвёл GitHub
Родитель 9047988069
Коммит a05f29915a
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
36 изменённых файлов: 3268 добавлений и 0 удалений

14
BuildTasks/README.md Normal file
Просмотреть файл

@ -0,0 +1,14 @@
# DevOps Automation Tools
These build steps will help you to automate Azure DevOps work which you need to do repeatedly.
Published at : https://marketplace.visualstudio.com/items?itemName=devopsCli.devopsAutomation
## Stale Work Item Build Task
Add this build task into a build definition and trigger it periodically to mark work items with {ProAct: Stale} tag after N days (configurable) of inactivity.
Add it to the build like this:
![image.png](images/StaleWorkItemImage1.png)
Make sure to put PAT token in a secure variable in Build:
![image.png](images/StaleWorkItemImage2.png)

Двоичные данные
BuildTasks/icons/extension-icon.PNG Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 3.2 KiB

Двоичные данные
BuildTasks/images/StaleWorkItemImage1.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 70 KiB

Двоичные данные
BuildTasks/images/StaleWorkItemImage2.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 38 KiB

Двоичные данные
BuildTasks/images/extension-icon.PNG Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 3.2 KiB

Двоичные данные
BuildTasks/markWorkItemAsStale/.gitignore поставляемый Normal file

Двоичный файл не отображается.

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Двоичные данные
BuildTasks/markWorkItemAsStale/markWorkItemAsStale.ps1 Normal file

Двоичный файл не отображается.

85
BuildTasks/markWorkItemAsStale/package-lock.json сгенерированный Normal file
Просмотреть файл

@ -0,0 +1,85 @@
{
"name": "devopsautomation",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@types/node": {
"version": "12.0.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.0.0.tgz",
"integrity": "sha512-Jrb/x3HT4PTJp6a4avhmJCDEVrPdqLfl3e8GGMbpkGGdwAV5UGlIs4vVEfsHHfylZVOKZWpOqmqFH8CbfOZ6kg==",
"dev": true
},
"@types/q": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.2.tgz",
"integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw==",
"dev": true
},
"azure-pipelines-task-lib": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/azure-pipelines-task-lib/-/azure-pipelines-task-lib-2.8.0.tgz",
"integrity": "sha512-PR8oap9z2j+o455W3PwAfB4SX1p4GdJc9OHQaQV0V+iQS1IBY6dVgcNSQMkHAXb0V1bbuLOFBLanXPe5eSgGTQ==",
"requires": {
"minimatch": "3.0.4",
"mockery": "1.7.0",
"q": "1.5.1",
"semver": "5.7.0",
"shelljs": "0.3.0",
"uuid": "3.3.2"
}
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"requires": {
"balanced-match": "1.0.0",
"concat-map": "0.0.1"
}
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"requires": {
"brace-expansion": "1.1.11"
}
},
"mockery": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/mockery/-/mockery-1.7.0.tgz",
"integrity": "sha1-9O3g2HUMHJcnwnLqLGBiniyaHE8="
},
"q": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
"integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc="
},
"semver": {
"version": "5.7.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
"integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA=="
},
"shelljs": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz",
"integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E="
},
"uuid": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
"integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA=="
}
}
}

Просмотреть файл

@ -0,0 +1,18 @@
{
"name": "devopsautomation",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"azure-pipelines-task-lib": "^2.8.0"
},
"devDependencies": {
"@types/node": "^12.0.0",
"@types/q": "^1.5.2"
}
}

Просмотреть файл

@ -0,0 +1,292 @@
<#
.SYNOPSIS
Finds files or directories.
.DESCRIPTION
Finds files or directories using advanced pattern matching.
.PARAMETER LiteralDirectory
Directory to search.
.PARAMETER LegacyPattern
Proprietary pattern format. The LiteralDirectory parameter is used to root any unrooted patterns.
Separate multiple patterns using ";". Escape actual ";" in the path by using ";;".
"?" indicates a wildcard that represents any single character within a path segment.
"*" indicates a wildcard that represents zero or more characters within a path segment.
"**" as the entire path segment indicates a recursive search.
"**" within a path segment indicates a recursive intersegment wildcard.
"+:" (can be omitted) indicates an include pattern.
"-:" indicates an exclude pattern.
The result is from the command is a union of all the matches from the include patterns, minus the matches from the exclude patterns.
.PARAMETER IncludeFiles
Indicates whether to include files in the results.
If neither IncludeFiles or IncludeDirectories is set, then IncludeFiles is assumed.
.PARAMETER IncludeDirectories
Indicates whether to include directories in the results.
If neither IncludeFiles or IncludeDirectories is set, then IncludeFiles is assumed.
.PARAMETER Force
Indicates whether to include hidden items.
.EXAMPLE
Find-VstsFiles -LegacyPattern "C:\Directory\Is?Match.txt"
Given:
C:\Directory\Is1Match.txt
C:\Directory\Is2Match.txt
C:\Directory\IsNotMatch.txt
Returns:
C:\Directory\Is1Match.txt
C:\Directory\Is2Match.txt
.EXAMPLE
Find-VstsFiles -LegacyPattern "C:\Directory\Is*Match.txt"
Given:
C:\Directory\IsOneMatch.txt
C:\Directory\IsTwoMatch.txt
C:\Directory\NonMatch.txt
Returns:
C:\Directory\IsOneMatch.txt
C:\Directory\IsTwoMatch.txt
.EXAMPLE
Find-VstsFiles -LegacyPattern "C:\Directory\**\Match.txt"
Given:
C:\Directory\Match.txt
C:\Directory\NotAMatch.txt
C:\Directory\SubDir\Match.txt
C:\Directory\SubDir\SubSubDir\Match.txt
Returns:
C:\Directory\Match.txt
C:\Directory\SubDir\Match.txt
C:\Directory\SubDir\SubSubDir\Match.txt
.EXAMPLE
Find-VstsFiles -LegacyPattern "C:\Directory\**"
Given:
C:\Directory\One.txt
C:\Directory\SubDir\Two.txt
C:\Directory\SubDir\SubSubDir\Three.txt
Returns:
C:\Directory\One.txt
C:\Directory\SubDir\Two.txt
C:\Directory\SubDir\SubSubDir\Three.txt
.EXAMPLE
Find-VstsFiles -LegacyPattern "C:\Directory\Sub**Match.txt"
Given:
C:\Directory\IsNotAMatch.txt
C:\Directory\SubDir\IsAMatch.txt
C:\Directory\SubDir\IsNot.txt
C:\Directory\SubDir\SubSubDir\IsAMatch.txt
C:\Directory\SubDir\SubSubDir\IsNot.txt
Returns:
C:\Directory\SubDir\IsAMatch.txt
C:\Directory\SubDir\SubSubDir\IsAMatch.txt
#>
function Find-Files {
[CmdletBinding()]
param(
[ValidateNotNullOrEmpty()]
[Parameter()]
[string]$LiteralDirectory,
[Parameter(Mandatory = $true)]
[string]$LegacyPattern,
[switch]$IncludeFiles,
[switch]$IncludeDirectories,
[switch]$Force)
Trace-EnteringInvocation $MyInvocation
if (!$IncludeFiles -and !$IncludeDirectories) {
$IncludeFiles = $true
}
$includePatterns = New-Object System.Collections.Generic.List[string]
$excludePatterns = New-Object System.Collections.Generic.List[System.Text.RegularExpressions.Regex]
$LegacyPattern = $LegacyPattern.Replace(';;', "`0")
foreach ($pattern in $LegacyPattern.Split(';', [System.StringSplitOptions]::RemoveEmptyEntries)) {
$pattern = $pattern.Replace("`0", ';')
$isIncludePattern = Test-IsIncludePattern -Pattern ([ref]$pattern)
if ($LiteralDirectory -and !([System.IO.Path]::IsPathRooted($pattern))) {
# Use the root directory provided to make the pattern a rooted path.
$pattern = [System.IO.Path]::Combine($LiteralDirectory, $pattern)
}
# Validate pattern does not end with a \.
if ($pattern[$pattern.Length - 1] -eq [System.IO.Path]::DirectorySeparatorChar) {
throw (Get-LocString -Key PSLIB_InvalidPattern0 -ArgumentList $pattern)
}
if ($isIncludePattern) {
$includePatterns.Add($pattern)
} else {
$excludePatterns.Add((Convert-PatternToRegex -Pattern $pattern))
}
}
$count = 0
foreach ($path in (Get-MatchingItems -IncludePatterns $includePatterns -ExcludePatterns $excludePatterns -IncludeFiles:$IncludeFiles -IncludeDirectories:$IncludeDirectories -Force:$Force)) {
$count++
$path
}
Write-Verbose "Total found: $count"
Trace-LeavingInvocation $MyInvocation
}
########################################
# Private functions.
########################################
function Convert-PatternToRegex {
[CmdletBinding()]
param([string]$Pattern)
$Pattern = [regex]::Escape($Pattern.Replace('\', '/')). # Normalize separators and regex escape.
Replace('/\*\*/', '((/.+/)|(/))'). # Replace directory globstar.
Replace('\*\*', '.*'). # Replace remaining globstars with a wildcard that can span directory separators.
Replace('\*', '[^/]*'). # Replace asterisks with a wildcard that cannot span directory separators.
Replace('\?', '.') # Replace single character wildcards.
New-Object regex -ArgumentList "^$Pattern`$", ([System.Text.RegularExpressions.RegexOptions]::IgnoreCase)
}
function Get-FileNameFilter {
[CmdletBinding()]
param([string]$Pattern)
$index = $Pattern.LastIndexOf('\')
if ($index -eq -1 -or # Pattern does not contain a backslash.
!($Pattern = $Pattern.Substring($index + 1)) -or # Pattern ends in a backslash.
$Pattern.Contains('**')) # Last segment contains an inter-segment wildcard.
{
return '*'
}
return $Pattern
}
function Get-MatchingItems {
[CmdletBinding()]
param(
[System.Collections.Generic.List[string]]$IncludePatterns,
[System.Collections.Generic.List[regex]]$ExcludePatterns,
[switch]$IncludeFiles,
[switch]$IncludeDirectories,
[switch]$Force)
Trace-EnteringInvocation $MyInvocation
$allFiles = New-Object System.Collections.Generic.HashSet[string]
foreach ($pattern in $IncludePatterns) {
$pathPrefix = Get-PathPrefix -Pattern $pattern
$fileNameFilter = Get-FileNameFilter -Pattern $pattern
$patternRegex = Convert-PatternToRegex -Pattern $pattern
# Iterate over the directories and files under the pathPrefix.
Get-PathIterator -Path $pathPrefix -Filter $fileNameFilter -IncludeFiles:$IncludeFiles -IncludeDirectories:$IncludeDirectories -Force:$Force |
ForEach-Object {
# Normalize separators.
$normalizedPath = $_.Replace('\', '/')
# **/times/** will not match C:/fun/times because there isn't a trailing slash.
# So try both if including directories.
$alternatePath = "$normalizedPath/"
$isMatch = $false
if ($patternRegex.IsMatch($normalizedPath) -or ($IncludeDirectories -and $patternRegex.IsMatch($alternatePath))) {
$isMatch = $true
# Test whether the path should be excluded.
foreach ($regex in $ExcludePatterns) {
if ($regex.IsMatch($normalizedPath) -or ($IncludeDirectories -and $regex.IsMatch($alternatePath))) {
$isMatch = $false
break
}
}
}
if ($isMatch) {
$null = $allFiles.Add($_)
}
}
}
Trace-Path -Path $allFiles -PassThru
Trace-LeavingInvocation $MyInvocation
}
function Get-PathIterator {
[CmdletBinding()]
param(
[string]$Path,
[string]$Filter,
[switch]$IncludeFiles,
[switch]$IncludeDirectories,
[switch]$Force)
if (!$Path) {
return
}
if ($IncludeDirectories) {
$Path
}
Get-DirectoryChildItem -Path $Path -Filter $Filter -Force:$Force -Recurse |
ForEach-Object {
if ($_.Attributes.HasFlag([VstsTaskSdk.FS.Attributes]::Directory)) {
if ($IncludeDirectories) {
$_.FullName
}
} elseif ($IncludeFiles) {
$_.FullName
}
}
}
function Get-PathPrefix {
[CmdletBinding()]
param([string]$Pattern)
$index = $Pattern.IndexOfAny([char[]]@('*'[0], '?'[0]))
if ($index -eq -1) {
# If no wildcards are found, return the directory name portion of the path.
# If there is no directory name (file name only in pattern), this will return empty string.
return [System.IO.Path]::GetDirectoryName($Pattern)
}
[System.IO.Path]::GetDirectoryName($Pattern.Substring(0, $index))
}
function Test-IsIncludePattern {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[ref]$Pattern)
# Include patterns start with +: or anything except -:
# Exclude patterns start with -:
if ($Pattern.value.StartsWith("+:")) {
# Remove the prefix.
$Pattern.value = $Pattern.value.Substring(2)
$true
} elseif ($Pattern.value.StartsWith("-:")) {
# Remove the prefix.
$Pattern.value = $Pattern.value.Substring(2)
$false
} else {
# No prefix, so leave the string alone.
$true;
}
}

Просмотреть файл

@ -0,0 +1,425 @@
# Hash table of known variable info. The formatted env var name is the lookup key.
#
# The purpose of this hash table is to keep track of known variables. The hash table
# needs to be maintained for multiple reasons:
# 1) to distinguish between env vars and job vars
# 2) to distinguish between secret vars and public
# 3) to know the real variable name and not just the formatted env var name.
$script:knownVariables = @{ }
$script:vault = @{ }
<#
.SYNOPSIS
Gets an endpoint.
.DESCRIPTION
Gets an endpoint object for the specified endpoint name. The endpoint is returned as an object with three properties: Auth, Data, and Url.
The Data property requires a 1.97 agent or higher.
.PARAMETER Require
Writes an error to the error pipeline if the endpoint is not found.
#>
function Get-Endpoint {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$Name,
[switch]$Require)
$originalErrorActionPreference = $ErrorActionPreference
try {
$ErrorActionPreference = 'Stop'
# Get the URL.
$description = Get-LocString -Key PSLIB_EndpointUrl0 -ArgumentList $Name
$key = "ENDPOINT_URL_$Name"
$url = Get-VaultValue -Description $description -Key $key -Require:$Require
# Get the auth object.
$description = Get-LocString -Key PSLIB_EndpointAuth0 -ArgumentList $Name
$key = "ENDPOINT_AUTH_$Name"
if ($auth = (Get-VaultValue -Description $description -Key $key -Require:$Require)) {
$auth = ConvertFrom-Json -InputObject $auth
}
# Get the data.
$description = "'$Name' service endpoint data"
$key = "ENDPOINT_DATA_$Name"
if ($data = (Get-VaultValue -Description $description -Key $key)) {
$data = ConvertFrom-Json -InputObject $data
}
# Return the endpoint.
if ($url -or $auth -or $data) {
New-Object -TypeName psobject -Property @{
Url = $url
Auth = $auth
Data = $data
}
}
} catch {
$ErrorActionPreference = $originalErrorActionPreference
Write-Error $_
}
}
<#
.SYNOPSIS
Gets an input.
.DESCRIPTION
Gets the value for the specified input name.
.PARAMETER AsBool
Returns the value as a bool. Returns true if the value converted to a string is "1" or "true" (case insensitive); otherwise false.
.PARAMETER AsInt
Returns the value as an int. Returns the value converted to an int. Returns 0 if the conversion fails.
.PARAMETER Default
Default value to use if the input is null or empty.
.PARAMETER Require
Writes an error to the error pipeline if the input is null or empty.
#>
function Get-Input {
[CmdletBinding(DefaultParameterSetName = 'Require')]
param(
[Parameter(Mandatory = $true)]
[string]$Name,
[Parameter(ParameterSetName = 'Default')]
$Default,
[Parameter(ParameterSetName = 'Require')]
[switch]$Require,
[switch]$AsBool,
[switch]$AsInt)
# Get the input from the vault. Splat the bound parameters hashtable. Splatting is required
# in order to concisely invoke the correct parameter set.
$null = $PSBoundParameters.Remove('Name')
$description = Get-LocString -Key PSLIB_Input0 -ArgumentList $Name
$key = "INPUT_$($Name.Replace(' ', '_').ToUpperInvariant())"
Get-VaultValue @PSBoundParameters -Description $description -Key $key
}
<#
.SYNOPSIS
Gets a task variable.
.DESCRIPTION
Gets the value for the specified task variable.
.PARAMETER AsBool
Returns the value as a bool. Returns true if the value converted to a string is "1" or "true" (case insensitive); otherwise false.
.PARAMETER AsInt
Returns the value as an int. Returns the value converted to an int. Returns 0 if the conversion fails.
.PARAMETER Default
Default value to use if the input is null or empty.
.PARAMETER Require
Writes an error to the error pipeline if the input is null or empty.
#>
function Get-TaskVariable {
[CmdletBinding(DefaultParameterSetName = 'Require')]
param(
[Parameter(Mandatory = $true)]
[string]$Name,
[Parameter(ParameterSetName = 'Default')]
$Default,
[Parameter(ParameterSetName = 'Require')]
[switch]$Require,
[switch]$AsBool,
[switch]$AsInt)
$originalErrorActionPreference = $ErrorActionPreference
try {
$ErrorActionPreference = 'Stop'
$description = Get-LocString -Key PSLIB_TaskVariable0 -ArgumentList $Name
$variableKey = Get-VariableKey -Name $Name
if ($script:knownVariables.$variableKey.Secret) {
# Get secret variable. Splatting is required to concisely invoke the correct parameter set.
$null = $PSBoundParameters.Remove('Name')
$vaultKey = "SECRET_$variableKey"
Get-VaultValue @PSBoundParameters -Description $description -Key $vaultKey
} else {
# Get public variable.
$item = $null
$path = "Env:$variableKey"
if ((Test-Path -LiteralPath $path) -and ($item = Get-Item -LiteralPath $path).Value) {
# Intentionally empty. Value was successfully retrieved.
} elseif (!$script:nonInteractive) {
# The value wasn't found and the module is running in interactive dev mode.
# Prompt for the value.
Set-Item -LiteralPath $path -Value (Read-Host -Prompt $description)
if (Test-Path -LiteralPath $path) {
$item = Get-Item -LiteralPath $path
}
}
# Get the converted value. Splatting is required to concisely invoke the correct parameter set.
$null = $PSBoundParameters.Remove('Name')
Get-Value @PSBoundParameters -Description $description -Key $variableKey -Value $item.Value
}
} catch {
$ErrorActionPreference = $originalErrorActionPreference
Write-Error $_
}
}
<#
.SYNOPSIS
Gets all job variables available to the task. Requires 2.104.1 agent or higher.
.DESCRIPTION
Gets a snapshot of the current state of all job variables available to the task.
Requires a 2.104.1 agent or higher for full functionality.
Returns an array of objects with the following properties:
[string]Name
[string]Value
[bool]Secret
Limitations on an agent prior to 2.104.1:
1) The return value does not include all public variables. Only public variables
that have been added using setVariable are returned.
2) The name returned for each secret variable is the formatted environment variable
name, not the actual variable name (unless it was set explicitly at runtime using
setVariable).
#>
function Get-TaskVariableInfo {
[CmdletBinding()]
param()
foreach ($info in $script:knownVariables.Values) {
New-Object -TypeName psobject -Property @{
Name = $info.Name
Value = Get-TaskVariable -Name $info.Name
Secret = $info.Secret
}
}
}
<#
.SYNOPSIS
Sets a task variable.
.DESCRIPTION
Sets a task variable in the current task context as well as in the current job context. This allows the task variable to retrieved by subsequent tasks within the same job.
#>
function Set-TaskVariable {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$Name,
[string]$Value,
[switch]$Secret)
# Once a secret always a secret.
$variableKey = Get-VariableKey -Name $Name
[bool]$Secret = $Secret -or $script:knownVariables.$variableKey.Secret
if ($Secret) {
$vaultKey = "SECRET_$variableKey"
if (!$Value) {
# Clear the secret.
Write-Verbose "Set $Name = ''"
$script:vault.Remove($vaultKey)
} else {
# Store the secret in the vault.
Write-Verbose "Set $Name = '********'"
$script:vault[$vaultKey] = New-Object System.Management.Automation.PSCredential(
$vaultKey,
(ConvertTo-SecureString -String $Value -AsPlainText -Force))
}
# Clear the environment variable.
Set-Item -LiteralPath "Env:$variableKey" -Value ''
} else {
# Set the environment variable.
Write-Verbose "Set $Name = '$Value'"
Set-Item -LiteralPath "Env:$variableKey" -Value $Value
}
# Store the metadata.
$script:knownVariables[$variableKey] = New-Object -TypeName psobject -Property @{
Name = $name
Secret = $Secret
}
# Persist the variable in the task context.
Write-SetVariable -Name $Name -Value $Value -Secret:$Secret
}
########################################
# Private functions.
########################################
function Get-VaultValue {
[CmdletBinding(DefaultParameterSetName = 'Require')]
param(
[Parameter(Mandatory = $true)]
[string]$Description,
[Parameter(Mandatory = $true)]
[string]$Key,
[Parameter(ParameterSetName = 'Require')]
[switch]$Require,
[Parameter(ParameterSetName = 'Default')]
[object]$Default,
[switch]$AsBool,
[switch]$AsInt)
# Attempt to get the vault value.
$value = $null
if ($psCredential = $script:vault[$Key]) {
$value = $psCredential.GetNetworkCredential().Password
} elseif (!$script:nonInteractive) {
# The value wasn't found. Prompt for the value if running in interactive dev mode.
$value = Read-Host -Prompt $Description
if ($value) {
$script:vault[$Key] = New-Object System.Management.Automation.PSCredential(
$Key,
(ConvertTo-SecureString -String $value -AsPlainText -Force))
}
}
Get-Value -Value $value @PSBoundParameters
}
function Get-Value {
[CmdletBinding(DefaultParameterSetName = 'Require')]
param(
[string]$Value,
[Parameter(Mandatory = $true)]
[string]$Description,
[Parameter(Mandatory = $true)]
[string]$Key,
[Parameter(ParameterSetName = 'Require')]
[switch]$Require,
[Parameter(ParameterSetName = 'Default')]
[object]$Default,
[switch]$AsBool,
[switch]$AsInt)
$result = $Value
if ($result) {
if ($Key -like 'ENDPOINT_AUTH_*') {
Write-Verbose "$($Key): '********'"
} else {
Write-Verbose "$($Key): '$result'"
}
} else {
Write-Verbose "$Key (empty)"
# Write error if required.
if ($Require) {
Write-Error "$(Get-LocString -Key PSLIB_Required0 $Description)"
return
}
# Fallback to the default if provided.
if ($PSCmdlet.ParameterSetName -eq 'Default') {
$result = $Default
$OFS = ' '
Write-Verbose " Defaulted to: '$result'"
} else {
$result = ''
}
}
# Convert to bool if specified.
if ($AsBool) {
if ($result -isnot [bool]) {
$result = "$result" -in '1', 'true'
Write-Verbose " Converted to bool: $result"
}
return $result
}
# Convert to int if specified.
if ($AsInt) {
if ($result -isnot [int]) {
try {
$result = [int]"$result"
} catch {
$result = 0
}
Write-Verbose " Converted to int: $result"
}
return $result
}
return $result
}
function Initialize-Inputs {
# Store endpoints, inputs, and secret variables in the vault.
foreach ($variable in (Get-ChildItem -Path Env:ENDPOINT_?*, Env:INPUT_?*, Env:SECRET_?*)) {
# Record the secret variable metadata. This is required by Get-TaskVariable to
# retrieve the value. In a 2.104.1 agent or higher, this metadata will be overwritten
# when $env:VSTS_SECRET_VARIABLES is processed.
if ($variable.Name -like 'SECRET_?*') {
$variableKey = $variable.Name.Substring('SECRET_'.Length)
$script:knownVariables[$variableKey] = New-Object -TypeName psobject -Property @{
# This is technically not the variable name (has underscores instead of dots),
# but it's good enough to make Get-TaskVariable work in a pre-2.104.1 agent
# where $env:VSTS_SECRET_VARIABLES is not defined.
Name = $variableKey
Secret = $true
}
}
# Store the value in the vault.
$vaultKey = $variable.Name
if ($variable.Value) {
$script:vault[$vaultKey] = New-Object System.Management.Automation.PSCredential(
$vaultKey,
(ConvertTo-SecureString -String $variable.Value -AsPlainText -Force))
}
# Clear the environment variable.
Remove-Item -LiteralPath "Env:$($variable.Name)"
}
# Record the public variable names. Env var added in 2.104.1 agent.
if ($env:VSTS_PUBLIC_VARIABLES) {
foreach ($name in (ConvertFrom-Json -InputObject $env:VSTS_PUBLIC_VARIABLES)) {
$variableKey = Get-VariableKey -Name $name
$script:knownVariables[$variableKey] = New-Object -TypeName psobject -Property @{
Name = $name
Secret = $false
}
}
$env:VSTS_PUBLIC_VARIABLES = ''
}
# Record the secret variable names. Env var added in 2.104.1 agent.
if ($env:VSTS_SECRET_VARIABLES) {
foreach ($name in (ConvertFrom-Json -InputObject $env:VSTS_SECRET_VARIABLES)) {
$variableKey = Get-VariableKey -Name $name
$script:knownVariables[$variableKey] = New-Object -TypeName psobject -Property @{
Name = $name
Secret = $true
}
}
$env:VSTS_SECRET_VARIABLES = ''
}
}
function Get-VariableKey {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$Name)
if ($Name -ne 'agent.jobstatus') {
$Name = $Name.Replace('.', '_')
}
$Name.ToUpperInvariant()
}

Просмотреть файл

@ -0,0 +1,150 @@
$script:resourceStrings = @{ }
<#
.SYNOPSIS
Gets a localized resource string.
.DESCRIPTION
Gets a localized resource string and optionally formats the string with arguments.
If the format fails (due to a bad format string or incorrect expected arguments in the format string), then the format string is returned followed by each of the arguments (delimited by a space).
If the lookup key is not found, then the lookup key is returned followed by each of the arguments (delimited by a space).
.PARAMETER Require
Writes an error to the error pipeline if the endpoint is not found.
#>
function Get-LocString {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true, Position = 1)]
[string]$Key,
[Parameter(Position = 2)]
[object[]]$ArgumentList = @( ))
# Due to the dynamically typed nature of PowerShell, a single null argument passed
# to an array parameter is interpreted as a null array.
if ([object]::ReferenceEquals($null, $ArgumentList)) {
$ArgumentList = @( $null )
}
# Lookup the format string.
$format = ''
if (!($format = $script:resourceStrings[$Key])) {
# Warn the key was not found. Prevent recursion if the lookup key is the
# "string resource key not found" lookup key.
$resourceNotFoundKey = 'PSLIB_StringResourceKeyNotFound0'
if ($key -ne $resourceNotFoundKey) {
Write-Warning (Get-LocString -Key $resourceNotFoundKey -ArgumentList $Key)
}
# Fallback to just the key itself if there aren't any arguments to format.
if (!$ArgumentList.Count) { return $key }
# Otherwise fallback to the key followed by the arguments.
$OFS = " "
return "$key $ArgumentList"
}
# Return the string if there aren't any arguments to format.
if (!$ArgumentList.Count) { return $format }
try {
[string]::Format($format, $ArgumentList)
} catch {
Write-Warning (Get-LocString -Key 'PSLIB_StringFormatFailed')
$OFS = " "
"$format $ArgumentList"
}
}
<#
.SYNOPSIS
Imports resource strings for use with Get-VstsLocString.
.DESCRIPTION
Imports resource strings for use with Get-VstsLocString. The imported strings are stored in an internal resource string dictionary. Optionally, if a separate resource file for the current culture exists, then the localized strings from that file then imported (overlaid) into the same internal resource string dictionary.
Resource strings from the SDK are prefixed with "PSLIB_". This prefix should be avoided for custom resource strings.
.Parameter LiteralPath
JSON file containing resource strings.
.EXAMPLE
Import-VstsLocStrings -LiteralPath $PSScriptRoot\Task.json
Imports strings from messages section in the JSON file. If a messages section is not defined, then no strings are imported. Example messages section:
{
"messages": {
"Hello": "Hello you!",
"Hello0": "Hello {0}!"
}
}
.EXAMPLE
Import-VstsLocStrings -LiteralPath $PSScriptRoot\Task.json
Overlays strings from an optional separate resource file for the current culture.
Given the task variable System.Culture is set to 'de-DE'. This variable is set by the agent based on the current culture for the job.
Given the file Task.json contains:
{
"messages": {
"GoodDay": "Good day!",
}
}
Given the file resources.resjson\de-DE\resources.resjson:
{
"loc.messages.GoodDay": "Guten Tag!"
}
The net result from the import command would be one new key-value pair added to the internal dictionary: Key = 'GoodDay', Value = 'Guten Tag!'
#>
function Import-LocStrings {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$LiteralPath)
# Validate the file exists.
if (!(Test-Path -LiteralPath $LiteralPath -PathType Leaf)) {
Write-Warning (Get-LocString -Key PSLIB_FileNotFound0 -ArgumentList $LiteralPath)
return
}
# Load the json.
Write-Verbose "Loading resource strings from: $LiteralPath"
$count = 0
if ($messages = (Get-Content -LiteralPath $LiteralPath -Encoding UTF8 | Out-String | ConvertFrom-Json).messages) {
# Add each resource string to the hashtable.
foreach ($member in (Get-Member -InputObject $messages -MemberType NoteProperty)) {
[string]$key = $member.Name
$script:resourceStrings[$key] = $messages."$key"
$count++
}
}
Write-Verbose "Loaded $count strings."
# Get the culture.
$culture = Get-TaskVariable -Name "System.Culture" -Default "en-US"
# Load the resjson.
$resjsonPath = "$([System.IO.Path]::GetDirectoryName($LiteralPath))\Strings\resources.resjson\$culture\resources.resjson"
if (Test-Path -LiteralPath $resjsonPath) {
Write-Verbose "Loading resource strings from: $resjsonPath"
$count = 0
$resjson = Get-Content -LiteralPath $resjsonPath -Encoding UTF8 | Out-String | ConvertFrom-Json
foreach ($member in (Get-Member -Name loc.messages.* -InputObject $resjson -MemberType NoteProperty)) {
if (!($value = $resjson."$($member.Name)")) {
continue
}
[string]$key = $member.Name.Substring('loc.messages.'.Length)
$script:resourceStrings[$key] = $value
$count++
}
Write-Verbose "Loaded $count strings."
}
}

Просмотреть файл

@ -0,0 +1,506 @@
$script:loggingCommandPrefix = '##vso['
$script:loggingCommandEscapeMappings = @( # TODO: WHAT ABOUT "="? WHAT ABOUT "%"?
New-Object psobject -Property @{ Token = ';' ; Replacement = '%3B' }
New-Object psobject -Property @{ Token = "`r" ; Replacement = '%0D' }
New-Object psobject -Property @{ Token = "`n" ; Replacement = '%0A' }
)
# TODO: BUG: Escape ]
# TODO: BUG: Escape % ???
# TODO: Add test to verify don't need to escape "=".
<#
.SYNOPSIS
See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md
.PARAMETER AsOutput
Indicates whether to write the logging command directly to the host or to the output pipeline.
#>
function Write-AddAttachment {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$Type,
[Parameter(Mandatory = $true)]
[string]$Name,
[Parameter(Mandatory = $true)]
[string]$Path,
[switch]$AsOutput)
Write-LoggingCommand -Area 'task' -Event 'addattachment' -Data $Path -Properties @{
'type' = $Type
'name' = $Name
} -AsOutput:$AsOutput
}
<#
.SYNOPSIS
See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md
.PARAMETER AsOutput
Indicates whether to write the logging command directly to the host or to the output pipeline.
#>
function Write-AddBuildTag {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$Value,
[switch]$AsOutput)
Write-LoggingCommand -Area 'build' -Event 'addbuildtag' -Data $Value -AsOutput:$AsOutput
}
<#
.SYNOPSIS
See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md
.PARAMETER AsOutput
Indicates whether to write the logging command directly to the host or to the output pipeline.
#>
function Write-AssociateArtifact {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$Name,
[Parameter(Mandatory = $true)]
[string]$Path,
[Parameter(Mandatory = $true)]
[string]$Type,
[hashtable]$Properties,
[switch]$AsOutput)
$p = @{ }
if ($Properties) {
foreach ($key in $Properties.Keys) {
$p[$key] = $Properties[$key]
}
}
$p['artifactname'] = $Name
$p['artifacttype'] = $Type
Write-LoggingCommand -Area 'artifact' -Event 'associate' -Data $Path -Properties $p -AsOutput:$AsOutput
}
<#
.SYNOPSIS
See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md
.PARAMETER AsOutput
Indicates whether to write the logging command directly to the host or to the output pipeline.
#>
function Write-LogDetail {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[guid]$Id,
$ParentId,
[string]$Type,
[string]$Name,
$Order,
$StartTime,
$FinishTime,
$Progress,
[ValidateSet('Unknown', 'Initialized', 'InProgress', 'Completed')]
[Parameter()]
$State,
[ValidateSet('Succeeded', 'SucceededWithIssues', 'Failed', 'Cancelled', 'Skipped')]
[Parameter()]
$Result,
[string]$Message,
[switch]$AsOutput)
Write-LoggingCommand -Area 'task' -Event 'logdetail' -Data $Message -Properties @{
'id' = $Id
'parentid' = $ParentId
'type' = $Type
'name' = $Name
'order' = $Order
'starttime' = $StartTime
'finishtime' = $FinishTime
'progress' = $Progress
'state' = $State
'result' = $Result
} -AsOutput:$AsOutput
}
<#
.SYNOPSIS
See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md
.PARAMETER AsOutput
Indicates whether to write the logging command directly to the host or to the output pipeline.
#>
function Write-SetProgress {
[CmdletBinding()]
param(
[ValidateRange(0, 100)]
[Parameter(Mandatory = $true)]
[int]$Percent,
[string]$CurrentOperation,
[switch]$AsOutput)
Write-LoggingCommand -Area 'task' -Event 'setprogress' -Data $CurrentOperation -Properties @{
'value' = $Percent
} -AsOutput:$AsOutput
}
<#
.SYNOPSIS
See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md
.PARAMETER AsOutput
Indicates whether to write the logging command directly to the host or to the output pipeline.
#>
function Write-SetResult {
[CmdletBinding(DefaultParameterSetName = 'AsOutput')]
param(
[ValidateSet("Succeeded", "SucceededWithIssues", "Failed", "Cancelled", "Skipped")]
[Parameter(Mandatory = $true)]
[string]$Result,
[string]$Message,
[Parameter(ParameterSetName = 'AsOutput')]
[switch]$AsOutput,
[Parameter(ParameterSetName = 'DoNotThrow')]
[switch]$DoNotThrow)
Write-LoggingCommand -Area 'task' -Event 'complete' -Data $Message -Properties @{
'result' = $Result
} -AsOutput:$AsOutput
if ($Result -eq 'Failed' -and !$AsOutput -and !$DoNotThrow) {
# Special internal exception type to control the flow. Not currently intended
# for public usage and subject to change.
throw (New-Object VstsTaskSdk.TerminationException($Message))
}
}
<#
.SYNOPSIS
See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md
.PARAMETER AsOutput
Indicates whether to write the logging command directly to the host or to the output pipeline.
#>
function Write-SetSecret {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$Value,
[switch]$AsOutput)
Write-LoggingCommand -Area 'task' -Event 'setsecret' -Data $Value -AsOutput:$AsOutput
}
<#
.SYNOPSIS
See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md
.PARAMETER AsOutput
Indicates whether to write the logging command directly to the host or to the output pipeline.
#>
function Write-SetVariable {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$Name,
[string]$Value,
[switch]$Secret,
[switch]$AsOutput)
Write-LoggingCommand -Area 'task' -Event 'setvariable' -Data $Value -Properties @{
'variable' = $Name
'issecret' = $Secret
} -AsOutput:$AsOutput
}
<#
.SYNOPSIS
See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md
.PARAMETER AsOutput
Indicates whether to write the logging command directly to the host or to the output pipeline.
#>
function Write-TaskDebug {
[CmdletBinding()]
param(
[string]$Message,
[switch]$AsOutput)
Write-TaskDebug_Internal @PSBoundParameters
}
<#
.SYNOPSIS
See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md
.PARAMETER AsOutput
Indicates whether to write the logging command directly to the host or to the output pipeline.
#>
function Write-TaskError {
[CmdletBinding()]
param(
[string]$Message,
[string]$ErrCode,
[string]$SourcePath,
[string]$LineNumber,
[string]$ColumnNumber,
[switch]$AsOutput)
Write-LogIssue -Type error @PSBoundParameters
}
<#
.SYNOPSIS
See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md
.PARAMETER AsOutput
Indicates whether to write the logging command directly to the host or to the output pipeline.
#>
function Write-TaskVerbose {
[CmdletBinding()]
param(
[string]$Message,
[switch]$AsOutput)
Write-TaskDebug_Internal @PSBoundParameters -AsVerbose
}
<#
.SYNOPSIS
See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md
.PARAMETER AsOutput
Indicates whether to write the logging command directly to the host or to the output pipeline.
#>
function Write-TaskWarning {
[CmdletBinding()]
param(
[string]$Message,
[string]$ErrCode,
[string]$SourcePath,
[string]$LineNumber,
[string]$ColumnNumber,
[switch]$AsOutput)
Write-LogIssue -Type warning @PSBoundParameters
}
<#
.SYNOPSIS
See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md
.PARAMETER AsOutput
Indicates whether to write the logging command directly to the host or to the output pipeline.
#>
function Write-UpdateBuildNumber {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$Value,
[switch]$AsOutput)
Write-LoggingCommand -Area 'build' -Event 'updatebuildnumber' -Data $Value -AsOutput:$AsOutput
}
<#
.SYNOPSIS
See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md
.PARAMETER AsOutput
Indicates whether to write the logging command directly to the host or to the output pipeline.
#>
function Write-UploadArtifact {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$ContainerFolder,
[Parameter(Mandatory = $true)]
[string]$Name,
[Parameter(Mandatory = $true)]
[string]$Path,
[switch]$AsOutput)
Write-LoggingCommand -Area 'artifact' -Event 'upload' -Data $Path -Properties @{
'containerfolder' = $ContainerFolder
'artifactname' = $Name
} -AsOutput:$AsOutput
}
<#
.SYNOPSIS
See https://github.com/Microsoft/vsts-tasks/blob/master/docs/authoring/commands.md
.PARAMETER AsOutput
Indicates whether to write the logging command directly to the host or to the output pipeline.
#>
function Write-UploadBuildLog {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$Path,
[switch]$AsOutput)
Write-LoggingCommand -Area 'build' -Event 'uploadlog' -Data $Path -AsOutput:$AsOutput
}
########################################
# Private functions.
########################################
function Format-LoggingCommandData {
[CmdletBinding()]
param([string]$Value, [switch]$Reverse)
if (!$Value) {
return ''
}
if (!$Reverse) {
foreach ($mapping in $script:loggingCommandEscapeMappings) {
$Value = $Value.Replace($mapping.Token, $mapping.Replacement)
}
} else {
for ($i = $script:loggingCommandEscapeMappings.Length - 1 ; $i -ge 0 ; $i--) {
$mapping = $script:loggingCommandEscapeMappings[$i]
$Value = $Value.Replace($mapping.Replacement, $mapping.Token)
}
}
return $Value
}
function Format-LoggingCommand {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$Area,
[Parameter(Mandatory = $true)]
[string]$Event,
[string]$Data,
[hashtable]$Properties)
# Append the preamble.
[System.Text.StringBuilder]$sb = New-Object -TypeName System.Text.StringBuilder
$null = $sb.Append($script:loggingCommandPrefix).Append($Area).Append('.').Append($Event)
# Append the properties.
if ($Properties) {
$first = $true
foreach ($key in $Properties.Keys) {
[string]$value = Format-LoggingCommandData $Properties[$key]
if ($value) {
if ($first) {
$null = $sb.Append(' ')
$first = $false
} else {
$null = $sb.Append(';')
}
$null = $sb.Append("$key=$value")
}
}
}
# Append the tail and output the value.
$Data = Format-LoggingCommandData $Data
$sb.Append(']').Append($Data).ToString()
}
function Write-LoggingCommand {
[CmdletBinding(DefaultParameterSetName = 'Parameters')]
param(
[Parameter(Mandatory = $true, ParameterSetName = 'Parameters')]
[string]$Area,
[Parameter(Mandatory = $true, ParameterSetName = 'Parameters')]
[string]$Event,
[Parameter(ParameterSetName = 'Parameters')]
[string]$Data,
[Parameter(ParameterSetName = 'Parameters')]
[hashtable]$Properties,
[Parameter(Mandatory = $true, ParameterSetName = 'Object')]
$Command,
[switch]$AsOutput)
if ($PSCmdlet.ParameterSetName -eq 'Object') {
Write-LoggingCommand -Area $Command.Area -Event $Command.Event -Data $Command.Data -Properties $Command.Properties -AsOutput:$AsOutput
return
}
$command = Format-LoggingCommand -Area $Area -Event $Event -Data $Data -Properties $Properties
if ($AsOutput) {
$command
} else {
Write-Host $command
}
}
function Write-LogIssue {
[CmdletBinding()]
param(
[ValidateSet('warning', 'error')]
[Parameter(Mandatory = $true)]
[string]$Type,
[string]$Message,
[string]$ErrCode,
[string]$SourcePath,
[string]$LineNumber,
[string]$ColumnNumber,
[switch]$AsOutput)
$command = Format-LoggingCommand -Area 'task' -Event 'logissue' -Data $Message -Properties @{
'type' = $Type
'code' = $ErrCode
'sourcepath' = $SourcePath
'linenumber' = $LineNumber
'columnnumber' = $ColumnNumber
}
if ($AsOutput) {
return $command
}
if ($Type -eq 'error') {
$foregroundColor = $host.PrivateData.ErrorForegroundColor
$backgroundColor = $host.PrivateData.ErrorBackgroundColor
if ($foregroundColor -isnot [System.ConsoleColor] -or $backgroundColor -isnot [System.ConsoleColor]) {
$foregroundColor = [System.ConsoleColor]::Red
$backgroundColor = [System.ConsoleColor]::Black
}
} else {
$foregroundColor = $host.PrivateData.WarningForegroundColor
$backgroundColor = $host.PrivateData.WarningBackgroundColor
if ($foregroundColor -isnot [System.ConsoleColor] -or $backgroundColor -isnot [System.ConsoleColor]) {
$foregroundColor = [System.ConsoleColor]::Yellow
$backgroundColor = [System.ConsoleColor]::Black
}
}
Write-Host $command -ForegroundColor $foregroundColor -BackgroundColor $backgroundColor
}
function Write-TaskDebug_Internal {
[CmdletBinding()]
param(
[string]$Message,
[switch]$AsVerbose,
[switch]$AsOutput)
$command = Format-LoggingCommand -Area 'task' -Event 'debug' -Data $Message
if ($AsOutput) {
return $command
}
if ($AsVerbose) {
$foregroundColor = $host.PrivateData.VerboseForegroundColor
$backgroundColor = $host.PrivateData.VerboseBackgroundColor
if ($foregroundColor -isnot [System.ConsoleColor] -or $backgroundColor -isnot [System.ConsoleColor]) {
$foregroundColor = [System.ConsoleColor]::Cyan
$backgroundColor = [System.ConsoleColor]::Black
}
} else {
$foregroundColor = $host.PrivateData.DebugForegroundColor
$backgroundColor = $host.PrivateData.DebugBackgroundColor
if ($foregroundColor -isnot [System.ConsoleColor] -or $backgroundColor -isnot [System.ConsoleColor]) {
$foregroundColor = [System.ConsoleColor]::DarkGray
$backgroundColor = [System.ConsoleColor]::Black
}
}
Write-Host -Object $command -ForegroundColor $foregroundColor -BackgroundColor $backgroundColor
}

Просмотреть файл

@ -0,0 +1,365 @@
########################################
# Private functions.
########################################
function ConvertFrom-LongFormPath {
[CmdletBinding()]
param([string]$Path)
if ($Path) {
if ($Path.StartsWith('\\?\UNC')) {
# E.g. \\?\UNC\server\share -> \\server\share
return $Path.Substring(1, '\?\UNC'.Length)
} elseif ($Path.StartsWith('\\?\')) {
# E.g. \\?\C:\directory -> C:\directory
return $Path.Substring('\\?\'.Length)
}
}
return $Path
}
function ConvertTo-LongFormPath {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$Path)
[string]$longFormPath = Get-FullNormalizedPath -Path $Path
if ($longFormPath -and !$longFormPath.StartsWith('\\?')) {
if ($longFormPath.StartsWith('\\')) {
# E.g. \\server\share -> \\?\UNC\server\share
return "\\?\UNC$($longFormPath.Substring(1))"
} else {
# E.g. C:\directory -> \\?\C:\directory
return "\\?\$longFormPath"
}
}
return $longFormPath
}
# TODO: ADD A SWITCH TO EXCLUDE FILES, A SWITCH TO EXCLUDE DIRECTORIES, AND A SWITCH NOT TO FOLLOW REPARSE POINTS.
function Get-DirectoryChildItem {
[CmdletBinding()]
param(
[string]$Path,
[ValidateNotNullOrEmpty()]
[Parameter()]
[string]$Filter = "*",
[switch]$Force,
[VstsTaskSdk.FS.FindFlags]$Flags = [VstsTaskSdk.FS.FindFlags]::LargeFetch,
[VstsTaskSdk.FS.FindInfoLevel]$InfoLevel = [VstsTaskSdk.FS.FindInfoLevel]::Basic,
[switch]$Recurse)
$stackOfDirectoryQueues = New-Object System.Collections.Stack
while ($true) {
$directoryQueue = New-Object System.Collections.Queue
$fileQueue = New-Object System.Collections.Queue
$findData = New-Object VstsTaskSdk.FS.FindData
$longFormPath = (ConvertTo-LongFormPath $Path)
$handle = $null
try {
$handle = [VstsTaskSdk.FS.NativeMethods]::FindFirstFileEx(
[System.IO.Path]::Combine($longFormPath, $Filter),
$InfoLevel,
$findData,
[VstsTaskSdk.FS.FindSearchOps]::NameMatch,
[System.IntPtr]::Zero,
$Flags)
if (!$handle.IsInvalid) {
while ($true) {
if ($findData.fileName -notin '.', '..') {
$attributes = [VstsTaskSdk.FS.Attributes]$findData.fileAttributes
# If the item is hidden, check if $Force is specified.
if ($Force -or !$attributes.HasFlag([VstsTaskSdk.FS.Attributes]::Hidden)) {
# Create the item.
$item = New-Object -TypeName psobject -Property @{
'Attributes' = $attributes
'FullName' = (ConvertFrom-LongFormPath -Path ([System.IO.Path]::Combine($Path, $findData.fileName)))
'Name' = $findData.fileName
}
# Output directories immediately.
if ($item.Attributes.HasFlag([VstsTaskSdk.FS.Attributes]::Directory)) {
$item
# Append to the directory queue if recursive and default filter.
if ($Recurse -and $Filter -eq '*') {
$directoryQueue.Enqueue($item)
}
} else {
# Hold the files until all directories have been output.
$fileQueue.Enqueue($item)
}
}
}
if (!([VstsTaskSdk.FS.NativeMethods]::FindNextFile($handle, $findData))) { break }
if ($handle.IsInvalid) {
throw (New-Object -TypeName System.ComponentModel.Win32Exception -ArgumentList @(
[System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
Get-LocString -Key PSLIB_EnumeratingSubdirectoriesFailedForPath0 -ArgumentList $Path
))
}
}
}
} finally {
if ($handle -ne $null) { $handle.Dispose() }
}
# If recursive and non-default filter, queue child directories.
if ($Recurse -and $Filter -ne '*') {
$findData = New-Object VstsTaskSdk.FS.FindData
$handle = $null
try {
$handle = [VstsTaskSdk.FS.NativeMethods]::FindFirstFileEx(
[System.IO.Path]::Combine($longFormPath, '*'),
[VstsTaskSdk.FS.FindInfoLevel]::Basic,
$findData,
[VstsTaskSdk.FS.FindSearchOps]::NameMatch,
[System.IntPtr]::Zero,
$Flags)
if (!$handle.IsInvalid) {
while ($true) {
if ($findData.fileName -notin '.', '..') {
$attributes = [VstsTaskSdk.FS.Attributes]$findData.fileAttributes
# If the item is hidden, check if $Force is specified.
if ($Force -or !$attributes.HasFlag([VstsTaskSdk.FS.Attributes]::Hidden)) {
# Collect directories only.
if ($attributes.HasFlag([VstsTaskSdk.FS.Attributes]::Directory)) {
# Create the item.
$item = New-Object -TypeName psobject -Property @{
'Attributes' = $attributes
'FullName' = (ConvertFrom-LongFormPath -Path ([System.IO.Path]::Combine($Path, $findData.fileName)))
'Name' = $findData.fileName
}
$directoryQueue.Enqueue($item)
}
}
}
if (!([VstsTaskSdk.FS.NativeMethods]::FindNextFile($handle, $findData))) { break }
if ($handle.IsInvalid) {
throw (New-Object -TypeName System.ComponentModel.Win32Exception -ArgumentList @(
[System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
Get-LocString -Key PSLIB_EnumeratingSubdirectoriesFailedForPath0 -ArgumentList $Path
))
}
}
}
} finally {
if ($handle -ne $null) { $handle.Dispose() }
}
}
# Output the files.
$fileQueue
# Push the directory queue onto the stack if any directories were found.
if ($directoryQueue.Count) { $stackOfDirectoryQueues.Push($directoryQueue) }
# Break out of the loop if no more directory queues to process.
if (!$stackOfDirectoryQueues.Count) { break }
# Get the next path.
$directoryQueue = $stackOfDirectoryQueues.Peek()
$Path = $directoryQueue.Dequeue().FullName
# Pop the directory queue if it's empty.
if (!$directoryQueue.Count) { $null = $stackOfDirectoryQueues.Pop() }
}
}
function Get-FullNormalizedPath {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$Path)
[string]$outPath = $Path
[uint32]$bufferSize = [VstsTaskSdk.FS.NativeMethods]::GetFullPathName($Path, 0, $null, $null)
[int]$lastWin32Error = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
if ($bufferSize -gt 0) {
$absolutePath = New-Object System.Text.StringBuilder([int]$bufferSize)
[uint32]$length = [VstsTaskSdk.FS.NativeMethods]::GetFullPathName($Path, $bufferSize, $absolutePath, $null)
$lastWin32Error = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
if ($length -gt 0) {
$outPath = $absolutePath.ToString()
} else {
throw (New-Object -TypeName System.ComponentModel.Win32Exception -ArgumentList @(
$lastWin32Error
Get-LocString -Key PSLIB_PathLengthNotReturnedFor0 -ArgumentList $Path
))
}
} else {
throw (New-Object -TypeName System.ComponentModel.Win32Exception -ArgumentList @(
$lastWin32Error
Get-LocString -Key PSLIB_PathLengthNotReturnedFor0 -ArgumentList $Path
))
}
if ($outPath.EndsWith('\') -and !$outPath.EndsWith(':\')) {
$outPath = $outPath.TrimEnd('\')
}
$outPath
}
########################################
# Types.
########################################
# If the type has already been loaded once, then it is not loaded again.
Write-Verbose "Adding long path native methods."
Add-Type -Debug:$false -TypeDefinition @'
namespace VstsTaskSdk.FS
{
using System;
using System.Runtime.InteropServices;
public static class NativeMethods
{
private const string Kernel32Dll = "kernel32.dll";
[DllImport(Kernel32Dll, CharSet = CharSet.Unicode, BestFitMapping = false, ThrowOnUnmappableChar = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool FindClose(IntPtr hFindFile);
// HANDLE WINAPI FindFirstFile(
// _In_ LPCTSTR lpFileName,
// _Out_ LPWIN32_FIND_DATA lpFindFileData
// );
[DllImport(Kernel32Dll, CharSet = CharSet.Unicode, BestFitMapping = false, ThrowOnUnmappableChar = true, SetLastError = true)]
public static extern SafeFindHandle FindFirstFile(
[MarshalAs(UnmanagedType.LPTStr)]
string fileName,
[In, Out] FindData findFileData
);
//HANDLE WINAPI FindFirstFileEx(
// _In_ LPCTSTR lpFileName,
// _In_ FINDEX_INFO_LEVELS fInfoLevelId,
// _Out_ LPVOID lpFindFileData,
// _In_ FINDEX_SEARCH_OPS fSearchOp,
// _Reserved_ LPVOID lpSearchFilter,
// _In_ DWORD dwAdditionalFlags
//);
[DllImport(Kernel32Dll, CharSet = CharSet.Unicode, BestFitMapping = false, ThrowOnUnmappableChar = true, SetLastError = true)]
public static extern SafeFindHandle FindFirstFileEx(
[MarshalAs(UnmanagedType.LPTStr)]
string fileName,
[In] FindInfoLevel fInfoLevelId,
[In, Out] FindData lpFindFileData,
[In] FindSearchOps fSearchOp,
IntPtr lpSearchFilter,
[In] FindFlags dwAdditionalFlags
);
[DllImport(Kernel32Dll, CharSet = CharSet.Unicode, BestFitMapping = false, ThrowOnUnmappableChar = true, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool FindNextFile(SafeFindHandle hFindFile, [In, Out] FindData lpFindFileData);
[DllImport(Kernel32Dll, CharSet = CharSet.Unicode, BestFitMapping = false, ThrowOnUnmappableChar = true, SetLastError = true)]
public static extern int GetFileAttributes(string lpFileName);
[DllImport(Kernel32Dll, CharSet = CharSet.Unicode, BestFitMapping = false, ThrowOnUnmappableChar = true, SetLastError = true)]
public static extern uint GetFullPathName(
[MarshalAs(UnmanagedType.LPTStr)]
string lpFileName,
uint nBufferLength,
[Out]
System.Text.StringBuilder lpBuffer,
System.Text.StringBuilder lpFilePart
);
}
//for mapping to the WIN32_FIND_DATA native structure
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public sealed class FindData
{
// NOTE:
// Although it may seem correct to Marshal the string members of this class as UnmanagedType.LPWStr, they
// must explicitly remain UnmanagedType.ByValTStr with the size constraints noted. Otherwise we end up with
// COM Interop exceptions while trying to marshal the data across the PInvoke boundaries.
public int fileAttributes;
public System.Runtime.InteropServices.ComTypes.FILETIME creationTime;
public System.Runtime.InteropServices.ComTypes.FILETIME lastAccessTime;
public System.Runtime.InteropServices.ComTypes.FILETIME lastWriteTime;
public int nFileSizeHigh;
public int nFileSizeLow;
public int dwReserved0;
public int dwReserved1;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string fileName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
public string alternateFileName;
}
//A Win32 safe find handle in which a return value of -1 indicates it's invalid
public sealed class SafeFindHandle : Microsoft.Win32.SafeHandles.SafeHandleMinusOneIsInvalid
{
public SafeFindHandle()
: base(true)
{
return;
}
[System.Runtime.ConstrainedExecution.ReliabilityContract(System.Runtime.ConstrainedExecution.Consistency.WillNotCorruptState, System.Runtime.ConstrainedExecution.Cer.Success)]
protected override bool ReleaseHandle()
{
return NativeMethods.FindClose(handle);
}
}
// TODO: UPDATE THIS BASED ON: https://msdn.microsoft.com/en-us/library/windows/desktop/gg258117(v=vs.85).aspx
[Flags]
public enum Attributes : uint
{
None = 0x00000000,
Readonly = 0x00000001,
Hidden = 0x00000002,
System = 0x00000004,
Directory = 0x00000010,
Archive = 0x00000020,
Device = 0x00000040,
Normal = 0x00000080,
Temporary = 0x00000100,
SparseFile = 0x00000200,
ReparsePoint = 0x00000400,
Compressed = 0x00000800,
Offline = 0x00001000,
NotContentIndexed = 0x00002000,
Encrypted = 0x00004000,
Write_Through = 0x80000000,
Overlapped = 0x40000000,
NoBuffering = 0x20000000,
RandomAccess = 0x10000000,
SequentialScan = 0x08000000,
DeleteOnClose = 0x04000000,
BackupSemantics = 0x02000000,
PosixSemantics = 0x01000000,
OpenReparsePoint = 0x00200000,
OpenNoRecall = 0x00100000,
FirstPipeInstance = 0x00080000
}
[Flags]
public enum FindFlags
{
None = 0,
CaseSensitive = 1,
LargeFetch = 2,
}
public enum FindInfoLevel
{
Standard = 0,
Basic = 1,
}
public enum FindSearchOps
{
NameMatch = 0,
LimitToDirectories = 1,
LimitToDevices = 2,
}
}
'@

Просмотреть файл

@ -0,0 +1,79 @@
# TODO: It would be better if the Out-Default function resolved the underlying Out-Default
# command in the begin block. This would allow for supporting other modules that override
# Out-Default.
$script:outDefaultCmdlet = $ExecutionContext.InvokeCommand.GetCmdlet("Microsoft.PowerShell.Core\Out-Default")
########################################
# Public functions.
########################################
function Out-Default {
[CmdletBinding(ConfirmImpact = "Medium")]
param(
[Parameter(ValueFromPipeline = $true)]
[System.Management.Automation.PSObject]$InputObject)
begin {
#Write-Host '[Entering Begin Out-Default]'
$__sp = { & $script:outDefaultCmdlet @PSBoundParameters }.GetSteppablePipeline()
$__sp.Begin($pscmdlet)
#Write-Host '[Leaving Begin Out-Default]'
}
process {
#Write-Host '[Entering Process Out-Default]'
if ($_ -is [System.Management.Automation.ErrorRecord]) {
Write-Verbose -Message 'Error record:' 4>&1 | Out-Default
Write-Verbose -Message (Remove-TrailingNewLine (Out-String -InputObject $_ -Width 2147483647)) 4>&1 | Out-Default
Write-Verbose -Message 'Script stack trace:' 4>&1 | Out-Default
Write-Verbose -Message "$($_.ScriptStackTrace)" 4>&1 | Out-Default
Write-Verbose -Message 'Exception:' 4>&1 | Out-Default
Write-Verbose -Message $_.Exception.ToString() 4>&1 | Out-Default
Write-TaskError -Message $_.Exception.Message
} elseif ($_ -is [System.Management.Automation.WarningRecord]) {
Write-TaskWarning -Message (Remove-TrailingNewLine (Out-String -InputObject $_ -Width 2147483647))
} elseif ($_ -is [System.Management.Automation.VerboseRecord]) {
foreach ($private:str in (Format-DebugMessage -Object $_)) {
Write-TaskVerbose -Message $private:str
}
} elseif ($_ -is [System.Management.Automation.DebugRecord]) {
foreach ($private:str in (Format-DebugMessage -Object $_)) {
Write-TaskDebug -Message $private:str
}
} else {
# TODO: Consider using out-string here to control the width. As a security precaution it would actually be best to set it to max so wrapping doesn't interfere with secret masking.
$__sp.Process($_)
}
#Write-Host '[Leaving Process Out-Default]'
}
end {
#Write-Host '[Entering End Out-Default]'
$__sp.End()
#Write-Host '[Leaving End Out-Default]'
}
}
########################################
# Private functions.
########################################
function Format-DebugMessage {
[CmdletBinding()]
param([psobject]$Object)
$private:str = Out-String -InputObject $Object -Width 2147483647
$private:str = Remove-TrailingNewLine $private:str
"$private:str".Replace("`r`n", "`n").Replace("`r", "`n").Split("`n"[0])
}
function Remove-TrailingNewLine {
[CmdletBinding()]
param($Str)
if ([object]::ReferenceEquals($Str, $null)) {
return $Str
} elseif ($Str.EndsWith("`r`n")) {
return $Str.Substring(0, $Str.Length - 2)
} else {
return $Str
}
}

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,549 @@
<#
.SYNOPSIS
Gets assembly reference information.
.DESCRIPTION
Not supported for use during task exection. This function is only intended to help developers resolve the minimal set of DLLs that need to be bundled when consuming the VSTS REST SDK or TFS Extended Client SDK. The interface and output may change between patch releases of the VSTS Task SDK.
Only a subset of the referenced assemblies may actually be required, depending on the functionality used by your task. It is best to bundle only the DLLs required for your scenario.
Walks an assembly's references to determine all of it's dependencies. Also walks the references of the dependencies, and so on until all nested dependencies have been traversed. Dependencies are searched for in the directory of the specified assembly. NET Framework assemblies are omitted.
See https://github.com/Microsoft/vsts-task-lib/tree/master/powershell/Docs/UsingOM.md for reliable usage when working with the TFS extended client SDK from a task.
.PARAMETER LiteralPath
Assembly to walk.
.EXAMPLE
Get-VstsAssemblyReference -LiteralPath C:\nuget\microsoft.teamfoundationserver.client.14.102.0\lib\net45\Microsoft.TeamFoundation.Build2.WebApi.dll
#>
function Get-AssemblyReference {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$LiteralPath)
$ErrorActionPreference = 'Stop'
Write-Warning "Not supported for use during task exection. This function is only intended to help developers resolve the minimal set of DLLs that need to be bundled when consuming the VSTS REST SDK or TFS Extended Client SDK. The interface and output may change between patch releases of the VSTS Task SDK."
Write-Output ''
Write-Warning "Only a subset of the referenced assemblies may actually be required, depending on the functionality used by your task. It is best to bundle only the DLLs required for your scenario."
$directory = [System.IO.Path]::GetDirectoryName($LiteralPath)
$hashtable = @{ }
$queue = @( [System.Reflection.Assembly]::ReflectionOnlyLoadFrom($LiteralPath).GetName() )
while ($queue.Count) {
# Add a blank line between assemblies.
Write-Output ''
# Pop.
$assemblyName = $queue[0]
$queue = @( $queue | Select-Object -Skip 1 )
# Attempt to find the assembly in the same directory.
$assembly = $null
$path = "$directory\$($assemblyName.Name).dll"
if ((Test-Path -LiteralPath $path -PathType Leaf)) {
$assembly = [System.Reflection.Assembly]::ReflectionOnlyLoadFrom($path)
} else {
$path = "$directory\$($assemblyName.Name).exe"
if ((Test-Path -LiteralPath $path -PathType Leaf)) {
$assembly = [System.Reflection.Assembly]::ReflectionOnlyLoadFrom($path)
}
}
# Make sure the assembly full name matches, not just the file name.
if ($assembly -and $assembly.GetName().FullName -ne $assemblyName.FullName) {
$assembly = $null
}
# Print the assembly.
if ($assembly) {
Write-Output $assemblyName.FullName
} else {
if ($assemblyName.FullName -eq 'Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed') {
Write-Warning "*** NOT FOUND $($assemblyName.FullName) *** This is an expected condition when using the HTTP clients from the 15.x VSTS REST SDK. Use Get-VstsVssHttpClient to load the HTTP clients (which applies a binding redirect assembly resolver for Newtonsoft.Json). Otherwise you will need to manage the binding redirect yourself."
} else {
Write-Warning "*** NOT FOUND $($assemblyName.FullName) ***"
}
continue
}
# Walk the references.
$refAssemblyNames = @( $assembly.GetReferencedAssemblies() )
for ($i = 0 ; $i -lt $refAssemblyNames.Count ; $i++) {
$refAssemblyName = $refAssemblyNames[$i]
# Skip framework assemblies.
$fxPaths = @(
"$env:windir\Microsoft.Net\Framework64\v4.0.30319\$($refAssemblyName.Name).dll"
"$env:windir\Microsoft.Net\Framework64\v4.0.30319\WPF\$($refAssemblyName.Name).dll"
)
$fxPath = $fxPaths |
Where-Object { Test-Path -LiteralPath $_ -PathType Leaf } |
Where-Object { [System.Reflection.Assembly]::ReflectionOnlyLoadFrom($_).GetName().FullName -eq $refAssemblyName.FullName }
if ($fxPath) {
continue
}
# Print the reference.
Write-Output " $($refAssemblyName.FullName)"
# Add new references to the queue.
if (!$hashtable[$refAssemblyName.FullName]) {
$queue += $refAssemblyName
$hashtable[$refAssemblyName.FullName] = $true
}
}
}
}
<#
.SYNOPSIS
Gets a credentials object that can be used with the TFS extended client SDK.
.DESCRIPTION
The agent job token is used to construct the credentials object. The identity associated with the token depends on the scope selected in the build/release definition (either the project collection build/release service identity, or the project build/release service identity).
Refer to Get-VstsTfsService for a more simple to get a TFS service object.
*** DO NOT USE Agent.ServerOMDirectory *** See https://github.com/Microsoft/vsts-task-lib/tree/master/powershell/Docs/UsingOM.md for reliable usage when working with the TFS extended client SDK from a task.
.PARAMETER OMDirectory
Directory where the extended client object model DLLs are located. If the DLLs for the credential types are not already loaded, an attempt will be made to automatically load the required DLLs from the object model directory.
If not specified, defaults to the directory of the entry script for the task.
*** DO NOT USE Agent.ServerOMDirectory *** See https://github.com/Microsoft/vsts-task-lib/tree/master/powershell/Docs/UsingOM.md for reliable usage when working with the TFS extended client SDK from a task.
.EXAMPLE
#
# Refer to Get-VstsTfsService for a more simple way to get a TFS service object.
#
$credentials = Get-VstsTfsClientCredentials
Add-Type -LiteralPath "$PSScriptRoot\Microsoft.TeamFoundation.VersionControl.Client.dll"
$tfsTeamProjectCollection = New-Object Microsoft.TeamFoundation.Client.TfsTeamProjectCollection(
(Get-VstsTaskVariable -Name 'System.TeamFoundationCollectionUri' -Require),
$credentials)
$versionControlServer = $tfsTeamProjectCollection.GetService([Microsoft.TeamFoundation.VersionControl.Client.VersionControlServer])
$versionControlServer.GetItems('$/*').Items | Format-List
#>
function Get-TfsClientCredentials {
[CmdletBinding()]
param([string]$OMDirectory)
Trace-EnteringInvocation -InvocationInfo $MyInvocation
$originalErrorActionPreference = $ErrorActionPreference
try {
$ErrorActionPreference = 'Stop'
# Get the endpoint.
$endpoint = Get-Endpoint -Name SystemVssConnection -Require
# Validate the type can be found.
$null = Get-OMType -TypeName 'Microsoft.TeamFoundation.Client.TfsClientCredentials' -OMKind 'ExtendedClient' -OMDirectory $OMDirectory -Require
# Construct the credentials.
$credentials = New-Object Microsoft.TeamFoundation.Client.TfsClientCredentials($false) # Do not use default credentials.
$credentials.AllowInteractive = $false
$credentials.Federated = New-Object Microsoft.TeamFoundation.Client.OAuthTokenCredential([string]$endpoint.auth.parameters.AccessToken)
return $credentials
} catch {
$ErrorActionPreference = $originalErrorActionPreference
Write-Error $_
} finally {
Trace-LeavingInvocation -InvocationInfo $MyInvocation
}
}
<#
.SYNOPSIS
Gets a TFS extended client service.
.DESCRIPTION
Gets an instance of an ITfsTeamProjectCollectionObject.
*** DO NOT USE Agent.ServerOMDirectory *** See https://github.com/Microsoft/vsts-task-lib/tree/master/powershell/Docs/UsingOM.md for reliable usage when working with the TFS extended client SDK from a task.
.PARAMETER TypeName
Namespace-qualified type name of the service to get.
.PARAMETER OMDirectory
Directory where the extended client object model DLLs are located. If the DLLs for the types are not already loaded, an attempt will be made to automatically load the required DLLs from the object model directory.
If not specified, defaults to the directory of the entry script for the task.
*** DO NOT USE Agent.ServerOMDirectory *** See https://github.com/Microsoft/vsts-task-lib/tree/master/powershell/Docs/UsingOM.md for reliable usage when working with the TFS extended client SDK from a task.
.PARAMETER Uri
URI to use when initializing the service. If not specified, defaults to System.TeamFoundationCollectionUri.
.PARAMETER TfsClientCredentials
Credentials to use when intializing the service. If not specified, the default uses the agent job token to construct the credentials object. The identity associated with the token depends on the scope selected in the build/release definition (either the project collection build/release service identity, or the project build/release service identity).
.EXAMPLE
$versionControlServer = Get-VstsTfsService -TypeName Microsoft.TeamFoundation.VersionControl.Client.VersionControlServer
$versionControlServer.GetItems('$/*').Items | Format-List
#>
function Get-TfsService {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$TypeName,
[string]$OMDirectory,
[string]$Uri,
$TfsClientCredentials)
Trace-EnteringInvocation -InvocationInfo $MyInvocation
$originalErrorActionPreference = $ErrorActionPreference
try {
$ErrorActionPreference = 'Stop'
# Default the URI to the collection URI.
if (!$Uri) {
$Uri = Get-TaskVariable -Name System.TeamFoundationCollectionUri -Require
}
# Default the credentials.
if (!$TfsClientCredentials) {
$TfsClientCredentials = Get-TfsClientCredentials -OMDirectory $OMDirectory
}
# Validate the project collection type can be loaded.
$null = Get-OMType -TypeName 'Microsoft.TeamFoundation.Client.TfsTeamProjectCollection' -OMKind 'ExtendedClient' -OMDirectory $OMDirectory -Require
# Load the project collection object.
$tfsTeamProjectCollection = New-Object Microsoft.TeamFoundation.Client.TfsTeamProjectCollection($Uri, $TfsClientCredentials)
# Validate the requested type can be loaded.
$type = Get-OMType -TypeName $TypeName -OMKind 'ExtendedClient' -OMDirectory $OMDirectory -Require
# Return the service object.
return $tfsTeamProjectCollection.GetService($type)
} catch {
$ErrorActionPreference = $originalErrorActionPreference
Write-Error $_
} finally {
Trace-LeavingInvocation -InvocationInfo $MyInvocation
}
}
<#
.SYNOPSIS
Gets a credentials object that can be used with the VSTS REST SDK.
.DESCRIPTION
The agent job token is used to construct the credentials object. The identity associated with the token depends on the scope selected in the build/release definition (either the project collection build/release service identity, or the project service build/release identity).
Refer to Get-VstsVssHttpClient for a more simple to get a VSS HTTP client.
*** DO NOT USE Agent.ServerOMDirectory *** See https://github.com/Microsoft/vsts-task-lib/tree/master/powershell/Docs/UsingOM.md for reliable usage when working with the VSTS REST SDK from a task.
.PARAMETER OMDirectory
Directory where the REST client object model DLLs are located. If the DLLs for the credential types are not already loaded, an attempt will be made to automatically load the required DLLs from the object model directory.
If not specified, defaults to the directory of the entry script for the task.
*** DO NOT USE Agent.ServerOMDirectory *** See https://github.com/Microsoft/vsts-task-lib/tree/master/powershell/Docs/UsingOM.md for reliable usage when working with the VSTS REST SDK from a task.
.EXAMPLE
#
# Refer to Get-VstsTfsService for a more simple way to get a TFS service object.
#
# This example works using the 14.x .NET SDK. A Newtonsoft.Json 6.0 to 8.0 binding
# redirect may be required when working with the 15.x SDK. Or use Get-VstsVssHttpClient
# to avoid managing the binding redirect.
#
$vssCredentials = Get-VstsVssCredentials
$collectionUrl = New-Object System.Uri((Get-VstsTaskVariable -Name 'System.TeamFoundationCollectionUri' -Require))
Add-Type -LiteralPath "$PSScriptRoot\Microsoft.TeamFoundation.Core.WebApi.dll"
$projectHttpClient = New-Object Microsoft.TeamFoundation.Core.WebApi.ProjectHttpClient($collectionUrl, $vssCredentials)
$projectHttpClient.GetProjects().Result
#>
function Get-VssCredentials {
[CmdletBinding()]
param([string]$OMDirectory)
Trace-EnteringInvocation -InvocationInfo $MyInvocation
$originalErrorActionPreference = $ErrorActionPreference
try {
$ErrorActionPreference = 'Stop'
# Get the endpoint.
$endpoint = Get-Endpoint -Name SystemVssConnection -Require
# Check if the VssOAuthAccessTokenCredential type is available.
if ((Get-OMType -TypeName 'Microsoft.VisualStudio.Services.OAuth.VssOAuthAccessTokenCredential' -OMKind 'WebApi' -OMDirectory $OMDirectory)) {
# Create the federated credential.
$federatedCredential = New-Object Microsoft.VisualStudio.Services.OAuth.VssOAuthAccessTokenCredential($endpoint.auth.parameters.AccessToken)
} else {
# Validate the fallback type can be loaded.
$null = Get-OMType -TypeName 'Microsoft.VisualStudio.Services.Client.VssOAuthCredential' -OMKind 'WebApi' -OMDirectory $OMDirectory -Require
# Create the federated credential.
$federatedCredential = New-Object Microsoft.VisualStudio.Services.Client.VssOAuthCredential($endpoint.auth.parameters.AccessToken)
}
# Return the credentials.
return New-Object Microsoft.VisualStudio.Services.Common.VssCredentials(
(New-Object Microsoft.VisualStudio.Services.Common.WindowsCredential($false)), # Do not use default credentials.
$federatedCredential,
[Microsoft.VisualStudio.Services.Common.CredentialPromptType]::DoNotPrompt)
} catch {
$ErrorActionPreference = $originalErrorActionPreference
Write-Error $_
} finally {
Trace-LeavingInvocation -InvocationInfo $MyInvocation
}
}
<#
.SYNOPSIS
Gets a VSS HTTP client.
.DESCRIPTION
Gets an instance of an VSS HTTP client.
*** DO NOT USE Agent.ServerOMDirectory *** See https://github.com/Microsoft/vsts-task-lib/tree/master/powershell/Docs/UsingOM.md for reliable usage when working with the VSTS REST SDK from a task.
.PARAMETER TypeName
Namespace-qualified type name of the HTTP client to get.
.PARAMETER OMDirectory
Directory where the REST client object model DLLs are located. If the DLLs for the credential types are not already loaded, an attempt will be made to automatically load the required DLLs from the object model directory.
If not specified, defaults to the directory of the entry script for the task.
*** DO NOT USE Agent.ServerOMDirectory *** See https://github.com/Microsoft/vsts-task-lib/tree/master/powershell/Docs/UsingOM.md for reliable usage when working with the VSTS REST SDK from a task.
# .PARAMETER Uri
# URI to use when initializing the HTTP client. If not specified, defaults to System.TeamFoundationCollectionUri.
# .PARAMETER VssCredentials
# Credentials to use when intializing the HTTP client. If not specified, the default uses the agent job token to construct the credentials object. The identity associated with the token depends on the scope selected in the build/release definition (either the project collection build/release service identity, or the project build/release service identity).
.EXAMPLE
$projectHttpClient = Get-VstsVssHttpClient -TypeName Microsoft.TeamFoundation.Core.WebApi.ProjectHttpClient
$projectHttpClient.GetProjects().Result
#>
function Get-VssHttpClient {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$TypeName,
[string]$OMDirectory,
[string]$Uri,
$VssCredentials)
Trace-EnteringInvocation -InvocationInfo $MyInvocation
$originalErrorActionPreference = $ErrorActionPreference
try {
$ErrorActionPreference = 'Stop'
# Default the URI to the collection URI.
if (!$Uri) {
$Uri = Get-TaskVariable -Name System.TeamFoundationCollectionUri -Require
}
# Cast the URI.
[uri]$Uri = New-Object System.Uri($Uri)
# Default the credentials.
if (!$VssCredentials) {
$VssCredentials = Get-VssCredentials -OMDirectory $OMDirectory
}
# Validate the type can be loaded.
$null = Get-OMType -TypeName $TypeName -OMKind 'WebApi' -OMDirectory $OMDirectory -Require
# Try to construct the HTTP client.
Write-Verbose "Constructing HTTP client."
try {
return New-Object $TypeName($Uri, $VssCredentials)
} catch {
# Rethrow if the exception is not due to Newtonsoft.Json DLL not found.
if ($_.Exception.InnerException -isnot [System.IO.FileNotFoundException] -or
$_.Exception.InnerException.FileName -notlike 'Newtonsoft.Json, *') {
throw
}
# Default the OMDirectory to the directory of the entry script for the task.
if (!$OMDirectory) {
$OMDirectory = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..")
Write-Verbose "Defaulted OM directory to: '$OMDirectory'"
}
# Test if the Newtonsoft.Json DLL exists in the OM directory.
$newtonsoftDll = [System.IO.Path]::Combine($OMDirectory, "Newtonsoft.Json.dll")
Write-Verbose "Testing file path: '$newtonsoftDll'"
if (!(Test-Path -LiteralPath $newtonsoftDll -PathType Leaf)) {
Write-Verbose 'Not found. Rethrowing exception.'
throw
}
# Add a binding redirect and try again. Parts of the Dev15 preview SDK have a
# dependency on the 6.0.0.0 Newtonsoft.Json DLL, while other parts reference
# the 8.0.0.0 Newtonsoft.Json DLL.
Write-Verbose "Adding assembly resolver."
$onAssemblyResolve = [System.ResolveEventHandler]{
param($sender, $e)
if ($e.Name -like 'Newtonsoft.Json, *') {
Write-Verbose "Resolving '$($e.Name)'"
return [System.Reflection.Assembly]::LoadFrom($newtonsoftDll)
}
Write-Verbose "Unable to resolve assembly name '$($e.Name)'"
return $null
}
[System.AppDomain]::CurrentDomain.add_AssemblyResolve($onAssemblyResolve)
try {
# Try again to construct the HTTP client.
Write-Verbose "Trying again to construct the HTTP client."
return New-Object $TypeName($Uri, $VssCredentials)
} finally {
# Unregister the assembly resolver.
Write-Verbose "Removing assemlby resolver."
[System.AppDomain]::CurrentDomain.remove_AssemblyResolve($onAssemblyResolve)
}
}
} catch {
$ErrorActionPreference = $originalErrorActionPreference
Write-Error $_
} finally {
Trace-LeavingInvocation -InvocationInfo $MyInvocation
}
}
########################################
# Private functions.
########################################
function Get-OMType {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$TypeName,
[ValidateSet('ExtendedClient', 'WebApi')]
[Parameter(Mandatory = $true)]
[string]$OMKind,
[string]$OMDirectory,
[switch]$Require)
Trace-EnteringInvocation -InvocationInfo $MyInvocation
try {
# Default the OMDirectory to the directory of the entry script for the task.
if (!$OMDirectory) {
$OMDirectory = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..")
Write-Verbose "Defaulted OM directory to: '$OMDirectory'"
}
# Try to load the type.
$errorRecord = $null
Write-Verbose "Testing whether type can be loaded: '$TypeName'"
$ErrorActionPreference = 'Ignore'
try {
# Failure when attempting to cast a string to a type, transfers control to the
# catch handler even when the error action preference is ignore. The error action
# is set to Ignore so the $Error variable is not polluted.
$type = [type]$TypeName
# Success.
Write-Verbose "The type was loaded successfully."
return $type
} catch {
# Store the error record.
$errorRecord = $_
}
$ErrorActionPreference = 'Stop'
Write-Verbose "The type was not loaded."
# Build a list of candidate DLL file paths from the namespace.
$dllPaths = @( )
$namespace = $TypeName
while ($namespace.LastIndexOf('.') -gt 0) {
# Trim the next segment from the namespace.
$namespace = $namespace.SubString(0, $namespace.LastIndexOf('.'))
# Derive potential DLL file paths based on the namespace and OM kind (i.e. extended client vs web API).
if ($OMKind -eq 'ExtendedClient') {
if ($namespace -like 'Microsoft.TeamFoundation.*') {
$dllPaths += [System.IO.Path]::Combine($OMDirectory, "$namespace.dll")
}
} else {
if ($namespace -like 'Microsoft.TeamFoundation.*' -or
$namespace -like 'Microsoft.VisualStudio.Services' -or
$namespace -like 'Microsoft.VisualStudio.Services.*') {
$dllPaths += [System.IO.Path]::Combine($OMDirectory, "$namespace.WebApi.dll")
$dllPaths += [System.IO.Path]::Combine($OMDirectory, "$namespace.dll")
}
}
}
foreach ($dllPath in $dllPaths) {
# Check whether the DLL exists.
Write-Verbose "Testing leaf path: '$dllPath'"
if (!(Test-Path -PathType Leaf -LiteralPath "$dllPath")) {
Write-Verbose "Not found."
continue
}
# Load the DLL.
Write-Verbose "Loading assembly: $dllPath"
try {
Add-Type -LiteralPath $dllPath
} catch {
# Write the information to the verbose stream and proceed to attempt to load the requested type.
#
# The requested type may successfully load now. For example, the type used with the 14.0 Web API for the
# federated credential (VssOAuthCredential) resides in Microsoft.VisualStudio.Services.Client.dll. Even
# though loading the DLL results in a ReflectionTypeLoadException when Microsoft.ServiceBus.dll (approx 3.75mb)
# is not present, enough types are loaded to use the VssOAuthCredential federated credential with the Web API
# HTTP clients.
Write-Verbose "$($_.Exception.GetType().FullName): $($_.Exception.Message)"
if ($_.Exception -is [System.Reflection.ReflectionTypeLoadException]) {
for ($i = 0 ; $i -lt $_.Exception.LoaderExceptions.Length ; $i++) {
$loaderException = $_.Exception.LoaderExceptions[$i]
Write-Verbose "LoaderExceptions[$i]: $($loaderException.GetType().FullName): $($loaderException.Message)"
}
}
}
# Try to load the type.
Write-Verbose "Testing whether type can be loaded: '$TypeName'"
$ErrorActionPreference = 'Ignore'
try {
# Failure when attempting to cast a string to a type, transfers control to the
# catch handler even when the error action preference is ignore. The error action
# is set to Ignore so the $Error variable is not polluted.
$type = [type]$TypeName
# Success.
Write-Verbose "The type was loaded successfully."
return $type
} catch {
$errorRecord = $_
}
$ErrorActionPreference = 'Stop'
Write-Verbose "The type was not loaded."
}
# Check whether to propagate the error.
if ($Require) {
Write-Error $errorRecord
}
} finally {
Trace-LeavingInvocation -InvocationInfo $MyInvocation
}
}

Просмотреть файл

@ -0,0 +1,17 @@
{
"loc.messages.PSLIB_ContainerPathNotFound0": "Der Containerpfad wurde nicht gefunden: \"{0}\".",
"loc.messages.PSLIB_EndpointAuth0": "\"{0}\"-Dienstendpunkt-Anmeldeinformationen",
"loc.messages.PSLIB_EndpointUrl0": "\"{0}\"-Dienstendpunkt-URL",
"loc.messages.PSLIB_EnumeratingSubdirectoriesFailedForPath0": "Fehler beim Aufzählen von Unterverzeichnissen für den folgenden Pfad: \"{0}\"",
"loc.messages.PSLIB_FileNotFound0": "Die Datei wurde nicht gefunden: \"{0}\".",
"loc.messages.PSLIB_Input0": "\"{0}\"-Eingabe",
"loc.messages.PSLIB_InvalidPattern0": "Ungültiges Muster: \"{0}\"",
"loc.messages.PSLIB_LeafPathNotFound0": "Der Blattpfad wurde nicht gefunden: \"{0}\".",
"loc.messages.PSLIB_PathLengthNotReturnedFor0": "Fehler bei der Normalisierung bzw. Erweiterung des Pfads. Die Pfadlänge wurde vom Kernel32-Subsystem nicht zurückgegeben für: \"{0}\"",
"loc.messages.PSLIB_PathNotFound0": "Der Pfad wurde nicht gefunden: \"{0}\".",
"loc.messages.PSLIB_Process0ExitedWithCode1": "Der Prozess \"{0}\" wurde mit dem Code \"{1}\" beendet.",
"loc.messages.PSLIB_Required0": "Erforderlich: {0}",
"loc.messages.PSLIB_StringFormatFailed": "Fehler beim Zeichenfolgenformat.",
"loc.messages.PSLIB_StringResourceKeyNotFound0": "Der Zeichenfolgen-Ressourcenschlüssel wurde nicht gefunden: \"{0}\".",
"loc.messages.PSLIB_TaskVariable0": "\"{0}\"-Taskvariable"
}

Просмотреть файл

@ -0,0 +1,17 @@
{
"loc.messages.PSLIB_ContainerPathNotFound0": "Container path not found: '{0}'",
"loc.messages.PSLIB_EndpointAuth0": "'{0}' service endpoint credentials",
"loc.messages.PSLIB_EndpointUrl0": "'{0}' service endpoint URL",
"loc.messages.PSLIB_EnumeratingSubdirectoriesFailedForPath0": "Enumerating subdirectories failed for path: '{0}'",
"loc.messages.PSLIB_FileNotFound0": "File not found: '{0}'",
"loc.messages.PSLIB_Input0": "'{0}' input",
"loc.messages.PSLIB_InvalidPattern0": "Invalid pattern: '{0}'",
"loc.messages.PSLIB_LeafPathNotFound0": "Leaf path not found: '{0}'",
"loc.messages.PSLIB_PathLengthNotReturnedFor0": "Path normalization/expansion failed. The path length was not returned by the Kernel32 subsystem for: '{0}'",
"loc.messages.PSLIB_PathNotFound0": "Path not found: '{0}'",
"loc.messages.PSLIB_Process0ExitedWithCode1": "Process '{0}' exited with code '{1}'.",
"loc.messages.PSLIB_Required0": "Required: {0}",
"loc.messages.PSLIB_StringFormatFailed": "String format failed.",
"loc.messages.PSLIB_StringResourceKeyNotFound0": "String resource key not found: '{0}'",
"loc.messages.PSLIB_TaskVariable0": "'{0}' task variable"
}

Просмотреть файл

@ -0,0 +1,17 @@
{
"loc.messages.PSLIB_ContainerPathNotFound0": "No se encuentra la ruta de acceso del contenedor: '{0}'",
"loc.messages.PSLIB_EndpointAuth0": "Credenciales del punto de conexión de servicio '{0}'",
"loc.messages.PSLIB_EndpointUrl0": "URL del punto de conexión de servicio '{0}'",
"loc.messages.PSLIB_EnumeratingSubdirectoriesFailedForPath0": "No se pudieron enumerar los subdirectorios de la ruta de acceso: '{0}'",
"loc.messages.PSLIB_FileNotFound0": "Archivo no encontrado: '{0}'",
"loc.messages.PSLIB_Input0": "Entrada '{0}'",
"loc.messages.PSLIB_InvalidPattern0": "Patrón no válido: '{0}'",
"loc.messages.PSLIB_LeafPathNotFound0": "No se encuentra la ruta de acceso de la hoja: '{0}'",
"loc.messages.PSLIB_PathLengthNotReturnedFor0": "No se pudo normalizar o expandir la ruta de acceso. El subsistema Kernel32 no devolvió la longitud de la ruta de acceso para: '{0}'",
"loc.messages.PSLIB_PathNotFound0": "No se encuentra la ruta de acceso: '{0}'",
"loc.messages.PSLIB_Process0ExitedWithCode1": "El proceso '{0}' finalizó con el código '{1}'.",
"loc.messages.PSLIB_Required0": "Se requiere: {0}",
"loc.messages.PSLIB_StringFormatFailed": "Error de formato de cadena.",
"loc.messages.PSLIB_StringResourceKeyNotFound0": "No se encuentra la clave de recurso de la cadena: '{0}'",
"loc.messages.PSLIB_TaskVariable0": "Variable de tarea '{0}'"
}

Просмотреть файл

@ -0,0 +1,17 @@
{
"loc.messages.PSLIB_ContainerPathNotFound0": "Le chemin du conteneur est introuvable : '{0}'",
"loc.messages.PSLIB_EndpointAuth0": "Informations d'identification du point de terminaison de service '{0}'",
"loc.messages.PSLIB_EndpointUrl0": "URL du point de terminaison de service '{0}'",
"loc.messages.PSLIB_EnumeratingSubdirectoriesFailedForPath0": "Échec de l'énumération des sous-répertoires pour le chemin : '{0}'",
"loc.messages.PSLIB_FileNotFound0": "Fichier introuvable : {0}.",
"loc.messages.PSLIB_Input0": "Entrée '{0}'",
"loc.messages.PSLIB_InvalidPattern0": "Modèle non valide : '{0}'",
"loc.messages.PSLIB_LeafPathNotFound0": "Le chemin feuille est introuvable : '{0}'",
"loc.messages.PSLIB_PathLengthNotReturnedFor0": "Échec de la normalisation/l'expansion du chemin. La longueur du chemin n'a pas été retournée par le sous-système Kernel32 pour : '{0}'",
"loc.messages.PSLIB_PathNotFound0": "Chemin introuvable : '{0}'",
"loc.messages.PSLIB_Process0ExitedWithCode1": "Le processus '{0}' s'est arrêté avec le code '{1}'.",
"loc.messages.PSLIB_Required0": "Obligatoire : {0}",
"loc.messages.PSLIB_StringFormatFailed": "Échec du format de la chaîne.",
"loc.messages.PSLIB_StringResourceKeyNotFound0": "Clé de la ressource de type chaîne introuvable : '{0}'",
"loc.messages.PSLIB_TaskVariable0": "Variable de tâche '{0}'"
}

Просмотреть файл

@ -0,0 +1,17 @@
{
"loc.messages.PSLIB_ContainerPathNotFound0": "Percorso del contenitore non trovato: '{0}'",
"loc.messages.PSLIB_EndpointAuth0": "Credenziali dell'endpoint servizio '{0}'",
"loc.messages.PSLIB_EndpointUrl0": "URL dell'endpoint servizio '{0}'",
"loc.messages.PSLIB_EnumeratingSubdirectoriesFailedForPath0": "L'enumerazione delle sottodirectory per il percorso '{0}' non è riuscita",
"loc.messages.PSLIB_FileNotFound0": "File non trovato: '{0}'",
"loc.messages.PSLIB_Input0": "Input di '{0}'",
"loc.messages.PSLIB_InvalidPattern0": "Criterio non valido: '{0}'",
"loc.messages.PSLIB_LeafPathNotFound0": "Percorso foglia non trovato: '{0}'",
"loc.messages.PSLIB_PathLengthNotReturnedFor0": "La normalizzazione o l'espansione del percorso non è riuscita. Il sottosistema Kernel32 non ha restituito la lunghezza del percorso per '{0}'",
"loc.messages.PSLIB_PathNotFound0": "Percorso non trovato: '{0}'",
"loc.messages.PSLIB_Process0ExitedWithCode1": "Il processo '{0}' è stato terminato ed è stato restituito il codice '{1}'.",
"loc.messages.PSLIB_Required0": "Obbligatorio: {0}",
"loc.messages.PSLIB_StringFormatFailed": "Errore nel formato della stringa.",
"loc.messages.PSLIB_StringResourceKeyNotFound0": "La chiave della risorsa stringa non è stata trovata: '{0}'",
"loc.messages.PSLIB_TaskVariable0": "Variabile dell'attività '{0}'"
}

Просмотреть файл

@ -0,0 +1,17 @@
{
"loc.messages.PSLIB_ContainerPathNotFound0": "コンテナーのパスが見つかりません: '{0}'",
"loc.messages.PSLIB_EndpointAuth0": "'{0}' サービス エンドポイントの資格情報",
"loc.messages.PSLIB_EndpointUrl0": "'{0}' サービス エンドポイントの URL",
"loc.messages.PSLIB_EnumeratingSubdirectoriesFailedForPath0": "パス '{0}' のサブディレクトリを列挙できませんでした",
"loc.messages.PSLIB_FileNotFound0": "ファイルが見つかりません: '{0}'",
"loc.messages.PSLIB_Input0": "'{0}' 入力",
"loc.messages.PSLIB_InvalidPattern0": "使用できないパターンです: '{0}'",
"loc.messages.PSLIB_LeafPathNotFound0": "リーフ パスが見つかりません: '{0}'",
"loc.messages.PSLIB_PathLengthNotReturnedFor0": "パスの正規化/展開に失敗しました。Kernel32 サブシステムからパス '{0}' の長さが返されませんでした",
"loc.messages.PSLIB_PathNotFound0": "パスが見つかりません: '{0}'",
"loc.messages.PSLIB_Process0ExitedWithCode1": "プロセス '{0}' がコード '{1}' で終了しました。",
"loc.messages.PSLIB_Required0": "必要: {0}",
"loc.messages.PSLIB_StringFormatFailed": "文字列のフォーマットに失敗しました。",
"loc.messages.PSLIB_StringResourceKeyNotFound0": "文字列のリソース キーが見つかりません: '{0}'",
"loc.messages.PSLIB_TaskVariable0": "'{0}' タスク変数"
}

Просмотреть файл

@ -0,0 +1,17 @@
{
"loc.messages.PSLIB_ContainerPathNotFound0": "컨테이너 경로를 찾을 수 없음: '{0}'",
"loc.messages.PSLIB_EndpointAuth0": "'{0}' 서비스 끝점 자격 증명",
"loc.messages.PSLIB_EndpointUrl0": "'{0}' 서비스 끝점 URL",
"loc.messages.PSLIB_EnumeratingSubdirectoriesFailedForPath0": "경로에 대해 하위 디렉터리를 열거하지 못함: '{0}'",
"loc.messages.PSLIB_FileNotFound0": "{0} 파일을 찾을 수 없습니다.",
"loc.messages.PSLIB_Input0": "'{0}' 입력",
"loc.messages.PSLIB_InvalidPattern0": "잘못된 패턴: '{0}'",
"loc.messages.PSLIB_LeafPathNotFound0": "Leaf 경로를 찾을 수 없음: '{0}'",
"loc.messages.PSLIB_PathLengthNotReturnedFor0": "경로 정규화/확장에 실패했습니다. 다음에 대해 Kernel32 subsystem에서 경로 길이를 반환하지 않음: '{0}'",
"loc.messages.PSLIB_PathNotFound0": "경로를 찾을 수 없음: '{0}'",
"loc.messages.PSLIB_Process0ExitedWithCode1": "'{1}' 코드로 '{0}' 프로세스가 종료되었습니다.",
"loc.messages.PSLIB_Required0": "필수: {0}",
"loc.messages.PSLIB_StringFormatFailed": "문자열을 포맷하지 못했습니다.",
"loc.messages.PSLIB_StringResourceKeyNotFound0": "문자열 리소스 키를 찾을 수 없음: '{0}'",
"loc.messages.PSLIB_TaskVariable0": "'{0}' 작업 변수"
}

Просмотреть файл

@ -0,0 +1,17 @@
{
"loc.messages.PSLIB_ContainerPathNotFound0": "Путь к контейнеру не найден: \"{0}\".",
"loc.messages.PSLIB_EndpointAuth0": "Учетные данные конечной точки службы \"{0}\"",
"loc.messages.PSLIB_EndpointUrl0": "URL-адрес конечной точки службы \"{0}\"",
"loc.messages.PSLIB_EnumeratingSubdirectoriesFailedForPath0": "Сбой перечисления подкаталогов для пути: \"{0}\".",
"loc.messages.PSLIB_FileNotFound0": "Файл не найден: \"{0}\".",
"loc.messages.PSLIB_Input0": "Входные данные \"{0}\".",
"loc.messages.PSLIB_InvalidPattern0": "Недопустимый шаблон: \"{0}\".",
"loc.messages.PSLIB_LeafPathNotFound0": "Путь к конечному объекту не найден: \"{0}\".",
"loc.messages.PSLIB_PathLengthNotReturnedFor0": "Сбой нормализации и расширения пути. Длина пути не была возвращена подсистемой Kernel32 для: \"{0}\".",
"loc.messages.PSLIB_PathNotFound0": "Путь не найден: \"{0}\".",
"loc.messages.PSLIB_Process0ExitedWithCode1": "Процесс \"{0}\" завершил работу с кодом \"{1}\".",
"loc.messages.PSLIB_Required0": "Требуется: {0}",
"loc.messages.PSLIB_StringFormatFailed": "Сбой формата строки.",
"loc.messages.PSLIB_StringResourceKeyNotFound0": "Ключ ресурса строки не найден: \"{0}\".",
"loc.messages.PSLIB_TaskVariable0": "Переменная задачи \"{0}\""
}

Просмотреть файл

@ -0,0 +1,17 @@
{
"loc.messages.PSLIB_ContainerPathNotFound0": "找不到容器路径:“{0}”",
"loc.messages.PSLIB_EndpointAuth0": "“{0}”服务终结点凭据",
"loc.messages.PSLIB_EndpointUrl0": "“{0}”服务终结点 URL",
"loc.messages.PSLIB_EnumeratingSubdirectoriesFailedForPath0": "枚举路径的子目录失败:“{0}”",
"loc.messages.PSLIB_FileNotFound0": "找不到文件: {0}。",
"loc.messages.PSLIB_Input0": "“{0}”输入",
"loc.messages.PSLIB_InvalidPattern0": "无效的模式:“{0}”",
"loc.messages.PSLIB_LeafPathNotFound0": "找不到叶路径:“{0}”",
"loc.messages.PSLIB_PathLengthNotReturnedFor0": "路径规范化/扩展失败。路径长度不是由“{0}”的 Kernel32 子系统返回的",
"loc.messages.PSLIB_PathNotFound0": "找不到路径:“{0}”",
"loc.messages.PSLIB_Process0ExitedWithCode1": "过程“{0}”已退出,代码为“{1}”。",
"loc.messages.PSLIB_Required0": "必需: {0}",
"loc.messages.PSLIB_StringFormatFailed": "字符串格式无效。",
"loc.messages.PSLIB_StringResourceKeyNotFound0": "找不到字符串资源关键字:“{0}”",
"loc.messages.PSLIB_TaskVariable0": "“{0}”任务变量"
}

Просмотреть файл

@ -0,0 +1,17 @@
{
"loc.messages.PSLIB_ContainerPathNotFound0": "找不到容器路徑: '{0}'",
"loc.messages.PSLIB_EndpointAuth0": "'{0}' 服務端點認證",
"loc.messages.PSLIB_EndpointUrl0": "'{0}' 服務端點 URL",
"loc.messages.PSLIB_EnumeratingSubdirectoriesFailedForPath0": "為路徑列舉子目錄失敗: '{0}'",
"loc.messages.PSLIB_FileNotFound0": "找不到檔案: '{0}'",
"loc.messages.PSLIB_Input0": "'{0}' 輸入",
"loc.messages.PSLIB_InvalidPattern0": "模式無效: '{0}'",
"loc.messages.PSLIB_LeafPathNotFound0": "找不到分葉路徑: '{0}'",
"loc.messages.PSLIB_PathLengthNotReturnedFor0": "路徑正規化/展開失敗。Kernel32 子系統未傳回 '{0}' 的路徑長度",
"loc.messages.PSLIB_PathNotFound0": "找不到路徑: '{0}'",
"loc.messages.PSLIB_Process0ExitedWithCode1": "處理序 '{0}' 以返回碼 '{1}' 結束。",
"loc.messages.PSLIB_Required0": "必要項: {0}",
"loc.messages.PSLIB_StringFormatFailed": "字串格式失敗。",
"loc.messages.PSLIB_StringResourceKeyNotFound0": "找不到字串資源索引鍵: '{0}'",
"loc.messages.PSLIB_TaskVariable0": "'{0}' 工作變數"
}

Просмотреть файл

@ -0,0 +1,99 @@
<#
.SYNOPSIS
Asserts that a path exists. Throws if the path does not exist.
.PARAMETER PassThru
True to return the path.
#>
function Assert-Path {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$LiteralPath,
[Microsoft.PowerShell.Commands.TestPathType]$PathType = [Microsoft.PowerShell.Commands.TestPathType]::Any,
[switch]$PassThru)
if ($PathType -eq [Microsoft.PowerShell.Commands.TestPathType]::Any) {
Write-Verbose "Asserting path exists: '$LiteralPath'"
} else {
Write-Verbose "Asserting $("$PathType".ToLowerInvariant()) path exists: '$LiteralPath'"
}
if (Test-Path -LiteralPath $LiteralPath -PathType $PathType) {
if ($PassThru) {
return $LiteralPath
}
return
}
$resourceKey = switch ($PathType) {
([Microsoft.PowerShell.Commands.TestPathType]::Container) { "PSLIB_ContainerPathNotFound0" ; break }
([Microsoft.PowerShell.Commands.TestPathType]::Leaf) { "PSLIB_LeafPathNotFound0" ; break }
default { "PSLIB_PathNotFound0" }
}
throw (Get-LocString -Key $resourceKey -ArgumentList $LiteralPath)
}
<#
.SYNOPSIS
Executes an external program.
.DESCRIPTION
Executes an external program and waits for the process to exit.
After calling this command, the exit code of the process can be retrieved from the variable $LASTEXITCODE.
.PARAMETER Encoding
This parameter not required for most scenarios. Indicates how to interpret the encoding from the external program. An example use case would be if an external program outputs UTF-16 XML and the output needs to be parsed.
.PARAMETER RequireExitCodeZero
Indicates whether to write an error to the error pipeline if the exit code is not zero.
#>
function Invoke-Tool { # TODO: RENAME TO INVOKE-PROCESS?
[CmdletBinding()]
param(
[ValidatePattern('^[^\r\n]*$')]
[Parameter(Mandatory = $true)]
[string]$FileName,
[ValidatePattern('^[^\r\n]*$')]
[Parameter()]
[string]$Arguments,
[string]$WorkingDirectory,
[System.Text.Encoding]$Encoding,
[switch]$RequireExitCodeZero)
Trace-EnteringInvocation $MyInvocation
$isPushed = $false
$originalEncoding = $null
try {
if ($Encoding) {
$originalEncoding = [System.Console]::OutputEncoding
[System.Console]::OutputEncoding = $Encoding
}
if ($WorkingDirectory) {
Push-Location -LiteralPath $WorkingDirectory -ErrorAction Stop
$isPushed = $true
}
$FileName = $FileName.Replace('"', '').Replace("'", "''")
Write-Host "##[command]""$FileName"" $Arguments"
Invoke-Expression "& '$FileName' --% $Arguments"
Write-Verbose "Exit code: $LASTEXITCODE"
if ($RequireExitCodeZero -and $LASTEXITCODE -ne 0) {
Write-Error (Get-LocString -Key PSLIB_Process0ExitedWithCode1 -ArgumentList ([System.IO.Path]::GetFileName($FileName)), $LASTEXITCODE)
}
} finally {
if ($originalEncoding) {
[System.Console]::OutputEncoding = $originalEncoding
}
if ($isPushed) {
Pop-Location
}
Trace-LeavingInvocation $MyInvocation
}
}

Просмотреть файл

@ -0,0 +1,139 @@
<#
.SYNOPSIS
Writes verbose information about the invocation being entered.
.DESCRIPTION
Used to trace verbose information when entering a function/script. Writes an entering message followed by a short description of the invocation. Additionally each bound parameter and unbound argument is also traced.
.PARAMETER Parameter
Wildcard pattern to control which bound parameters are traced.
#>
function Trace-EnteringInvocation {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[System.Management.Automation.InvocationInfo]$InvocationInfo,
[string[]]$Parameter = '*')
Write-Verbose "Entering $(Get-InvocationDescription $InvocationInfo)."
$OFS = ", "
if ($InvocationInfo.BoundParameters.Count -and $Parameter.Count) {
if ($Parameter.Count -eq 1 -and $Parameter[0] -eq '*') {
# Trace all parameters.
foreach ($key in $InvocationInfo.BoundParameters.Keys) {
Write-Verbose " $($key): '$($InvocationInfo.BoundParameters[$key])'"
}
} else {
# Trace matching parameters.
foreach ($key in $InvocationInfo.BoundParameters.Keys) {
foreach ($p in $Parameter) {
if ($key -like $p) {
Write-Verbose " $($key): '$($InvocationInfo.BoundParameters[$key])'"
break
}
}
}
}
}
# Trace all unbound arguments.
if (@($InvocationInfo.UnboundArguments).Count) {
for ($i = 0 ; $i -lt $InvocationInfo.UnboundArguments.Count ; $i++) {
Write-Verbose " args[$i]: '$($InvocationInfo.UnboundArguments[$i])'"
}
}
}
<#
.SYNOPSIS
Writes verbose information about the invocation being left.
.DESCRIPTION
Used to trace verbose information when leaving a function/script. Writes a leaving message followed by a short description of the invocation.
#>
function Trace-LeavingInvocation {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[System.Management.Automation.InvocationInfo]$InvocationInfo)
Write-Verbose "Leaving $(Get-InvocationDescription $InvocationInfo)."
}
<#
.SYNOPSIS
Writes verbose information about paths.
.DESCRIPTION
Writes verbose information about the paths. The paths are sorted and a the common root is written only once, followed by each relative path.
.PARAMETER PassThru
Indicates whether to return the sorted paths.
#>
function Trace-Path {
[CmdletBinding()]
param(
[string[]]$Path,
[switch]$PassThru)
if ($Path.Count -eq 0) {
Write-Verbose "No paths."
if ($PassThru) {
$Path
}
} elseif ($Path.Count -eq 1) {
Write-Verbose "Path: $($Path[0])"
if ($PassThru) {
$Path
}
} else {
# Find the greatest common root.
$sorted = $Path | Sort-Object
$firstPath = $sorted[0].ToCharArray()
$lastPath = $sorted[-1].ToCharArray()
$commonEndIndex = 0
$j = if ($firstPath.Length -lt $lastPath.Length) { $firstPath.Length } else { $lastPath.Length }
for ($i = 0 ; $i -lt $j ; $i++) {
if ($firstPath[$i] -eq $lastPath[$i]) {
if ($firstPath[$i] -eq '\') {
$commonEndIndex = $i
}
} else {
break
}
}
if ($commonEndIndex -eq 0) {
# No common root.
Write-Verbose "Paths:"
foreach ($p in $sorted) {
Write-Verbose " $p"
}
} else {
Write-Verbose "Paths: $($Path[0].Substring(0, $commonEndIndex + 1))"
foreach ($p in $sorted) {
Write-Verbose " $($p.Substring($commonEndIndex + 1))"
}
}
if ($PassThru) {
$sorted
}
}
}
########################################
# Private functions.
########################################
function Get-InvocationDescription {
[CmdletBinding()]
param([System.Management.Automation.InvocationInfo]$InvocationInfo)
if ($InvocationInfo.MyCommand.Path) {
$InvocationInfo.MyCommand.Path
} elseif ($InvocationInfo.MyCommand.Name) {
$InvocationInfo.MyCommand.Name
} else {
$InvocationInfo.MyCommand.CommandType
}
}

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,155 @@
[CmdletBinding()]
param(
[ValidateNotNull()]
[Parameter()]
[hashtable]$ModuleParameters = @{ })
if ($host.Name -ne 'ConsoleHost') {
Write-Warning "VstsTaskSdk is designed for use with powershell.exe (ConsoleHost). Output may be different when used with other hosts."
}
# Private module variables.
[bool]$script:nonInteractive = "$($ModuleParameters['NonInteractive'])" -eq 'true'
Write-Verbose "NonInteractive: $script:nonInteractive"
# Import/export functions.
. "$PSScriptRoot\FindFunctions.ps1"
. "$PSScriptRoot\InputFunctions.ps1"
. "$PSScriptRoot\LocalizationFunctions.ps1"
. "$PSScriptRoot\LoggingCommandFunctions.ps1"
. "$PSScriptRoot\LongPathFunctions.ps1"
. "$PSScriptRoot\ServerOMFunctions.ps1"
. "$PSScriptRoot\ToolFunctions.ps1"
. "$PSScriptRoot\TraceFunctions.ps1"
. "$PSScriptRoot\OutFunctions.ps1" # Load the out functions after all of the other functions are loaded.
Export-ModuleMember -Function @(
# Find functions.
'Find-Files'
# Input functions.
'Get-Endpoint'
'Get-Input'
'Get-TaskVariable'
'Get-TaskVariableInfo'
'Set-TaskVariable'
# Localization functions.
'Get-LocString'
'Import-LocStrings'
# Logging command functions.
'Write-AddAttachment'
'Write-AddBuildTag'
'Write-AssociateArtifact'
'Write-LogDetail'
'Write-SetProgress'
'Write-SetResult'
'Write-SetSecret'
'Write-SetVariable'
'Write-TaskDebug'
'Write-TaskError'
'Write-TaskVerbose'
'Write-TaskWarning'
'Write-UpdateBuildNumber'
'Write-UploadArtifact'
'Write-UploadBuildLog'
# Out functions.
'Out-Default'
# Server OM functions.
'Get-AssemblyReference'
'Get-TfsClientCredentials'
'Get-TfsService'
'Get-VssCredentials'
'Get-VssHttpClient'
# Tool functions.
'Assert-Path'
'Invoke-Tool'
# Trace functions.
'Trace-EnteringInvocation'
'Trace-LeavingInvocation'
'Trace-Path'
)
# Special internal exception type to control the flow. Not currently intended
# for public usage and subject to change. If the type has already
# been loaded once, then it is not loaded again.
Write-Verbose "Adding exceptions types."
Add-Type -WarningAction SilentlyContinue -Debug:$false -TypeDefinition @'
namespace VstsTaskSdk
{
public class TerminationException : System.Exception
{
public TerminationException(System.String message) : base(message) { }
}
}
'@
# Override Out-Default globally.
$null = New-Item -Force -Path "function:\global:Out-Default" -Value (Get-Command -CommandType Function -Name Out-Default -ListImported)
New-Alias -Name Out-Default -Value "global:Out-Default" -Scope global
# Perform some initialization in a script block to enable merging the pipelines.
$scriptText = @"
# Load the SDK resource strings.
Import-LocStrings "$PSScriptRoot\lib.json"
# Load the module that contains ConvertTo-SecureString.
if (!(Get-Module -Name Microsoft.PowerShell.Security)) {
Write-Verbose "Importing the module 'Microsoft.PowerShell.Security'."
Import-Module -Name Microsoft.PowerShell.Security 2>&1 |
ForEach-Object {
if (`$_ -is [System.Management.Automation.ErrorRecord]) {
Write-Verbose `$_.Exception.Message
} else {
,`$_
}
}
}
"@
. ([scriptblock]::Create($scriptText)) 2>&1 3>&1 4>&1 5>&1 | Out-Default
# Create Invoke-VstsTaskScript in a special way so it is not bound to the module.
# Otherwise calling the task script block would run within the module context.
#
# An alternative way to solve the problem is to close the script block (i.e. closure).
# However, that introduces a different problem. Closed script blocks are created within
# a dynamic module. Each module gets it's own session state separate from the global
# session state. When running in a regular script context, Import-Module calls import
# the target module into the global session state. When running in a module context,
# Import-Module calls import the target module into the caller module's session state.
#
# The goal of a task may include executing ad-hoc scripts. Therefore, task scripts
# should run in regular script context. The end user specifying an ad-hoc script expects
# the module import rules to be consistent with the default behavior (i.e. imported
# into the global session state).
$null = New-Item -Force -Path "function:\global:Invoke-VstsTaskScript" -Value ([scriptblock]::Create(@'
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[scriptblock]$ScriptBlock)
try {
$global:ErrorActionPreference = 'Stop'
# Initialize the environment.
$vstsModule = Get-Module -Name VstsTaskSdk
Write-Verbose "$($vstsModule.Name) $($vstsModule.Version) commit $($vstsModule.PrivateData.PSData.CommitHash)" 4>&1 | Out-Default
& $vstsModule Initialize-Inputs 4>&1 | Out-Default
# Remove the local variable before calling the user's script.
Remove-Variable -Name vstsModule
# Call the user's script.
$ScriptBlock |
ForEach-Object {
# Remove the scriptblock variable before calling it.
Remove-Variable -Name ScriptBlock
& $_ 2>&1 3>&1 4>&1 5>&1 | Out-Default
}
} catch [VstsTaskSdk.TerminationException] {
# Special internal exception type to control the flow. Not currently intended
# for public usage and subject to change.
Write-Verbose "Task script terminated." 4>&1 | Out-Default
} catch {
Write-Verbose "Caught exception from task script." 4>&1 | Out-Default
$_ | Out-Default
Write-Host "##vso[task.complete result=Failed]"
}
'@))

Просмотреть файл

@ -0,0 +1,19 @@
{
"messages": {
"PSLIB_ContainerPathNotFound0": "Container path not found: '{0}'",
"PSLIB_EndpointAuth0": "'{0}' service endpoint credentials",
"PSLIB_EndpointUrl0": "'{0}' service endpoint URL",
"PSLIB_EnumeratingSubdirectoriesFailedForPath0": "Enumerating subdirectories failed for path: '{0}'",
"PSLIB_FileNotFound0": "File not found: '{0}'",
"PSLIB_Input0": "'{0}' input",
"PSLIB_InvalidPattern0": "Invalid pattern: '{0}'",
"PSLIB_LeafPathNotFound0": "Leaf path not found: '{0}'",
"PSLIB_PathLengthNotReturnedFor0": "Path normalization/expansion failed. The path length was not returned by the Kernel32 subsystem for: '{0}'",
"PSLIB_PathNotFound0": "Path not found: '{0}'",
"PSLIB_Process0ExitedWithCode1": "Process '{0}' exited with code '{1}'.",
"PSLIB_Required0": "Required: {0}",
"PSLIB_StringFormatFailed": "String format failed.",
"PSLIB_StringResourceKeyNotFound0": "String resource key not found: '{0}'",
"PSLIB_TaskVariable0": "'{0}' task variable"
}
}

Двоичные данные
BuildTasks/markWorkItemAsStale/task.json Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,62 @@
{
"compilerOptions": {
/* Basic Options */
"target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
// "lib": [], /* Specify library files to be included in the compilation. */
// "allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
// "declaration": true, /* Generates corresponding '.d.ts' file. */
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
// "sourceMap": true, /* Generates corresponding '.map' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */
// "outDir": "./", /* Redirect output structure to the directory. */
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
// "composite": true, /* Enable project compilation */
// "incremental": true, /* Enable incremental compilation */
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
// "removeComments": true, /* Do not emit comments to output. */
// "noEmit": true, /* Do not emit outputs. */
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
/* Strict Type-Checking Options */
"strict": true, /* Enable all strict type-checking options. */
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* Enable strict null checks. */
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
/* Additional Checks */
// "noUnusedLocals": true, /* Report errors on unused locals. */
// "noUnusedParameters": true, /* Report errors on unused parameters. */
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
/* Module Resolution Options */
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
// "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
/* Source Map Options */
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
/* Experimental Options */
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
}
}

Просмотреть файл

@ -0,0 +1,46 @@
{
"manifestVersion": 1,
"id": "devopsAutomation",
"name": "DevOps Automation Tools",
"version": "0.0.6",
"publisher": "devopsCli",
"targets": [
{
"id": "Microsoft.VisualStudio.Services"
}
],
"public": true,
"description": "Tools for running automation tasks against azure devops.",
"categories": [
"Azure Pipelines"
],
"icons": {
"default": "icons/extension-icon.png"
},
"content": {
"details": {
"path": "overview.md"
}
},
"files": [
{
"path": "markWorkItemAsStale"
},
{
"path": "images",
"addressable": true
}
],
"contributions": [
{
"id": "custom-build-release-task",
"type": "ms.vss-distributed-task.task",
"targets": [
"ms.vss-distributed-task.tasks"
],
"properties": {
"name": "markWorkItemAsStale"
}
}
]
}