diff --git a/Tasks/ANT/task.json b/Tasks/ANT/task.json index 78bb74ef7131..28b23074fa2b 100644 --- a/Tasks/ANT/task.json +++ b/Tasks/ANT/task.json @@ -8,12 +8,16 @@ "visibility": [ "Build", "Release" + ], + "runsOn": [ + "Agent", + "MachineGroup" ], "author": "Microsoft Corporation", "version": { "Major": 1, "Minor": 0, - "Patch": 58 + "Patch": 59 }, "demands": [ "ant" diff --git a/Tasks/ANT/task.loc.json b/Tasks/ANT/task.loc.json index 3b082f3a564d..408c2e30caea 100644 --- a/Tasks/ANT/task.loc.json +++ b/Tasks/ANT/task.loc.json @@ -9,11 +9,15 @@ "Build", "Release" ], + "runsOn": [ + "Agent", + "MachineGroup" + ], "author": "Microsoft Corporation", "version": { "Major": 1, "Minor": 0, - "Patch": 58 + "Patch": 59 }, "demands": [ "ant" diff --git a/Tasks/AndroidBuild/AndroidBuild.ps1 b/Tasks/AndroidBuild/AndroidBuild.ps1 deleted file mode 100644 index a31c719873d3..000000000000 --- a/Tasks/AndroidBuild/AndroidBuild.ps1 +++ /dev/null @@ -1,72 +0,0 @@ -param( - [string]$gradleWrapper, # Path to gradle wrapper. Empty if using gradle installation. - [string]$gradleProj, # Optional - Root directory of gradle project. Defaults to root of working directory if empty. - [string]$gradleArguments, # Gradle arguments - [string]$avdName, # Android Virtual Device name - [string]$createAvd, # Create the named AVD - [string]$emulatorTarget, # Emulator target version (keep name for back compat) - [string]$emulatorDevice, # Emulator device (keep name for back compat) - [string]$avdAbi, # Emulator ABI - [string]$avdForce, # Overwrite existing AVD (--force) - [string]$avdOptionalArgs, # Optional args passed to "android create avd" - [string]$startEmulator, # True if emulator start required. Converted to Boolean - [string]$emulatorTimeout, # Timeout value when waiting for emulator to start - [string]$emulatorHeadless, # Headless display - [string]$emulatorOptionalArgs, # Optional arguments to "tools/emulator" - [string]$deleteAvd # Delete AVD -) - -Write-Warning "The Android Build task has been deprecated. Use the Gradle task instead. See https://go.microsoft.com/fwlink/?LinkID=613720." - -Write-Verbose "Entering script AndroidBuild.ps1" -Write-Verbose "gradleWrapper = $gradleWrapper" -Write-Verbose "gradleProj = $gradleProj" -Write-Verbose "gradleArguments = $gradleArguments" -Write-Verbose "avdName = $avdName" -Write-Verbose "createAvd = $createAvd" -Write-Verbose "emulatorTarget = $emulatorTarget" -Write-Verbose "emulatorDevice = $emulatorDevice" -Write-Verbose "avdAbi = $avdAbi" -Write-Verbose "avdForce = $avdForce" -Write-Verbose "avdOptionalArgs = $avdOptionalArgs" -Write-Verbose "startEmulator = $startEmulator" -Write-Verbose "emulatorTimeout = $emulatorTimeout" -Write-Verbose "emulatorHeadless = $emulatorHeadless" -Write-Verbose "emulatorOptionalArgs = $emulatorOptionalArgs" -Write-Verbose "deleteAvd = $deleteAvd" - -# Import the Task.Common and Task.Internal dll that has all the cmdlets we need for Build -import-module "Microsoft.TeamFoundation.DistributedTask.Task.Internal" -import-module "Microsoft.TeamFoundation.DistributedTask.Task.Common" - - -# Set the paths of the Start and Kill Android Emulator scripts, which are in the same directory as AndroidBuild.ps1 -$PSScriptRoot = Split-Path -Parent -Path $MyInvocation.MyCommand.Definition -$StartEmulatorScript = Join-Path -Path $PSScriptRoot -ChildPath "StartAndroidEmulator.ps1" -$KillEmulatorScript = Join-Path -Path $PSScriptRoot -ChildPath "KillAndroidEmulator.ps1" - -# Always invoke the start up script, let the script handle create and start emulator checks -$createAvdArgs = "-avdName `"$avdName`" -createAvd $createAvd -avdTarget `"$emulatorTarget`" -avdDevice `"$emulatorDevice`" -avdAbi `"$avdAbi`" -avdForceOverwrite $avdForce -avdOptionalArgs `"$avdOptionalArgs`"" -$emulatorArgs = "-startEmulator $startEmulator -timeout `"$emulatorTimeout`" -headlessEmulator $emulatorHeadless -emulatorOptionalArgs `"$emulatorOptionalArgs`"" -$startEmulatorCommand = "& `"$StartEmulatorScript`" $createAvdArgs $emulatorArgs" -Write-Verbose "Calling start emulator script: $startEmulatorCommand" -Invoke-Expression -Command $startEmulatorCommand - -# Use Gradle Wrapper -if ([System.IO.File]::Exists($gradleWrapper)) -{ - Write-Verbose "Invoking gradle wrapper $gradleWrapper with arguments $gradleArguments in working directory $gradleProj" - Invoke-BatchScript $gradleWrapper -Arguments $gradleArguments -WorkingFolder $gradleProj -} -else -{ - throw "Unable to find script $gradleWrapper" -} - -# Always invoke the post build script, emulator must be stopped if we started it -# otherwise task hangs -$killEmulatorCommand = "& `"$KillEmulatorScript`" `"$avdName`" $startEmulator $deleteAvd" -Write-Verbose "Calling stop emulator script with command: $killEmulatorCommand" -Invoke-Expression -Command $killEmulatorCommand - -Write-Verbose "Leaving script AndroidBuild.ps1" diff --git a/Tasks/AndroidBuild/KillAndroidEmulator.ps1 b/Tasks/AndroidBuild/KillAndroidEmulator.ps1 deleted file mode 100644 index 0ce7e0287278..000000000000 --- a/Tasks/AndroidBuild/KillAndroidEmulator.ps1 +++ /dev/null @@ -1,58 +0,0 @@ -param( - [string]$avdName, - [string]$startEmulator, - [string]$deleteAvd -) - -Write-Verbose "Entering script KillAndroidEmulator.ps1" -Write-Verbose "avdName = $avdName" - -$emulatorStarted = Convert-String $startEmulator Boolean -Write-Verbose "stopEmulatorChecked (converted) = $emulatorStarted" -$deleteAvdChecked = Convert-String $deleteAvd Boolean -Write-Verbose "deleteAvdChecked (converted) = $deleteAvdChecked" - - -if ($emulatorStarted) -{ - $emulatorPid = $env:EMULATOR_PID - - if ($env:ANDROID_HOME -eq $null) - { - throw 'Environment variable not set: ANDROID_HOME' - } - - $adbexe = $env:ANDROID_HOME + "\platform-tools\adb.exe" - if (!(Test-Path -Path $adbexe)) - { - throw "File not found: $adbexe" - } - - $androidbat = $env:ANDROID_HOME + "\tools\android.bat" - if (!(Test-Path -Path $androidbat)) - { - throw "File not found: $androidbat" - } - - if ($emulatorPid) - { - $emulators = Get-WmiObject -Class Win32_Process -Filter "ParentProcessID=$emulatorPid" - if ($emulators) - { - # Delete emulator device. Stop-Process is used because Wait-Job or Stop-Job hangs. - # Emulator.exe is the parent process which spawns the actual child emulator processes - Stop-Process $emulators.ProcessId - } - } - - if ($deleteAvdChecked) - { - & $androidbat delete avd -n $avdName - } - - # Stop any Android Debug Bridge process, otherwise the task may hang. - & $adbexe kill-server - Stop-Process -processname 'adb' 2> $null -} - -Write-Verbose "Leaving script KillAndroidEmulator.ps1" diff --git a/Tasks/AndroidBuild/StartAndroidEmulator.ps1 b/Tasks/AndroidBuild/StartAndroidEmulator.ps1 deleted file mode 100755 index a64c359cb5f7..000000000000 --- a/Tasks/AndroidBuild/StartAndroidEmulator.ps1 +++ /dev/null @@ -1,189 +0,0 @@ -param( - [string]$createAvd, # Create AVD - [string]$avdName, # Name of AVD - [string]$avdTarget, # AVD target version - [string]$avdDevice, # AVD device - [string]$avdAbi, # AVD ABI - [string]$avdForceOverwrite, # Force overwrite existing AVD - [string]$avdOptionalArgs, # AVD Optional args - [string]$startEmulator, # True if emulator start required. Converted to Boolean - [string]$headlessEmulator, # Avoid showing the emulator interface if true - [int]$timeout # Length of time allowed per try -) - -Write-Verbose "Entering script StartAndroidEmulator.ps1" -Write-Verbose "createAvd = $createAvd" -Write-Verbose "avdTarget = $avdTarget" -Write-Verbose "avdDevice = $avdDevice" -Write-Verbose "avdName = $avdName" -Write-Verbose "avdAbi = $avdAbi" -Write-Verbose "avdForceOverwrite = $avdForceOverwrite" -Write-Verbose "avdOptionalArgs = $avdOptionalArgs" -Write-Verbose "headlessEmulator = $headlessEmulator" -Write-Verbose "timeout = $timeout seconds" - -$startEmulatorChecked = Convert-String $startEmulator Boolean -Write-Verbose "startEmulatorChecked (converted) = $startEmulatorChecked" -$emulatorHeadlessChecked = Convert-String $headlessEmulator Boolean -Write-Verbose "emulatorHeadlessChecked (converted) = $emulatorHeadlessChecked" -$createAvdChecked = Convert-String $createAvd Boolean -Write-Verbose "createAvdChecked (converted) = $createAvdChecked" -$avdForceOverwriteChecked = Convert-String $avdForceOverwrite Boolean -Write-Verbose "avdForceOverwriteChecked (converted) = $avdForceOverwriteChecked" - -function Start-EmulatorProcess -{ - param([string]$arguments) - - Push-Location $env:ANDROID_HOME - - $processStartInfo = New-Object System.Diagnostics.ProcessStartInfo - $processStartInfo.FileName = $env:ANDROID_HOME + "\tools\emulator.exe" - $processStartInfo.Arguments = $arguments - $processStartInfo.UseShellExecute = $false - $processStartInfo.CreateNoWindow = $true - $processStartInfo.RedirectStandardOutput = $true - - $process = New-Object System.Diagnostics.Process - $process.StartInfo = $processStartInfo - - # Start the process - $process.Start() - - Pop-Location - - return $process -} - -function Clean-EmulatorProcess -{ - param([int]$emulatorPid) - - if ($emulatorPid) - { - $emulators = Get-WmiObject -Class Win32_Process -Filter "ParentProcessID=$emulatorPid" - if ($emulators) - { - Stop-Process $emulators.ProcessId - } - } - - # Stop any Android Debug Bridge process we started, otherwise the task may hang. - # adb process sometimes restarts itself so we may need to kill adb again after kill the emulator - & $adbexe kill-server - Stop-Process -processname 'adb' 2> $null -} - -if ($createAvdChecked) -{ - if ($env:ANDROID_HOME -eq $null) - { - throw 'Environment variable not set: ANDROID_HOME' - } - - $androidbat = $env:ANDROID_HOME + "\tools\android.bat" - if (!(Test-Path -Path $androidbat)) - { - throw "File not found: $androidbat" - } - - # Create an emulator device - # Exit code always returns 0. Assume success and if this failed, we will report failure later on - $createAvdCmd = "& `"$androidbat`" create avd --name `"$avdName`" --target $avdTarget --device `"$avdDevice`" --abi $avdAbi $avdOptionalArgs" - - if ($avdForceOverwriteChecked) - { - $createAvdCmd = "$createAvdCmd --force" - } - - Write-Verbose "Creating AVD with: $createAvdCmd" - Invoke-Expression -Command $createAvdCmd -} - -if ($startEmulatorChecked) -{ - if ($env:ANDROID_HOME -eq $null) - { - throw 'Environment variable not set: ANDROID_HOME' - } - - $adbexe = $env:ANDROID_HOME + "\platform-tools\adb.exe" - if (!(Test-Path -Path $adbexe)) - { - throw "File not found: $adbexe" - } - - # Start emulator - # Exit code always returns 0. Assume success and if this failed, we will report failure later on - Push-Location $env:ANDROID_HOME - $emulatorArgs = "-avd `"$avdName`" -prop persist.sys.language=en -prop persist.sys.country=US $emulatorOptionalArgs" - if ($emulatorHeadlessChecked) - { - $emulatorArgs = "$emulatorArgs -no-skin -no-audio -no-window" - } - - Write-Verbose "Starting emulator with: $emulatorArgs" - $emulatorProcess = Start-EmulatorProcess -arguments $emulatorArgs - - # Record the parent process id so we will only kill what we started - $env:EMULATOR_PID=$emulatorProcess.Id - - Pop-Location - - # Connect to emulator - & $adbexe start-server - - # Script block containing WaitADBProperty. Putting function in script block so it can be called by job. - $adbBlock = { - function WaitADBProperty { - param( - [string]$property, - [string]$expectedOutput, - [int]$timeout = 10 - ) - Write-Verbose "Waiting for property $property to be $expectedOutput" - $adbexe = $env:ANDROID_HOME + "\platform-tools\adb.exe" - $adbOutput = 0 - while($adbOutput[0] -ne $expectedOutput) { - ($adbPropertyJob = Start-Job -ScriptBlock { - param($adbexe, $property) - & $adbexe shell getprop $property 2> $null - } -Argumentlist $adbexe, $property) | Out-Null - Wait-Job $adbPropertyJob -Timeout $timeout| Out-Null - Receive-Job $adbPropertyJob -OutVariable adbOutput | Out-Null - } - } - } - - # Running together as a job allows us to set a time out. - $bootJob = Start-Job -InitializationScript $adbBlock -ScriptBlock { - WaitADBProperty "dev.bootcomplete" "1" - WaitADBProperty "sys.boot_completed" "1" - WaitADBProperty "init.svc.bootanim" "stopped" - return $TRUE - } - - Write-Host "Wait for $timeout seconds for emulator to start..." - Wait-Job $bootJob -Timeout $timeout | Out-Null - Receive-Job $bootJob -OutVariable bootCompleted | Out-Null - - # List attached emulator devices - & $adbexe devices -l - - # Check if emulator booted up successfully - if ([boolean]$bootCompleted -ne $TRUE) - { - # Must clean up otherwise the task hangs here - # Kill whatever process we started - Clean-EmulatorProcess $emulatorProcess.Id - - Write-Verbose "Emulator property dev.bootcomplete, sys.boot_completed and init.svc.bootanim do not indicate emulator was started up completely." - throw "Error: Emulator failed to start within $timeout seconds." - } - - # Stop any Android Debug Bridge process we started, otherwise the task may hang. - & $adbexe kill-server - Stop-Process -processname 'adb' 2> $null -} - -Write-Verbose "Leaving script StartAndroidEmulator.ps1" diff --git a/Tasks/AndroidBuild/Strings/resources.resjson/de-de/resources.resjson b/Tasks/AndroidBuild/Strings/resources.resjson/de-de/resources.resjson deleted file mode 100644 index ce0c22492c0f..000000000000 --- a/Tasks/AndroidBuild/Strings/resources.resjson/de-de/resources.resjson +++ /dev/null @@ -1,34 +0,0 @@ -{ - "loc.friendlyName": "Android-Build (veraltet, verwenden Sie Gradle)", - "loc.helpMarkDown": "[More Information](https://go.microsoft.com/fwlink/?LinkID=613716)", - "loc.description": "Erstellen Sie eine Android-App mithilfe von Gradle, und starten Sie optional den Emulator für Komponententests.", - "loc.instanceNameFormat": "Android-Build $(gradleProj)", - "loc.group.displayName.avdOptions": "Optionen für virtuelle Android-Geräte (AVD)", - "loc.group.displayName.emulatorOptions": "Emulatoroptionen", - "loc.input.label.gradleWrapper": "Speicherort des Gradle-Wrappers", - "loc.input.label.gradleProj": "Projektverzeichnis", - "loc.input.label.gradleArguments": "Gradle-Argumente", - "loc.input.label.avdName": "Name", - "loc.input.help.avdName": "Der Name des zu startenden oder zu erstellenden virtuellen Android-Geräts (AVD).", - "loc.input.label.createAvd": "AVD erstellen", - "loc.input.help.createAvd": "Erstellt das benannte virtuelle Android-Gerät (AVD).", - "loc.input.label.emulatorTarget": "AVD-Ziel-SDK", - "loc.input.help.emulatorTarget": "Die Ziel-ID des neuen virtuellen Android-Geräts (AVD).", - "loc.input.label.emulatorDevice": "AVD-Gerät", - "loc.input.help.emulatorDevice": "The optional device definition to use. Can be a device index or ID.", - "loc.input.label.avdAbi": "AVD-ABI", - "loc.input.help.avdAbi": "Die für das virtuelle Android-Gerät (AVD) zu verwendende ABI.", - "loc.input.label.avdForce": "Vorhandenes AVD überschreiben", - "loc.input.help.avdForce": "Die Übergabe wird ausgeführt – Befehl \"android create avd\" erzwingen.", - "loc.input.label.avdOptionalArgs": "Optionale AVD-Argumente erstellen", - "loc.input.help.avdOptionalArgs": "Zusätzliche Argumente, die an \"android create avd\" übergeben werden.", - "loc.input.label.startEmulator": "Android-Emulator starten und beenden", - "loc.input.help.startEmulator": "Starten und beenden Sie den Android-Emulator nach Abschluss dieser Aufgabe.", - "loc.input.label.emulatorTimeout": "Zeitüberschreitung in Sekunden", - "loc.input.help.emulatorTimeout": "Wie lange der Buildvorgang auf den Start des Emulators wartet.", - "loc.input.label.emulatorHeadless": "Monitorlose Anzeige", - "loc.input.help.emulatorHeadless": "Verwenden Sie \"-no-skin -no-audio -no-window\" beim Starten des Emulators.", - "loc.input.label.emulatorOptionalArgs": "Optionale Emulatorargumente", - "loc.input.help.emulatorOptionalArgs": "Zusätzliche Argumente, die an Android \"tools\\emulator\" übergeben werden.", - "loc.input.label.deleteAvd": "AVD löschen" -} \ No newline at end of file diff --git a/Tasks/AndroidBuild/Strings/resources.resjson/en-US/resources.resjson b/Tasks/AndroidBuild/Strings/resources.resjson/en-US/resources.resjson deleted file mode 100644 index eb8c8f442dd7..000000000000 --- a/Tasks/AndroidBuild/Strings/resources.resjson/en-US/resources.resjson +++ /dev/null @@ -1,34 +0,0 @@ -{ - "loc.friendlyName": "Android Build (deprecated; use Gradle)", - "loc.helpMarkDown": "[More Information](https://go.microsoft.com/fwlink/?LinkID=613716)", - "loc.description": "Build an Android app using Gradle and optionally start the emulator for unit tests", - "loc.instanceNameFormat": "Android Build $(gradleProj)", - "loc.group.displayName.avdOptions": "Android Virtual Device (AVD) Options", - "loc.group.displayName.emulatorOptions": "Emulator Options", - "loc.input.label.gradleWrapper": "Location of Gradle Wrapper", - "loc.input.label.gradleProj": "Project Directory", - "loc.input.label.gradleArguments": "Gradle Arguments", - "loc.input.label.avdName": "Name", - "loc.input.help.avdName": "Name of the Android Virtual Device (AVD) to be started or created.", - "loc.input.label.createAvd": "Create AVD", - "loc.input.help.createAvd": "Create the named Android Virtual Device (AVD).", - "loc.input.label.emulatorTarget": "AVD Target SDK", - "loc.input.help.emulatorTarget": "Target ID of the new Android Virtual Device (AVD).", - "loc.input.label.emulatorDevice": "AVD Device", - "loc.input.help.emulatorDevice": "The optional device definition to use. Can be a device index or ID.", - "loc.input.label.avdAbi": "AVD ABI", - "loc.input.help.avdAbi": "The ABI to use for the Android Virtual Device (AVD).", - "loc.input.label.avdForce": "Overwrite Existing AVD", - "loc.input.help.avdForce": "Passing --force to 'android create avd' command.", - "loc.input.label.avdOptionalArgs": "Create AVD Optional Arguments", - "loc.input.help.avdOptionalArgs": "Additional arguments passed to 'android create avd'.", - "loc.input.label.startEmulator": "Start and Stop Android Emulator", - "loc.input.help.startEmulator": "Start Android emulator and stop emulator after this task finishes.", - "loc.input.label.emulatorTimeout": "Timeout in Seconds", - "loc.input.help.emulatorTimeout": "How long build will wait for the emulator to start.", - "loc.input.label.emulatorHeadless": "Headless Display", - "loc.input.help.emulatorHeadless": "Use '-no-skin -no-audio -no-window' when start the emulator.", - "loc.input.label.emulatorOptionalArgs": "Emulator Optional Arguments", - "loc.input.help.emulatorOptionalArgs": "Additional arguments passed to Android 'tools\\emulator'.", - "loc.input.label.deleteAvd": "Delete AVD" -} \ No newline at end of file diff --git a/Tasks/AndroidBuild/Strings/resources.resjson/es-es/resources.resjson b/Tasks/AndroidBuild/Strings/resources.resjson/es-es/resources.resjson deleted file mode 100644 index 61d754c30894..000000000000 --- a/Tasks/AndroidBuild/Strings/resources.resjson/es-es/resources.resjson +++ /dev/null @@ -1,34 +0,0 @@ -{ - "loc.friendlyName": "Compilación de Android (en desuso, use Gradle)", - "loc.helpMarkDown": "[More Information](https://go.microsoft.com/fwlink/?LinkID=613716)", - "loc.description": "Compilar una aplicación Android con Gradle y, opcionalmente, iniciar el emulador para realizar pruebas unitarias", - "loc.instanceNameFormat": "Compilación de Android $(gradleProj)", - "loc.group.displayName.avdOptions": "Opciones de dispositivo virtual Android (AVD)", - "loc.group.displayName.emulatorOptions": "Opciones del emulador", - "loc.input.label.gradleWrapper": "Ubicación del contenedor de Gradle", - "loc.input.label.gradleProj": "Directorio del proyecto", - "loc.input.label.gradleArguments": "Argumentos de Gradle", - "loc.input.label.avdName": "Nombre", - "loc.input.help.avdName": "Nombre del dispositivo virtual Android (AVD) que se va a iniciar o crear.", - "loc.input.label.createAvd": "Crear AVD", - "loc.input.help.createAvd": "Cree el dispositivo virtual Android (AVD) con nombre.", - "loc.input.label.emulatorTarget": "SDK de destino AVD", - "loc.input.help.emulatorTarget": "Id. de destino del nuevo dispositivo virtual Android (AVD).", - "loc.input.label.emulatorDevice": "Dispositivo AVD", - "loc.input.help.emulatorDevice": "The optional device definition to use. Can be a device index or ID.", - "loc.input.label.avdAbi": "ABI AVD", - "loc.input.help.avdAbi": "ABI que se va a usar para el dispositivo virtual Android (AVD).", - "loc.input.label.avdForce": "Sobrescribir AVD existente", - "loc.input.help.avdForce": "Pasando --force al comando 'android create avd'.", - "loc.input.label.avdOptionalArgs": "Crear argumentos opcionales de AVD", - "loc.input.help.avdOptionalArgs": "Argumentos adicionales pasados a \"android create avd\".", - "loc.input.label.startEmulator": "Iniciar y detener el emulador de Android", - "loc.input.help.startEmulator": "Inicie el emulador de Android y deténgalo cuando esta tarea acabe.", - "loc.input.label.emulatorTimeout": "Tiempo de espera en segundos", - "loc.input.help.emulatorTimeout": "Tiempo que el compilador espera a que el emulador se inicie.", - "loc.input.label.emulatorHeadless": "Emulador de pantalla", - "loc.input.help.emulatorHeadless": "Use \"-no-skin -no-audio -no-window\" cuando inicie el emulador.", - "loc.input.label.emulatorOptionalArgs": "Argumentos opcionales de emulador", - "loc.input.help.emulatorOptionalArgs": "Argumentos adicionales pasados a \"tools\\emulator\" de Android.", - "loc.input.label.deleteAvd": "Eliminar AVD" -} \ No newline at end of file diff --git a/Tasks/AndroidBuild/Strings/resources.resjson/fr-fr/resources.resjson b/Tasks/AndroidBuild/Strings/resources.resjson/fr-fr/resources.resjson deleted file mode 100644 index e3399e6a1bd4..000000000000 --- a/Tasks/AndroidBuild/Strings/resources.resjson/fr-fr/resources.resjson +++ /dev/null @@ -1,34 +0,0 @@ -{ - "loc.friendlyName": "Build Android (déconseillé, utiliser Gradle)", - "loc.helpMarkDown": "[More Information](https://go.microsoft.com/fwlink/?LinkID=613716)", - "loc.description": "Générer une application Android à l'aide de Gradle et démarrer éventuellement l'émulateur pour les tests unitaires", - "loc.instanceNameFormat": "Build Android $(gradleProj)", - "loc.group.displayName.avdOptions": "Options de l'appareil virtuel Android", - "loc.group.displayName.emulatorOptions": "Options de l'émulateur", - "loc.input.label.gradleWrapper": "Emplacement du wrapper Gradle", - "loc.input.label.gradleProj": "Répertoire du projet", - "loc.input.label.gradleArguments": "Arguments Gradle", - "loc.input.label.avdName": "Nom", - "loc.input.help.avdName": "Nom de l'appareil virtuel Android à démarrer ou créer.", - "loc.input.label.createAvd": "Créer un AVD", - "loc.input.help.createAvd": "Créez l'appareil virtuel Android nommé.", - "loc.input.label.emulatorTarget": "Kit de développement logiciel (SDK) cible AVD", - "loc.input.help.emulatorTarget": "ID cible du nouvel appareil virtuel Android.", - "loc.input.label.emulatorDevice": "Appareil AVD", - "loc.input.help.emulatorDevice": "The optional device definition to use. Can be a device index or ID.", - "loc.input.label.avdAbi": "ABI AVD", - "loc.input.help.avdAbi": "ABI à utiliser pour l'appareil virtuel Android.", - "loc.input.label.avdForce": "Remplacer l'AVD existant", - "loc.input.help.avdForce": "Transmission --forcée vers la commande 'android create avd'.", - "loc.input.label.avdOptionalArgs": "Créer des arguments facultatifs AVD", - "loc.input.help.avdOptionalArgs": "Arguments supplémentaires passés à 'android create avd'.", - "loc.input.label.startEmulator": "Démarrer et arrêter l'émulateur Android", - "loc.input.help.startEmulator": "Démarrez l'émulateur Android et arrêtez-le à la fin de cette tâche.", - "loc.input.label.emulatorTimeout": "Délai d'expiration en secondes", - "loc.input.help.emulatorTimeout": "Durée d'attente de la build avant le démarrage de l'émulateur.", - "loc.input.label.emulatorHeadless": "Affichage sans périphérique de contrôle", - "loc.input.help.emulatorHeadless": "Utilisez '-no-skin -no-audio -no-window' au démarrage de l'émulateur.", - "loc.input.label.emulatorOptionalArgs": "Arguments facultatifs de l'émulateur", - "loc.input.help.emulatorOptionalArgs": "Arguments supplémentaires passés à 'tools\\emulator' Android.", - "loc.input.label.deleteAvd": "Supprimer un AVD" -} \ No newline at end of file diff --git a/Tasks/AndroidBuild/Strings/resources.resjson/it-IT/resources.resjson b/Tasks/AndroidBuild/Strings/resources.resjson/it-IT/resources.resjson deleted file mode 100644 index 47975f02cdee..000000000000 --- a/Tasks/AndroidBuild/Strings/resources.resjson/it-IT/resources.resjson +++ /dev/null @@ -1,34 +0,0 @@ -{ - "loc.friendlyName": "Compilazione Android (deprecata; usare Gradle)", - "loc.helpMarkDown": "[More Information](https://go.microsoft.com/fwlink/?LinkID=613716)", - "loc.description": "Consente di compilare un'app per Android con Gradle e facoltativamente di avviare l'emulatore per gli unit test", - "loc.instanceNameFormat": "Build Android $(gradleProj)", - "loc.group.displayName.avdOptions": "Opzioni del dispositivo virtuale Android (AVD)", - "loc.group.displayName.emulatorOptions": "Opzioni emulatore", - "loc.input.label.gradleWrapper": "Percorso del wrapper di Gradle", - "loc.input.label.gradleProj": "Directory del progetto", - "loc.input.label.gradleArguments": "Argomenti di Gradle", - "loc.input.label.avdName": "Nome", - "loc.input.help.avdName": "Nome del dispositivo virtuale Android (AVD) da avviare o creare.", - "loc.input.label.createAvd": "Crea AVD", - "loc.input.help.createAvd": "Crea il dispositivo virtuale Android (AVD) denominato.", - "loc.input.label.emulatorTarget": "SDK di destinazione AVD", - "loc.input.help.emulatorTarget": "ID di destinazione del nuovo dispositivo virtuale Android (AVD).", - "loc.input.label.emulatorDevice": "Dispositivo AVD", - "loc.input.help.emulatorDevice": "The optional device definition to use. Can be a device index or ID.", - "loc.input.label.avdAbi": "ABI AVD", - "loc.input.help.avdAbi": "ABI da usare per il dispositivo virtuale Android (AVD).", - "loc.input.label.avdForce": "Sovrascrivi AVD esistente", - "loc.input.help.avdForce": "Passaggio di --force al comando 'android create avd'.", - "loc.input.label.avdOptionalArgs": "Argomenti facoltativi creazione AVD", - "loc.input.help.avdOptionalArgs": "Argomenti aggiuntivi passati ad 'android create avd'.", - "loc.input.label.startEmulator": "Avvia e arresta emulatore Android", - "loc.input.help.startEmulator": "Avvia l'emulatore Android e lo arresta al termine di questa attività.", - "loc.input.label.emulatorTimeout": "Timeout in secondi", - "loc.input.help.emulatorTimeout": "Indica per quanto tempo la build attenderà l'avvio dell'emulatore.", - "loc.input.label.emulatorHeadless": "Visualizzazione headless", - "loc.input.help.emulatorHeadless": "All'avvio dell'emulatore usare '-no-skin -no-audio -no-window'.", - "loc.input.label.emulatorOptionalArgs": "Argomenti facoltativi emulatore", - "loc.input.help.emulatorOptionalArgs": "Argomenti aggiuntivi passati a 'tools\\emulator' Android.", - "loc.input.label.deleteAvd": "Elimina AVD" -} \ No newline at end of file diff --git a/Tasks/AndroidBuild/Strings/resources.resjson/ja-jp/resources.resjson b/Tasks/AndroidBuild/Strings/resources.resjson/ja-jp/resources.resjson deleted file mode 100644 index f56d8041c1cd..000000000000 --- a/Tasks/AndroidBuild/Strings/resources.resjson/ja-jp/resources.resjson +++ /dev/null @@ -1,34 +0,0 @@ -{ - "loc.friendlyName": "Android のビルド (非推奨。Gradle をご使用ください)", - "loc.helpMarkDown": "[More Information](https://go.microsoft.com/fwlink/?LinkID=613716)", - "loc.description": "Gradle を使用して Android アプリを作成し、必要に応じて単体テストのエミュレーターを起動します", - "loc.instanceNameFormat": "Android のビルド $(gradleProj)", - "loc.group.displayName.avdOptions": "Android 仮想デバイス (AVD) のオプション", - "loc.group.displayName.emulatorOptions": "エミュレーター オプション", - "loc.input.label.gradleWrapper": "Gradle ラッパーの場所", - "loc.input.label.gradleProj": "プロジェクト ディレクトリ", - "loc.input.label.gradleArguments": "Gradle の引数", - "loc.input.label.avdName": "名前", - "loc.input.help.avdName": "起動または作成する Android 仮想デバイス (AVD) の名前。", - "loc.input.label.createAvd": "AVD の作成", - "loc.input.help.createAvd": "名前が指定された Android 仮想デバイス (AVD) を作成します。", - "loc.input.label.emulatorTarget": "AVD のターゲット SDK", - "loc.input.help.emulatorTarget": "新しい Android 仮想デバイス (AVD) のターゲット ID。", - "loc.input.label.emulatorDevice": "AVD デバイス", - "loc.input.help.emulatorDevice": "The optional device definition to use. Can be a device index or ID.", - "loc.input.label.avdAbi": "AVD ABI", - "loc.input.help.avdAbi": "Android 仮想デバイス (AVD) で使用する ABI。", - "loc.input.label.avdForce": "既存の AVD の上書き", - "loc.input.help.avdForce": "'android create avd' コマンドに --force を渡しています。", - "loc.input.label.avdOptionalArgs": "AVD の省略可能な引数の作成", - "loc.input.help.avdOptionalArgs": "'Android 作成 avd' に渡すその他の引数。", - "loc.input.label.startEmulator": "Android エミュレーターの開始と停止", - "loc.input.help.startEmulator": "Android エミュレーターを起動し、このタスクが終了したらエミュレーターを停止します。", - "loc.input.label.emulatorTimeout": "タイムアウト (秒)", - "loc.input.help.emulatorTimeout": "エミュレーターが起動するまでビルドが待機する時間。", - "loc.input.label.emulatorHeadless": "ヘッドレス表示", - "loc.input.help.emulatorHeadless": "エミュレーターの起動時に '-no-skin -no-audio -no-window' を使用します。", - "loc.input.label.emulatorOptionalArgs": "エミュレーターの省略可能な引数", - "loc.input.help.emulatorOptionalArgs": "Android の 'tools\\emulator' に渡すその他の引数。", - "loc.input.label.deleteAvd": "AVD の削除" -} \ No newline at end of file diff --git a/Tasks/AndroidBuild/Strings/resources.resjson/ko-KR/resources.resjson b/Tasks/AndroidBuild/Strings/resources.resjson/ko-KR/resources.resjson deleted file mode 100644 index 1c3a3d23a1e5..000000000000 --- a/Tasks/AndroidBuild/Strings/resources.resjson/ko-KR/resources.resjson +++ /dev/null @@ -1,34 +0,0 @@ -{ - "loc.friendlyName": "Android 빌드(사용되지 않음, Gradle 사용)", - "loc.helpMarkDown": "[More Information](https://go.microsoft.com/fwlink/?LinkID=613716)", - "loc.description": "Gradle을 사용하여 Android 앱을 빌드하고 원하는 경우 단위 테스트를 수행하기 위해 에뮬레이터 시작할 수 있습니다.", - "loc.instanceNameFormat": "Android 빌드 $(gradleProj)", - "loc.group.displayName.avdOptions": "AVD(Android 가상 장치) 옵션", - "loc.group.displayName.emulatorOptions": "에뮬레이터 옵션", - "loc.input.label.gradleWrapper": "Gradle 래퍼 위치", - "loc.input.label.gradleProj": "프로젝트 디렉터리", - "loc.input.label.gradleArguments": "Gradle 인수", - "loc.input.label.avdName": "이름", - "loc.input.help.avdName": "시작하거나 만들 AVD(Android 가상 장치)의 이름입니다.", - "loc.input.label.createAvd": "AVD 만들기", - "loc.input.help.createAvd": "명명된 AVD(Android 가상 장치)를 만듭니다.", - "loc.input.label.emulatorTarget": "AVD 대상 SDK", - "loc.input.help.emulatorTarget": "새 AVD(Android 가상 장치)의 대상 ID입니다.", - "loc.input.label.emulatorDevice": "AVD 장치", - "loc.input.help.emulatorDevice": "The optional device definition to use. Can be a device index or ID.", - "loc.input.label.avdAbi": "AVD ABI", - "loc.input.help.avdAbi": "AVD(Android 가상 장치)에 사용할 ABI입니다.", - "loc.input.label.avdForce": "기존 AVD 덮어쓰기", - "loc.input.help.avdForce": "'android create avd' 명령에 --force를 전달하는 중입니다.", - "loc.input.label.avdOptionalArgs": "AVD 선택적 인수 만들기", - "loc.input.help.avdOptionalArgs": "추가 인수를 'android create avd'에 전달했습니다.", - "loc.input.label.startEmulator": "Android 에뮬레이터 시작 및 중지", - "loc.input.help.startEmulator": "Android 에뮬레이터를 시작하고 이 작업이 끝나면 에뮬레이터를 중지하세요.", - "loc.input.label.emulatorTimeout": "시간 제한(초)", - "loc.input.help.emulatorTimeout": "빌드에서 에뮬레이터가 시작될 때까지 대기하는 시간입니다.", - "loc.input.label.emulatorHeadless": "헤드리스 표시", - "loc.input.help.emulatorHeadless": "에뮬레이터를 시작할 때 '-no-skin -no-audio -no-window'를 사용하세요.", - "loc.input.label.emulatorOptionalArgs": "에뮬레이터 선택적 인수", - "loc.input.help.emulatorOptionalArgs": "추가 인수를 Android 'tools\\emulator'에 전달했습니다.", - "loc.input.label.deleteAvd": "AVD 삭제" -} \ No newline at end of file diff --git a/Tasks/AndroidBuild/Strings/resources.resjson/ru-RU/resources.resjson b/Tasks/AndroidBuild/Strings/resources.resjson/ru-RU/resources.resjson deleted file mode 100644 index d345643e3084..000000000000 --- a/Tasks/AndroidBuild/Strings/resources.resjson/ru-RU/resources.resjson +++ /dev/null @@ -1,34 +0,0 @@ -{ - "loc.friendlyName": "Сборка Android (не рекомендуется; используйте Gradle)", - "loc.helpMarkDown": "[More Information](https://go.microsoft.com/fwlink/?LinkID=613716)", - "loc.description": "Сборка приложения Android с помощью Gradle и при необходимости запуск эмулятора для модульных тестов", - "loc.instanceNameFormat": "Сборка Android $(gradleProj)", - "loc.group.displayName.avdOptions": "Параметры виртуального устройства Android (AVD)", - "loc.group.displayName.emulatorOptions": "Параметры эмулятора", - "loc.input.label.gradleWrapper": "Расположение программы-оболочки Gradle", - "loc.input.label.gradleProj": "Каталог проекта", - "loc.input.label.gradleArguments": "Аргументы Gradle", - "loc.input.label.avdName": "Имя", - "loc.input.help.avdName": "Имя запускаемого или создаваемого виртуального устройства Android (AVD).", - "loc.input.label.createAvd": "Создать AVD", - "loc.input.help.createAvd": "Создание именованного виртуального устройства Android (AVD).", - "loc.input.label.emulatorTarget": "Целевой пакет SDK AVD", - "loc.input.help.emulatorTarget": "Целевой идентификатор нового виртуального устройства Android (AVD).", - "loc.input.label.emulatorDevice": "Устройство AVD", - "loc.input.help.emulatorDevice": "The optional device definition to use. Can be a device index or ID.", - "loc.input.label.avdAbi": "AVD ABI", - "loc.input.help.avdAbi": "ABI, используемый для виртуального устройства Android (AVD).", - "loc.input.label.avdForce": "Перезаписать существующее устройство AVD", - "loc.input.help.avdForce": "Передача параметра --force в команду \"android create avd\".", - "loc.input.label.avdOptionalArgs": "Создать дополнительные аргументы AVD", - "loc.input.help.avdOptionalArgs": "Дополнительные аргументы, передаваемые команде \"android create avd\".", - "loc.input.label.startEmulator": "Запуск и остановка эмулятора Android", - "loc.input.help.startEmulator": "Запустите эмулятор Android и остановите его после завершения задачи.", - "loc.input.label.emulatorTimeout": "Время ожидания в секундах", - "loc.input.help.emulatorTimeout": "Время ожидания сборкой запуска эмулятора.", - "loc.input.label.emulatorHeadless": "Виртуальный дисплей", - "loc.input.help.emulatorHeadless": "Используйте параметры \"-no-skin -no-audio -no-window\" при запуске эмулятора.", - "loc.input.label.emulatorOptionalArgs": "Дополнительные аргументы эмулятора", - "loc.input.help.emulatorOptionalArgs": "Дополнительные аргументы, передаваемые команде Android \"tools\\emulator\".", - "loc.input.label.deleteAvd": "Удалить AVD" -} \ No newline at end of file diff --git a/Tasks/AndroidBuild/Strings/resources.resjson/zh-CN/resources.resjson b/Tasks/AndroidBuild/Strings/resources.resjson/zh-CN/resources.resjson deleted file mode 100644 index 584eb2c99734..000000000000 --- a/Tasks/AndroidBuild/Strings/resources.resjson/zh-CN/resources.resjson +++ /dev/null @@ -1,34 +0,0 @@ -{ - "loc.friendlyName": "Android 生成(已弃用; 使用 Gradle)", - "loc.helpMarkDown": "[More Information](https://go.microsoft.com/fwlink/?LinkID=613716)", - "loc.description": "使用 Gradle 生成 Android 应用,可选择启动用于单元测试的仿真器", - "loc.instanceNameFormat": "Android 版本 $(gradleProj)", - "loc.group.displayName.avdOptions": "Android 虚拟设备(AVD)选项", - "loc.group.displayName.emulatorOptions": "模拟器选项", - "loc.input.label.gradleWrapper": "Gradle 包装器的位置", - "loc.input.label.gradleProj": "项目目录", - "loc.input.label.gradleArguments": "Gradle 参数", - "loc.input.label.avdName": "名称", - "loc.input.help.avdName": "要启动或创建的 Android 虚拟设备(AVD)的名称。", - "loc.input.label.createAvd": "创建 AVD", - "loc.input.help.createAvd": "创建命名 Android 虚拟设备(AVD)。", - "loc.input.label.emulatorTarget": "AVD 目标 SDK", - "loc.input.help.emulatorTarget": "新 Android 虚拟设备(AVD)的目标 ID。", - "loc.input.label.emulatorDevice": "AVD 设备", - "loc.input.help.emulatorDevice": "The optional device definition to use. Can be a device index or ID.", - "loc.input.label.avdAbi": "AVD ABI", - "loc.input.help.avdAbi": "要用于 Android 虚拟设备(AVD)的 ABI。", - "loc.input.label.avdForce": "覆盖现有 AVD", - "loc.input.help.avdForce": "正在将 --force 传递到 \"android create avd\" 命令。", - "loc.input.label.avdOptionalArgs": "创建 AVD 可选参数", - "loc.input.help.avdOptionalArgs": "传递给 \"android create avd\" 的其他参数。", - "loc.input.label.startEmulator": "启动和停止 Android 仿真程序", - "loc.input.help.startEmulator": "启动 Android 仿真程序,然后在此任务完成之后停止仿真程序。", - "loc.input.label.emulatorTimeout": "超时秒数", - "loc.input.help.emulatorTimeout": "生成会等待仿真程序启动的时间长度。", - "loc.input.label.emulatorHeadless": "无外设显示", - "loc.input.help.emulatorHeadless": "启动仿真程序时使用 \"-no-skin -no-audio -no-window\"。", - "loc.input.label.emulatorOptionalArgs": "仿真程序可选参数", - "loc.input.help.emulatorOptionalArgs": "传递给 Android \"tools\\emulator\" 的其他参数。", - "loc.input.label.deleteAvd": "删除 AVD" -} \ No newline at end of file diff --git a/Tasks/AndroidBuild/Strings/resources.resjson/zh-TW/resources.resjson b/Tasks/AndroidBuild/Strings/resources.resjson/zh-TW/resources.resjson deleted file mode 100644 index c9058d5faf05..000000000000 --- a/Tasks/AndroidBuild/Strings/resources.resjson/zh-TW/resources.resjson +++ /dev/null @@ -1,34 +0,0 @@ -{ - "loc.friendlyName": "Android 組建 (已取代; 使用 Gradle)", - "loc.helpMarkDown": "[More Information](https://go.microsoft.com/fwlink/?LinkID=613716)", - "loc.description": "使用 Gradle 建置 Android 應用程式,並選擇性地啟動模擬器進行單元測試", - "loc.instanceNameFormat": "Android 組建 $(gradleProj)", - "loc.group.displayName.avdOptions": "Android 虛擬裝置 (AVD) 選項", - "loc.group.displayName.emulatorOptions": "模擬器選項", - "loc.input.label.gradleWrapper": "Gradle 包裝函式的位置", - "loc.input.label.gradleProj": "專案目錄", - "loc.input.label.gradleArguments": "Gradle 引數", - "loc.input.label.avdName": "名稱", - "loc.input.help.avdName": "要啟動或建立的 Android 虛擬裝置 (AVD) 的名稱。", - "loc.input.label.createAvd": "建立 AVD", - "loc.input.help.createAvd": "建立具名 Android 虛擬裝置 (AVD)。", - "loc.input.label.emulatorTarget": "AVD 目標 SDK", - "loc.input.help.emulatorTarget": "新 Android 虛擬裝置 (AVD) 的目標 ID。", - "loc.input.label.emulatorDevice": "AVD 裝置", - "loc.input.help.emulatorDevice": "The optional device definition to use. Can be a device index or ID.", - "loc.input.label.avdAbi": "AVD ABI", - "loc.input.help.avdAbi": "Android 虛擬裝置 (AVD) 要使用的 ABI。 ", - "loc.input.label.avdForce": "覆寫現有 AVD", - "loc.input.help.avdForce": "傳遞中 -- 強制使用 'android create avd' 命令。", - "loc.input.label.avdOptionalArgs": "建立 AVD 選擇性引數", - "loc.input.help.avdOptionalArgs": "傳遞至 'android create avd' 的額外引數。", - "loc.input.label.startEmulator": "啟動和停止 Android 模擬器", - "loc.input.help.startEmulator": "啟動 Android 模擬器並在此工作完成後停止模擬器。", - "loc.input.label.emulatorTimeout": "逾時 (以秒為單位)", - "loc.input.help.emulatorTimeout": "組建將等候模擬器啟動的時間。", - "loc.input.label.emulatorHeadless": "無周邊顯示", - "loc.input.help.emulatorHeadless": "啟動模擬器時使用 '-no-skin -no-audio -no-window'。", - "loc.input.label.emulatorOptionalArgs": "模擬器選擇性引數", - "loc.input.help.emulatorOptionalArgs": "傳遞至 Android 'tools\\emulator' 的額外引數。", - "loc.input.label.deleteAvd": "刪除 AVD" -} \ No newline at end of file diff --git a/Tasks/AndroidBuild/icon.png b/Tasks/AndroidBuild/icon.png deleted file mode 100644 index f37ee8513ede..000000000000 Binary files a/Tasks/AndroidBuild/icon.png and /dev/null differ diff --git a/Tasks/AndroidBuild/icon.svg b/Tasks/AndroidBuild/icon.svg deleted file mode 100644 index a3c36c652328..000000000000 --- a/Tasks/AndroidBuild/icon.svg +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - diff --git a/Tasks/AndroidBuild/task.json b/Tasks/AndroidBuild/task.json deleted file mode 100644 index b8716c9b836f..000000000000 --- a/Tasks/AndroidBuild/task.json +++ /dev/null @@ -1,180 +0,0 @@ -{ - "id": "DF857559-8715-46EB-A74E-AC98B9178AA0", - "name": "AndroidBuild", - "friendlyName": "Android Build (deprecated; use Gradle)", - "description": "Build an Android app using Gradle and optionally start the emulator for unit tests", - "helpMarkDown": "[More Information](https://go.microsoft.com/fwlink/?LinkID=613716)", - "category": "Build", - "visibility": [ - "Build" - ], - "author": "Microsoft Corporation", - "version": { - "Major": 1, - "Minor": 0, - "Patch": 15 - }, - "demands": [ - "AndroidSDK" - ], - "minimumAgentVersion": "1.83.0", - "groups": [ - { - "name": "avdOptions", - "displayName": "Android Virtual Device (AVD) Options", - "isExpanded": true - }, - { - "name": "emulatorOptions", - "displayName": "Emulator Options", - "isExpanded": true - } - ], - "inputs": [ - { - "name": "gradleWrapper", - "type": "filePath", - "label": "Location of Gradle Wrapper", - "defaultValue": "", - "required": false - }, - { - "name": "gradleProj", - "type": "filePath", - "label": "Project Directory", - "defaultValue": "", - "required": false - }, - { - "name": "gradleArguments", - "type": "string", - "label": "Gradle Arguments", - "defaultValue": "build", - "required": false - }, - { - "name": "avdName", - "type": "string", - "label": "Name", - "defaultValue": "AndroidBuildEmulator", - "required": true, - "helpMarkDown": "Name of the Android Virtual Device (AVD) to be started or created.", - "groupName": "avdOptions" - }, - { - "name": "createAvd", - "type": "boolean", - "label": "Create AVD", - "defaultValue": "AndroidBuildEmulator", - "required": false, - "helpMarkDown": "Create the named Android Virtual Device (AVD).", - "groupName": "avdOptions" - }, - { - "name": "emulatorTarget", - "type": "string", - "label": "AVD Target SDK", - "defaultValue": "android-19", - "required": true, - "visibleRule": "createAvd = true", - "helpMarkDown": "Target ID of the new Android Virtual Device (AVD).", - "groupName": "avdOptions" - }, - { - "name": "emulatorDevice", - "type": "string", - "label": "AVD Device", - "defaultValue": "Nexus 5", - "required": false, - "visibleRule": "createAvd = true", - "helpMarkDown": "The optional device definition to use. Can be a device index or ID.", - "groupName": "avdOptions" - }, - { - "name": "avdAbi", - "type": "string", - "label": "AVD ABI", - "defaultValue": "default/armeabi-v7a", - "required": true, - "visibleRule": "createAvd = true", - "helpMarkDown": "The ABI to use for the Android Virtual Device (AVD).", - "groupName": "avdOptions" - }, - { - "name": "avdForce", - "type": "boolean", - "label": "Overwrite Existing AVD", - "defaultValue": false, - "required": false, - "visibleRule": "createAvd = true", - "helpMarkDown": "Passing --force to 'android create avd' command.", - "groupName": "avdOptions" - }, - { - "name": "avdOptionalArgs", - "type": "string", - "label": "Create AVD Optional Arguments", - "defaultValue": "", - "required": false, - "visibleRule": "createAvd = true", - "helpMarkDown": "Additional arguments passed to 'android create avd'.", - "groupName": "avdOptions" - }, - { - "name": "startEmulator", - "type": "boolean", - "label": "Start and Stop Android Emulator", - "defaultValue": false, - "required": false, - "helpMarkDown": "Start Android emulator and stop emulator after this task finishes.", - "groupName": "emulatorOptions" - }, - { - "name": "emulatorTimeout", - "type": "string", - "label": "Timeout in Seconds", - "defaultValue": "300", - "required": true, - "visibleRule": "startEmulator = true", - "helpMarkDown": "How long build will wait for the emulator to start.", - "groupName": "emulatorOptions" - }, - { - "name": "emulatorHeadless", - "type": "boolean", - "label": "Headless Display", - "defaultValue": false, - "required": false, - "visibleRule": "startEmulator = true", - "helpMarkDown": "Use '-no-skin -no-audio -no-window' when start the emulator.", - "groupName": "emulatorOptions" - }, - { - "name": "emulatorOptionalArgs", - "type": "string", - "label": "Emulator Optional Arguments", - "defaultValue": "-no-snapshot-load -no-snapshot-save", - "required": false, - "visibleRule": "startEmulator = true", - "helpMarkDown": "Additional arguments passed to Android 'tools\\emulator'.", - "groupName": "emulatorOptions" - }, - { - "name": "deleteAvd", - "type": "boolean", - "label": "Delete AVD", - "defaultValue": false, - "required": false, - "visibleRule": "startEmulator = true", - "groupName": "emulatorOptions" - } - ], - "instanceNameFormat": "Android Build $(gradleProj)", - "execution": { - "PowerShell": { - "target": "$(currentDirectory)\\AndroidBuild.ps1", - "argumentFormat": "", - "workingDirectory": "$(currentDirectory)" - } - } -} \ No newline at end of file diff --git a/Tasks/AndroidBuild/task.loc.json b/Tasks/AndroidBuild/task.loc.json deleted file mode 100644 index 1acc7e5123bf..000000000000 --- a/Tasks/AndroidBuild/task.loc.json +++ /dev/null @@ -1,180 +0,0 @@ -{ - "id": "DF857559-8715-46EB-A74E-AC98B9178AA0", - "name": "AndroidBuild", - "friendlyName": "ms-resource:loc.friendlyName", - "description": "ms-resource:loc.description", - "helpMarkDown": "ms-resource:loc.helpMarkDown", - "category": "Build", - "visibility": [ - "Build" - ], - "author": "Microsoft Corporation", - "version": { - "Major": 1, - "Minor": 0, - "Patch": 15 - }, - "demands": [ - "AndroidSDK" - ], - "minimumAgentVersion": "1.83.0", - "groups": [ - { - "name": "avdOptions", - "displayName": "ms-resource:loc.group.displayName.avdOptions", - "isExpanded": true - }, - { - "name": "emulatorOptions", - "displayName": "ms-resource:loc.group.displayName.emulatorOptions", - "isExpanded": true - } - ], - "inputs": [ - { - "name": "gradleWrapper", - "type": "filePath", - "label": "ms-resource:loc.input.label.gradleWrapper", - "defaultValue": "", - "required": false - }, - { - "name": "gradleProj", - "type": "filePath", - "label": "ms-resource:loc.input.label.gradleProj", - "defaultValue": "", - "required": false - }, - { - "name": "gradleArguments", - "type": "string", - "label": "ms-resource:loc.input.label.gradleArguments", - "defaultValue": "build", - "required": false - }, - { - "name": "avdName", - "type": "string", - "label": "ms-resource:loc.input.label.avdName", - "defaultValue": "AndroidBuildEmulator", - "required": true, - "helpMarkDown": "ms-resource:loc.input.help.avdName", - "groupName": "avdOptions" - }, - { - "name": "createAvd", - "type": "boolean", - "label": "ms-resource:loc.input.label.createAvd", - "defaultValue": "AndroidBuildEmulator", - "required": false, - "helpMarkDown": "ms-resource:loc.input.help.createAvd", - "groupName": "avdOptions" - }, - { - "name": "emulatorTarget", - "type": "string", - "label": "ms-resource:loc.input.label.emulatorTarget", - "defaultValue": "android-19", - "required": true, - "visibleRule": "createAvd = true", - "helpMarkDown": "ms-resource:loc.input.help.emulatorTarget", - "groupName": "avdOptions" - }, - { - "name": "emulatorDevice", - "type": "string", - "label": "ms-resource:loc.input.label.emulatorDevice", - "defaultValue": "Nexus 5", - "required": false, - "visibleRule": "createAvd = true", - "helpMarkDown": "ms-resource:loc.input.help.emulatorDevice", - "groupName": "avdOptions" - }, - { - "name": "avdAbi", - "type": "string", - "label": "ms-resource:loc.input.label.avdAbi", - "defaultValue": "default/armeabi-v7a", - "required": true, - "visibleRule": "createAvd = true", - "helpMarkDown": "ms-resource:loc.input.help.avdAbi", - "groupName": "avdOptions" - }, - { - "name": "avdForce", - "type": "boolean", - "label": "ms-resource:loc.input.label.avdForce", - "defaultValue": false, - "required": false, - "visibleRule": "createAvd = true", - "helpMarkDown": "ms-resource:loc.input.help.avdForce", - "groupName": "avdOptions" - }, - { - "name": "avdOptionalArgs", - "type": "string", - "label": "ms-resource:loc.input.label.avdOptionalArgs", - "defaultValue": "", - "required": false, - "visibleRule": "createAvd = true", - "helpMarkDown": "ms-resource:loc.input.help.avdOptionalArgs", - "groupName": "avdOptions" - }, - { - "name": "startEmulator", - "type": "boolean", - "label": "ms-resource:loc.input.label.startEmulator", - "defaultValue": false, - "required": false, - "helpMarkDown": "ms-resource:loc.input.help.startEmulator", - "groupName": "emulatorOptions" - }, - { - "name": "emulatorTimeout", - "type": "string", - "label": "ms-resource:loc.input.label.emulatorTimeout", - "defaultValue": "300", - "required": true, - "visibleRule": "startEmulator = true", - "helpMarkDown": "ms-resource:loc.input.help.emulatorTimeout", - "groupName": "emulatorOptions" - }, - { - "name": "emulatorHeadless", - "type": "boolean", - "label": "ms-resource:loc.input.label.emulatorHeadless", - "defaultValue": false, - "required": false, - "visibleRule": "startEmulator = true", - "helpMarkDown": "ms-resource:loc.input.help.emulatorHeadless", - "groupName": "emulatorOptions" - }, - { - "name": "emulatorOptionalArgs", - "type": "string", - "label": "ms-resource:loc.input.label.emulatorOptionalArgs", - "defaultValue": "-no-snapshot-load -no-snapshot-save", - "required": false, - "visibleRule": "startEmulator = true", - "helpMarkDown": "ms-resource:loc.input.help.emulatorOptionalArgs", - "groupName": "emulatorOptions" - }, - { - "name": "deleteAvd", - "type": "boolean", - "label": "ms-resource:loc.input.label.deleteAvd", - "defaultValue": false, - "required": false, - "visibleRule": "startEmulator = true", - "groupName": "emulatorOptions" - } - ], - "instanceNameFormat": "ms-resource:loc.instanceNameFormat", - "execution": { - "PowerShell": { - "target": "$(currentDirectory)\\AndroidBuild.ps1", - "argumentFormat": "", - "workingDirectory": "$(currentDirectory)" - } - } -} \ No newline at end of file diff --git a/Tasks/ArchiveFiles/task.json b/Tasks/ArchiveFiles/task.json index f115270c451d..e7f37f17c4db 100644 --- a/Tasks/ArchiveFiles/task.json +++ b/Tasks/ArchiveFiles/task.json @@ -9,12 +9,16 @@ "visibility": [ "Build", "Release" + ], + "runsOn": [ + "Agent", + "MachineGroup" ], "demands": [], "version": { "Major": 1, "Minor": 0, - "Patch": 8 + "Patch": 9 }, "groups": [ { diff --git a/Tasks/ArchiveFiles/task.loc.json b/Tasks/ArchiveFiles/task.loc.json index 870e25e44e8a..25c41c5cf3d3 100644 --- a/Tasks/ArchiveFiles/task.loc.json +++ b/Tasks/ArchiveFiles/task.loc.json @@ -10,11 +10,15 @@ "Build", "Release" ], + "runsOn": [ + "Agent", + "MachineGroup" + ], "demands": [], "version": { "Major": 1, "Minor": 0, - "Patch": 8 + "Patch": 9 }, "groups": [ { diff --git a/Tasks/AzureAppServiceManage/task.loc.json b/Tasks/AzureAppServiceManage/task.loc.json index b71ef22fbf00..8550f829834b 100644 --- a/Tasks/AzureAppServiceManage/task.loc.json +++ b/Tasks/AzureAppServiceManage/task.loc.json @@ -140,4 +140,4 @@ "Successfullyswappedslots": "ms-resource:loc.messages.Successfullyswappedslots", "SourceAndTargetSlotCannotBeSame": "ms-resource:loc.messages.SourceAndTargetSlotCannotBeSame" } -} +} \ No newline at end of file diff --git a/Tasks/AzureCLI/task.json b/Tasks/AzureCLI/task.json index f9222b3090c2..06de40fd23a8 100644 --- a/Tasks/AzureCLI/task.json +++ b/Tasks/AzureCLI/task.json @@ -11,13 +11,14 @@ "Release" ], "runsOn": [ - "Agent" + "Agent", + "MachineGroup" ], "demands": [], "version": { "Major": 0, "Minor": 2, - "Patch": 4 + "Patch": 5 }, "minimumAgentVersion": "1.95.0", "instanceNameFormat": "Azure CLI $(scriptPath)", diff --git a/Tasks/AzureCLI/task.loc.json b/Tasks/AzureCLI/task.loc.json index be50131c695c..d831e968810b 100644 --- a/Tasks/AzureCLI/task.loc.json +++ b/Tasks/AzureCLI/task.loc.json @@ -11,13 +11,14 @@ "Release" ], "runsOn": [ - "Agent" + "Agent", + "MachineGroup" ], "demands": [], "version": { "Major": 0, "Minor": 2, - "Patch": 4 + "Patch": 5 }, "minimumAgentVersion": "1.95.0", "instanceNameFormat": "ms-resource:loc.instanceNameFormat", diff --git a/Tasks/AzureFileCopy/Tests/L0.ts b/Tasks/AzureFileCopy/Tests/L0.ts new file mode 100644 index 000000000000..a54298f3330a --- /dev/null +++ b/Tasks/AzureFileCopy/Tests/L0.ts @@ -0,0 +1,112 @@ +/// +/// +/// + +import Q = require('q'); +import assert = require('assert'); +import path = require('path'); + +var psm = require('../../../Tests/lib/psRunner'); +var shell = require('shelljs'); +var ps = shell.which('powershell.exe'); +var psr = null; + +describe('AzureFileCopy Suite', function () { + this.timeout(20000); + + before((done) => { + if (ps) { + psr = new psm.PSRunner(); + psr.start(); + } + done(); + }); + + after(function () { + psr.kill(); + }); + + if(ps) { + it('Validate AzureFileCopy.Utility Get-AzureUtility', (done) => { + psr.run(path.join(__dirname, 'L0GetAzureUtility.ps1'), done); + }); + it('Validate AzureFileCopy.Utility Validate-AzurePowershellVersion', (done) => { + psr.run(path.join(__dirname, 'L0ValidateAzurePSVersion.ps1'), done); + }); + it('Validate AzureFileCopy.Utility Get-StorageKey', (done) => { + psr.run(path.join(__dirname, 'L0GetStorageKey.ps1'), done); + }); + it('Validate AzureFileCopy.Utility Get-StorageAccountType', (done) => { + psr.run(path.join(__dirname, 'L0GetStorageAccountType.ps1'), done); + }); + it('Validate AzureFileCopy.Utility Get-blobStorageEndpoint', (done) => { + psr.run(path.join(__dirname, 'L0GetblobStorageEndpoint.ps1'), done); + }); + it('Validate AzureFileCopy.Utility Get-StorageKey', (done) => { + psr.run(path.join(__dirname, 'L0UtilityThrowError.ps1'), done); + }); + it('Validate AzureFileCopy.Utility Upload-FilesToAzureContainer', (done) => { + psr.run(path.join(__dirname, 'L0UploadFilesToAzureContainer.ps1'), done); + }); + it('Validate AzureFileCopy.Utility Does-AzureVMMatchTagFilterCriteria', (done) => { + psr.run(path.join(__dirname, 'L0DoesAzureVMMatchTagFilter.ps1'), done); + }); + it('Validate AzureFileCopy.Utility Get-TagBasedFilteredAzureVMs', (done) => { + psr.run(path.join(__dirname, 'L0GetTagBasedFilteredAzureVMs.ps1'), done); + }); + it('Validate AzureFileCopy.Utility Get-MachineBasedFilteredAzureVMs', (done) => { + psr.run(path.join(__dirname, 'L0GetMachineBasedFilteredAzureVMs.ps1'), done); + }); + it('Validate AzureFileCopy.Utility Get-FilteredAzureVMsInResourceGroup', (done) => { + psr.run(path.join(__dirname, 'L0GetFilteredAzureVmsInResourceGroup.ps1'), done); + }); + it('Validate AzureFileCopy.Utility Get-FilteredAzureClassicVMsInResourceGroup', (done) => { + psr.run(path.join(__dirname, 'L0GetFilteredAzureClassicVmsInRG.ps1'), done); + }); + it('Validate AzureFileCopy.Utility Get-FilteredAzureRMVMsInResourceGroup', (done) => { + psr.run(path.join(__dirname, 'L0GetFilteredAzureRMVmsInResourceGroup.ps1'), done); + }); + it('Validate AzureFileCopy.Utility Get-MachineNameFromId', (done) => { + psr.run(path.join(__dirname, 'L0GetMachineNameFromId.ps1'), done); + }); + it('Validate AzureFileCopy.Utility Get-MachinesFqdnsForLB', (done) => { + psr.run(path.join(__dirname, 'L0GetMachinesFqdnForLB.ps1'), done); + }); + it('Validate AzureFileCopy.Utility Get-FrontEndPorts', (done) => { + psr.run(path.join(__dirname, 'L0GetFrontEndPorts.ps1'), done); + }); + it('Validate AzureFileCopy.Utility Get-AzureRMVMsConnectionDetailsInResourceGroup', (done) => { + psr.run(path.join(__dirname, 'L0GetRMVMConnectionDetailsInRG.ps1'), done); + }); + it('Validate AzureFileCopy.Utility Check-AzureCloudServiceExists', (done) => { + psr.run(path.join(__dirname, 'L0CheckCloudServiceExists.ps1'), done); + }); + it('Validate AzureFileCopy.Utility Get-AzureVMResourcesProperties', (done) => { + psr.run(path.join(__dirname, 'L0GetAzureVMResourcesProperties.ps1'), done); + }); + it('Validate AzureFileCopy.Utility Get-SkipCACheckOption', (done) => { + psr.run(path.join(__dirname, 'L0GetSkipCACheckOption.ps1'), done); + }); + it('Validate AzureFileCopy.Utility Get-AzureVMsCredentials', (done) => { + psr.run(path.join(__dirname, 'L0GetAzureVMsCredentials.ps1'), done); + }); + it('Validate AzureFileCopy.Utility Copy-FilesParallelyToAzureVMs', (done) => { + psr.run(path.join(__dirname, 'L0CopyFilesParallelyToAzureVMs.ps1'), done); + }); + it('Validate AzureFileCopy.Utility Copy-FilesToAzureVMsFromStorageContainer', (done) => { + psr.run(path.join(__dirname, 'L0CopyFilesToAzureVMsFromStorageContainer.ps1'), done); + }); + it('Validate AzureFileCopy.Utility Validate-CustomScriptExecutionStatus', (done) => { + psr.run(path.join(__dirname, 'L0ValidateCustomScriptExecutionStatus.ps1'), done); + }); + it('Validate AzureFileCopy.Utility Add-AzureVMCustomScriptExtension', (done) => { + psr.run(path.join(__dirname, 'L0AddAzureVMCustomScriptExtension.ps1'), done); + }); + it('Validate AzureFileCopy.Utility Is-WinRMCustomScriptExtensionExists', (done) => { + psr.run(path.join(__dirname, 'L0IsWinRMCustomScriptExtensionExists.ps1'), done); + }); + it('Validate AzureFileCopy.Utility Copy-FilesSequentiallyToAzureVMs', (done) => { + psr.run(path.join(__dirname, 'L0CopyFilesSequentiallyToAzureVMs.ps1'), done); + }); + } +}); diff --git a/Tasks/AzureFileCopy/Tests/L0AddAzureVMCustomScriptExtension.ps1 b/Tasks/AzureFileCopy/Tests/L0AddAzureVMCustomScriptExtension.ps1 new file mode 100644 index 000000000000..2fad79a0ce96 --- /dev/null +++ b/Tasks/AzureFileCopy/Tests/L0AddAzureVMCustomScriptExtension.ps1 @@ -0,0 +1,67 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 +. $PSScriptRoot\MockVariable.ps1 +. $PSScriptRoot\..\Utility.ps1 +. $PSScriptRoot\MockHelper.ps1 + +Register-Mock Write-Telemetry { } + +# Test 1 "Should throw Resource group name is null" +Assert-Throws { + Add-AzureVMCustomScriptExtension -resourceGroupName $null -vmName $vm0Name -dnsName $azurevmFqdn -location $location -connectedServiceName $connectedServiceName +} -MessagePattern "AFC_CopyPrereqsFailed *" + + +# Test 2 "Should throw when VM name is null" +Assert-Throws { + Add-AzureVMCustomScriptExtension -resourceGroupName $validRG -vmName $null -dnsName $azurevmFqdn -location $location -connectedServiceName $connectedServiceName +} -MessagePattern "AFC_CopyPrereqsFailed *" + +# Test 3 "should throw when VM name is invalid" +Register-Mock Get-Endpoint {} +Assert-Throws { + Add-AzureVMCustomScriptExtension -resourceGroupName $validRG -vmName $invalidMachineName -dnsName $azurevmFqdn -location $location -connectedServiceName $connectedServiceName +} -MessagePattern "AFC_CopyPrereqsFailed AFC_UnableToSetCustomScriptExtension *" + +# Test 4 "Should fail to provision winrm custom script extension and remove the failed extension" +$extensionName="WinRMCustomScriptExtension" +Register-Mock Set-AzureMachineCustomScriptExtension { + return Set-AzureMachineCustomScriptExtension -resourceGroupName $resourceGroupName -vmName $vmName -name $extensionName -fileUri $configWinRMScriptFile, $makeCertFile, $winrmConfFile -run $invalidCustomScriptName -argument $dnsName -location $location +} -ParametersEvaluator { $run -eq $scriptToRun } + +Assert-Throws { + Add-AzureVMCustomScriptExtension -resourceGroupName $validRG -vmName $vm0Name -dnsName $azurevmFqdn -location $location -connectedServiceName $connectedServiceName +} -MessagePattern "AFC_CopyPrereqsFailed *" + +Assert-AreEqual 0 $vmInstanceViews[$vm0Name]["Extensions"].Count + +# Test 5 "Should fail to deploy winrm custom script extension and remove the failed extension" +$extensionName="WinRMCustomScriptExtension" +Unregister-Mock Set-AzureMachineCustomScriptExtension +Register-Mock Set-AzureMachineCustomScriptExtension { + return Set-AzureMachineCustomScriptExtension -resourceGroupName $resourceGroupName -vmName $vmName -name $extensionName -fileUri $configWinRMScriptFile, $makeCertFile -run $invalidCustomScriptName -argument $dnsName -location $location +} -ParametersEvaluator { $run -eq $scriptToRun } + +Assert-Throws { + Add-AzureVMCustomScriptExtension -resourceGroupName $validRG -vmName $vm0Name -dnsName $azurevmFqdn -location $location -connectedServiceName $connectedServiceName +} -MessagePattern "AFC_CopyPrereqsFailed *" + +Assert-AreEqual 0 $vmInstanceViews[$vm0Name]["Extensions"].Count + +# Test 6 "Should configure winrm successfully on target azure vm for valid Input" +Unregister-Mock Set-AzureMachineCustomScriptExtension +Add-AzureVMCustomScriptExtension -resourceGroupName $validRG -vmName $vm0Name -dnsName $azurevmFqdn -location $location -connectedServiceName $connectedServiceName +$tempStatus = Get-AzureMachineStatus -resourceGroupName $validRG -name $vm0Name +$tempStatus.Extensions.Statuses.DisplayStatus.Contains("Provisioning succeeded"); + +# Test 7 "Should skip configuring winrm on target azure vm" +Register-Mock Set-AzureMachineCustomScriptExtension { return $null } +Register-Mock Is-WinRMCustomScriptExtensionExists { return $true } +Add-AzureVMCustomScriptExtension -resourceGroupName $validRG -vmName $vm0Name -dnsName $azurevmFqdn -location $location -connectedServiceName $connectedServiceName + +Assert-WasCalled Set-AzureMachineCustomScriptExtension -Times 0 + +#Clean the extension +$vmInstanceViews[$vm0Name]["Extensions"]=@() \ No newline at end of file diff --git a/Tasks/AzureFileCopy/Tests/L0CheckCloudServiceExists.ps1 b/Tasks/AzureFileCopy/Tests/L0CheckCloudServiceExists.ps1 new file mode 100644 index 000000000000..8e02b8c35950 --- /dev/null +++ b/Tasks/AzureFileCopy/Tests/L0CheckCloudServiceExists.ps1 @@ -0,0 +1,22 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 +. $PSScriptRoot\MockVariable.ps1 +. $PSScriptRoot\..\Utility.ps1 +. $PSScriptRoot\MockHelper.ps1 + +Register-Mock Write-Telemetry { } +$invalidCloudServiceName = "invalidCloudServiceName" + +# Test 1 "It should throw if cloudservice does not exist and connection type is cert" +Assert-Throws { + Check-AzureCloudServiceExists -cloudServiceName $invalidCloudServiceName -connectionType 'Certificate' +} -MessagePattern "AFC_ResourceGroupNotFoundForSelectedConnection *" + +# Test 2 "Should not throw If cloud service exists" +$rgWithClassicVMs = "taskplatformtesttwovm" +Check-AzureCloudServiceExists -cloudServiceName $rgWithClassicVMs -connectionType 'Certificate' + +# Test 3 "Should not throw if cloud service exists and connection type is not cert" +Check-AzureCloudServiceExists -cloudServiceName $invalidCloudServiceName -connectionType 'UserNamePassword' diff --git a/Tasks/AzureFileCopy/Tests/L0CopyFilesParallelyToAzureVMs.ps1 b/Tasks/AzureFileCopy/Tests/L0CopyFilesParallelyToAzureVMs.ps1 new file mode 100644 index 000000000000..3cc448477edb --- /dev/null +++ b/Tasks/AzureFileCopy/Tests/L0CopyFilesParallelyToAzureVMs.ps1 @@ -0,0 +1,71 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 +. $PSScriptRoot\MockVariable.ps1 +. $PSScriptRoot\..\Utility.ps1 +. $PSScriptRoot\MockHelper.ps1 + +$validRG = "AzureFileCopyTaskPlatformTestDoNotDelete" +$vmName = "myVM0" +$vmfqdn = "lbipac2b71e2680c44fd987d.westus.cloudapp.azure.com" +$vmWinRMHttpsPort1 = '40001' +$vmWinRMHttpsPort2 = '40003' +$vmWinRMHttpsPort3 = '40005' +$azureVMsProperties = Get-AzureVMResourcesProperties -resourceGroupName $validRG -connectionType 'ServicePrincipal' -resourceFilteringMethod 'tags' +$azureVMCredntials = Get-AzureVMsCredentials -vmsAdminUserName $validInputVmsAdminUserName -vmsAdminPassword $validInputVmsAdminPassword + +Register-Mock Get-DeploymentModulePath { Write-Output (Join-Path $(Get-Location).Path "Microsoft.TeamFoundation.DistributedTask.Task.DevTestLabs") } + +# Test 1 "Should throw if failed on one vm and passed on other vm" + +Register-Mock Copy-ToAzureMachines { return $failedDeploymentResponseForCopy } -ParametersEvaluator { $WinRMPort -eq $vmWinRMHttpsPort1 } +Register-Mock Copy-ToAzureMachines { return $passedDeploymentResponseForCopy } -ParametersEvaluator { $WinRMPort -eq $vmWinRMHttpsPort2 } +Register-Mock Copy-ToAzureMachines { return $passedLatestDeploymentResponseForCopy } -ParametersEvaluator { $WinRMPort -eq $vmWinRMHttpsPort3 } +Register-Mock Get-ChildItem { return $assembly } +Register-Mock Write-ResponseLogs { } + +Register-Mock Start-Job { $testJobs.Add($failedJob); return $failedJob} -ParametersEvaluator{$ArgumentList -contains $vmWinRMHttpsPort1 } +Register-Mock Start-Job { $testJobs.Add($passedJob); return $passedJob} -ParametersEvaluator{$ArgumentList -contains $vmWinRMHttpsPort2 } +Register-Mock Start-Job { $testJobs.Add($passedLatestJob); return $passedLatestJob} -ParametersEvaluator{$ArgumentList -contains $vmWinRMHttpsPort3 } +Register-Mock Get-Job { return $testJobs } + +Register-Mock Start-Sleep { } + +Register-Mock Receive-Job { return $jobFailedResponse } -ParametersEvaluator{$Id -eq $failedJob.Id} +Register-Mock Receive-Job { return $jobPassedResponse } -ParametersEvaluator{$Id -eq $passedJob.Id} +Register-Mock Receive-Job { return $jobPassedLatestResponse } -ParametersEvaluator{$Id -eq $passedLatestJob.Id} +Register-Mock Remove-Job { $testJobs.RemoveAt(0) } +Register-Mock Write-Telemetry { } + +Assert-Throws { + Copy-FilesParallellyToAzureVMs -storageAccountName $validInputStorageAccount -containerName $validInputContainerName -containerSasToken $validSasToken ` + -targetPath $validInputTargetPath -azCopyLocation $validAzCopyLocation -azureVMResourcesProperties $azureVMsProperties ` + -azureVMsCredentials $azureVMCredntials -cleanTargetBeforeCopy "false" -communicationProtocol '' -skipCACheckOption "false" -enableDetailedLoggingString "false" ` + -additionalArguments "" -connectionType 'ServicePrincipal' +} -MessagePattern "AFC_ParallelCopyFailed*" + +Assert-WasCalled Start-Job -Times 3 +Assert-WasCalled Receive-Job -Times 3 + +# Test 2 "Should not throw if copy passed on both vms" +Unregister-Mock Start-Job +Register-Mock Start-Job { $testJobs.Add($passedJob1); return $passedJob1} -ParametersEvaluator{$ArgumentList -contains $vmWinRMHttpsPort1 } +Register-Mock Start-Job { $testJobs.Add($passedJob); return $passedJob} -ParametersEvaluator{$ArgumentList -contains $vmWinRMHttpsPort2 } +Register-Mock Start-Job { $testJobs.Add($passedLatestJob); return $passedLatestJob} -ParametersEvaluator{$ArgumentList -contains $vmWinRMHttpsPort3 } + +Unregister-Mock Copy-ToAzureMachines +Register-Mock Copy-ToAzureMachines { return $passedDeploymentResponseForCopy } + +Unregister-Mock Remove-Job +Register-Mock Remove-Job { $testJobs.RemoveAt(0) } + +Unregister-Mock Receive-Job +Register-Mock Receive-Job { return $jobPassedResponse } +Copy-FilesParallellyToAzureVMs -storageAccountName $validInputStorageAccount -containerName $validInputContainerName -containerSasToken $validSasToken ` + -targetPath $validInputTargetPath -azCopyLocation $validAzCopyLocation -azureVMResourcesProperties $azureVMsProperties ` + -azureVMsCredentials $azureVMCredntials -cleanTargetBeforeCopy "false" -communicationProtocol '' -skipCACheckOption "false" -enableDetailedLoggingString "false" ` + -additionalArguments "" -connectionType 'ServicePrincipal' + +Assert-WasCalled Start-Job -Times 3 +Assert-WasCalled Receive-Job -Times 3 \ No newline at end of file diff --git a/Tasks/AzureFileCopy/Tests/L0CopyFilesSequentiallyToAzureVMs.ps1 b/Tasks/AzureFileCopy/Tests/L0CopyFilesSequentiallyToAzureVMs.ps1 new file mode 100644 index 000000000000..642d5c96d126 --- /dev/null +++ b/Tasks/AzureFileCopy/Tests/L0CopyFilesSequentiallyToAzureVMs.ps1 @@ -0,0 +1,38 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 +. $PSScriptRoot\MockVariable.ps1 +. $PSScriptRoot\..\Utility.ps1 +. $PSScriptRoot\MockHelper.ps1 +. $PSScriptRoot\..\AzureFileCopyJob.ps1 + +$validRG = "AzureFileCopyTaskPlatformTestDoNotDelete" +$vmName = "myVM0" +$vmfqdn = "lbipac2b71e2680c44fd987d.westus.cloudapp.azure.com" +$vmWinRMHttpsPort = '40003' +$azureVMsProperties = Get-AzureVMResourcesProperties -resourceGroupName $validRG -connectionType 'ServicePrincipal' -resourceFilteringMethod 'tags' +$azureVMCredntials = Get-AzureVMsCredentials -vmsAdminUserName $validInputVmsAdminUserName -vmsAdminPassword $validInputVmsAdminPassword +Register-Mock Get-DeploymentModulePath { Write-Output (Join-Path $(Get-Location).Path "Microsoft.TeamFoundation.DistributedTask.Task.DevTestLabs") } + +Register-Mock Copy-ToAzureMachines { return $failedDeploymentResponseForCopy } -ParameterFilter { $WinRMPort -eq $vmWinRMHttpsPort } +Register-Mock Get-ChildItem { return $assembly } +Register-Mock Write-ResponseLogs { } +Register-Mock Get-AzureStorageAccount { return $null } +Register-Mock Write-Telemetry { } + +# Test 1 "Should throw if failed on one vm" +Assert-Throws { +Copy-FilesSequentiallyToAzureVMs -storageAccountName $validInputStorageAccount -containerName $validInputContainerName -containerSasToken $validSasToken ` + -targetPath $validInputTargetPath -azCopyLocation $validAzCopyLocation -azureVMResourcesProperties $azureVMsProperties ` + -azureVMsCredentials $azureVMCredntials -cleanTargetBeforeCopy "false" -communicationProtocol '' -skipCACheckOption "false" -enableDetailedLoggingString "false" ` + -additionalArguments "" -connectionType "ServicePrincipal" +} -MessagePattern "AFC_WinRMHelpMessage AFC_AzureFileCopyMoreHelp*" + +# Test 2 "Should not throw if copy succeded on both vms" +Register-Mock Copy-ToAzureMachines { return $passedDeploymentResponseForCopy } + + Copy-FilesSequentiallyToAzureVMs -storageAccountName $validInputStorageAccount -containerName $validInputContainerName -containerSasToken $validSasToken ` + -targetPath $validInputTargetPath -azCopyLocation $validAzCopyLocation -azureVMResourcesProperties $azureVMsProperties ` + -azureVMsCredentials $azureVMCredntials -cleanTargetBeforeCopy "false" -communicationProtocol '' -skipCACheckOption "false" -enableDetailedLoggingString "false" ` + -additionalArguments "" -connectionType "ServicePrincipal" diff --git a/Tasks/AzureFileCopy/Tests/L0CopyFilesToAzureVMsFromStorageContainer.ps1 b/Tasks/AzureFileCopy/Tests/L0CopyFilesToAzureVMsFromStorageContainer.ps1 new file mode 100644 index 000000000000..0fcdf33763d4 --- /dev/null +++ b/Tasks/AzureFileCopy/Tests/L0CopyFilesToAzureVMsFromStorageContainer.ps1 @@ -0,0 +1,53 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 +. $PSScriptRoot\MockVariable.ps1 +. $PSScriptRoot\..\Utility.ps1 +. $PSScriptRoot\MockHelper.ps1 + +$rgWithClassicVMs = "taskplatformtesttwovm" +$azureVMsProperties = Get-AzureVMResourcesProperties -resourceGroupName $rgWithClassicVMs -connectionType 'Certificate' -resourceFilteringMethod 'tags' +$azureVMCredntials = Get-AzureVMsCredentials -vmsAdminUserName $validInputVmsAdminUserName -vmsAdminPassword $validInputVmsAdminPassword +$deploymentUtilitiesLocation = Join-Path $(Get-Location).Path "Microsoft.TeamFoundation.DistributedTask.Task.DevTestLabs" + +Register-Mock Copy-FilesParallellyToAzureVMs { } +Register-Mock Copy-FilesSequentiallyToAzureVMs { } + +# Test 1 "Should Call Copy-FilesParallellyToAzureVMs for parallel option" +Copy-FilesToAzureVMsFromStorageContainer -storageAccountName $validInputStorageAccount -containerName $validInputContainerName -containerSasToken $validSasToken ` + -targetPath $validInputTargetPath -azCopyLocation $validAzCopyLocation -resourceGroupName $rgWithClassicVMs -azureVMResourcesProperties $azureVMsProperties ` + -azureVMsCredentials $azureVMCredntials -cleanTargetBeforeCopy "false" -communicationProtocol '' -skipCACheckOption "false" -enableDetailedLoggingString "false" ` + -additionalArguments "" -copyFilesInParallel "true" -connectionType 'ServicePrincipal' + +Assert-WasCalled Copy-FilesParallellyToAzureVMs -Times 1 +Assert-WasCalled Copy-FilesSequentiallyToAzureVMs -Times 0 + + +# Test 2 "should call Copy-FilesSequentiallyToAzureVMs for sequential option with greater than one vm" +Copy-FilesToAzureVMsFromStorageContainer -storageAccountName $validInputStorageAccount -containerName $validInputContainerName -containerSasToken $validSasToken ` + -targetPath $validInputTargetPath -azCopyLocation $validAzCopyLocation -resourceGroupName $rgWithClassicVMs -azureVMResourcesProperties $azureVMsProperties ` + -azureVMsCredentials $azureVMCredntials -cleanTargetBeforeCopy "false" -communicationProtocol '' -skipCACheckOption "false" -enableDetailedLoggingString "false" ` + -additionalArguments "" -copyFilesInParallel "false" -connectionType 'ServicePrincipal' + + +Unregister-Mock Copy-FilesParallellyToAzureVMs +Register-Mock Copy-FilesParallellyToAzureVMs { } + +Assert-WasCalled Copy-FilesParallellyToAzureVMs -Times 0 +Assert-WasCalled Copy-FilesSequentiallyToAzureVMs -Times 1 + +# Test 3 "should call Copy-FilesSequentiallyToAzureVMs for parallel option with one vm" +$azureVMsProperties.Remove("vm0") + +Unregister-Mock Copy-FilesSequentiallyToAzureVMs +Register-Mock Copy-FilesSequentiallyToAzureVMs { } + +Copy-FilesToAzureVMsFromStorageContainer -storageAccountName $validInputStorageAccount -containerName $validInputContainerName -containerSasToken $validSasToken ` + -targetPath $validInputTargetPath -azCopyLocation $validAzCopyLocation -resourceGroupName $rgWithClassicVMs -azureVMResourcesProperties $azureVMsProperties ` + -azureVMsCredentials $azureVMCredntials -cleanTargetBeforeCopy "false" -communicationProtocol '' -skipCACheckOption "false" -enableDetailedLoggingString "false" ` + -additionalArguments "" -copyFilesInParallel "false" -connectionType 'ServicePrincipal' + + +Assert-WasCalled Copy-FilesParallellyToAzureVMs -Times 0 +Assert-WasCalled Copy-FilesSequentiallyToAzureVMs -Times 1 \ No newline at end of file diff --git a/Tasks/AzureFileCopy/Tests/L0DoesAzureVMMatchTagFilter.ps1 b/Tasks/AzureFileCopy/Tests/L0DoesAzureVMMatchTagFilter.ps1 new file mode 100644 index 000000000000..a9debca28daa --- /dev/null +++ b/Tasks/AzureFileCopy/Tests/L0DoesAzureVMMatchTagFilter.ps1 @@ -0,0 +1,33 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 +. $PSScriptRoot\MockVariable.ps1 +. $PSScriptRoot\..\Utility.ps1 +. $PSScriptRoot\MockHelper.ps1 + +Register-Mock Write-Telemetry { } +Register-Mock Switch-AzureMode { } + +$validRG = "AzureFileCopyTaskPlatformTestDoNotDelete" +$azureRMVMResources = Get-AzureRMVMsInResourceGroup -resourceGroupName $validRG +$azureVMResource1 = $azureRMVMResources[0] +$validTagFilterForVMResource1 = "role:test" +$azureVMResource2 = $azureRMVMResources[1] + +# Test 1 "should return true if vm match tag filter criteria with case insensitive check" +$vmMatchFilterCriteria = Does-AzureVMMatchTagFilterCriteria -azureVMResource $azureVMResource1 -filter "Role:TEST, Test1" +Assert-AreEqual $true $vmMatchFilterCriteria + +# Test 2 "should return true if vm match tag filter criteria with same tag repeated twice" +$vmMatchFilterCriteria = Does-AzureVMMatchTagFilterCriteria -azureVMResource $azureVMResource2 -filter "OS:win8, win9; Role:myTEST, MYTest, Test1" +Assert-AreEqual $true $vmMatchFilterCriteria + +# Test 3 "should return false if vm does not match tag filter criteria" +$vmMatchFilterCriteria = Does-AzureVMMatchTagFilterCriteria -azureVMResource $azureVMResource2 -filter "OS:win8, win9; Role:Test5, Test2, Test1" +Assert-AreEqual $false $vmMatchFilterCriteria + +# Test 4 "Should throw if invalid tag filter format" +Assert-Throws { + Does-AzureVMMatchTagFilterCriteria -azureVMResource $azureVMResource2 -filter "OS:win8 : win9; Role:myTEST, MYTest, Test1" +} -MessagePattern "AFC_IncorrectTags" \ No newline at end of file diff --git a/Tasks/AzureFileCopy/Tests/L0GetAzureUtility.ps1 b/Tasks/AzureFileCopy/Tests/L0GetAzureUtility.ps1 new file mode 100644 index 000000000000..22d347cf078f --- /dev/null +++ b/Tasks/AzureFileCopy/Tests/L0GetAzureUtility.ps1 @@ -0,0 +1,37 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 + +$requireSwitchAzureModeVersion = New-Object -TypeName System.Version -ArgumentList "0.9.7" +$notRequireSwitchAzureModeVersion = New-Object -TypeName System.Version -ArgumentList "1.0.1" +$azureRMVersion104 = New-Object -TypeName System.Version -ArgumentList "1.0.4" +$azureRMVersion133 = New-Object -TypeName System.Version -ArgumentList "1.3.3" +$connectedServiceName = "DummyConnectedServiceName" + +Register-Mock Get-TypeOfConnection { return "ServicePrincipal"} + +. $PSScriptRoot\..\Utility.ps1 + +#Test 1 "Should return AzureUtilityLTE9.8.ps1 if version is less than equal to 0.9.8" +Register-Mock Get-AzureCmdletsVersion { return $requireSwitchAzureModeVersion } +$azureUtilityFile = Get-AzureUtility -connectedServiceName $connectedServiceName +Assert-AreEqual $azureUtilityFile "AzureUtilityLTE9.8.ps1" + +#Test 2 "Should return AzureUtilityGTE1.0.ps1 if version is greater than equal to 1.0.0" +Unregister-Mock Get-AzureCmdletsVersion +Register-Mock Get-AzureCmdletsVersion { return $notRequireSwitchAzureModeVersion } +$azureUtilityFile = Get-AzureUtility -connectedServiceName $connectedServiceName +Assert-AreEqual $azureUtilityFile "AzureUtilityGTE1.0.ps1" + +#Test 3 "Should return AzureUtilityGTE1.1.0.ps1 if version is greater than equal to 1.0.3" +Unregister-Mock Get-AzureCmdletsVersion +Register-Mock Get-AzureCmdletsVersion { return $azureRMVersion104 } +$azureUtilityFile = Get-AzureUtility -connectedServiceName $connectedServiceName +Assert-AreEqual $azureUtilityFile "AzureUtilityGTE1.1.0.ps1" + +#Test 4 "Should return AzureUtilityRest.ps1 if version is greater than equal to 1.3.2" +Unregister-Mock Get-AzureCmdletsVersion +Register-Mock Get-AzureCmdletsVersion { return $azureRMVersion133 } +$azureUtilityFile = Get-AzureUtility -connectedServiceName $connectedServiceName +Assert-AreEqual $azureUtilityFile "AzureUtilityRest.ps1" \ No newline at end of file diff --git a/Tasks/AzureFileCopy/Tests/L0GetAzureVMResourcesProperties.ps1 b/Tasks/AzureFileCopy/Tests/L0GetAzureVMResourcesProperties.ps1 new file mode 100644 index 000000000000..b329011c20cc --- /dev/null +++ b/Tasks/AzureFileCopy/Tests/L0GetAzureVMResourcesProperties.ps1 @@ -0,0 +1,63 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 +. $PSScriptRoot\MockVariable.ps1 +. $PSScriptRoot\..\Utility.ps1 +. $PSScriptRoot\MockHelper.ps1 + +Register-Mock Write-Telemetry { } + +$rgWithClassicVMs = "taskplatformtesttwovm" +$vmName = "vm0" +$vmfqdn = "taskplatformtesttwovm.cloudapp.net" + +# Test 1 "should return azureVM resources if valid input given" +$response = Get-AzureVMResourcesProperties -resourceGroupName $rgWithClassicVMs -connectionType 'Certificate' -resourceFilteringMethod 'tags' + +Assert-IsNotNullOrEmpty $response +Assert-AreEqual 2 $response.Count + +$resource = $response[$vmName] +Assert-AreEqual $vmName $resource.Name +Assert-AreEqual $vmfqdn $resource.fqdn +Assert-AreEqual 5986 $resource.winRMHttpsPort + + +# Test 2 "should throw if no azurevm resources" +$cloudServiceWithNoVM = "taskplatformtestnovm" + +Assert-Throws { + $response = Get-AzureVMResourcesProperties -resourceGroupName $cloudServiceWithNoVM -connectionType 'Certificate' -resourceFilteringMethod 'tags' +} -MessagePattern "AFC_NoClassicVMResources*" + +# Test 3 "should throw if no azurevm resources (connection type is UserNamePassword)" +$cloudServiceWithNoVM = "taskplatformtestnovm" + +Assert-Throws { + Get-AzureVMResourcesProperties -resourceGroupName $cloudServiceWithNoVM -connectionType 'UserNamePassword' -resourceFilteringMethod 'tags' +} -MessagePattern "AFC_NoGenericVMResources*" + +# Test 4 "should throw if no azurevm resources (connection type is ServicePrincipal)" +$cloudServiceWithNoVM = "taskplatformtestnovm" + +Assert-Throws { + Get-AzureVMResourcesProperties -resourceGroupName $cloudServiceWithNoVM -connectionType 'ServicePrincipal' -resourceFilteringMethod 'tags' +} -MessagePattern "AFC_NoARMVMResources*" + +# Test 5 "should return azureVM resources if valid input given (connection type is ServicePrincipal)" +$validRG = "AzureFileCopyTaskPlatformTestDoNotDelete" +$vmName = "myVM0" +$vmfqdn = "lbipac2b71e2680c44fd987d.westus.cloudapp.azure.com" +$vmWinRMHttpsPort = '40001' + +$response = Get-AzureVMResourcesProperties -resourceGroupName $validRG -connectionType 'ServicePrincipal' -resourceFilteringMethod 'tags' + +Assert-IsNotNullOrEmpty $response +Assert-AreEqual 3 $response.Count + +$resource = $response[$vmName] + +Assert-AreEqual $vmName $resource.Name +Assert-AreEqual $vmfqdn $resource.fqdn +Assert-AreEqual $vmWinRMHttpsPort $resource.winRMHttpsPort \ No newline at end of file diff --git a/Tasks/AzureFileCopy/Tests/L0GetAzureVMsCredentials.ps1 b/Tasks/AzureFileCopy/Tests/L0GetAzureVMsCredentials.ps1 new file mode 100644 index 000000000000..584df180c0a8 --- /dev/null +++ b/Tasks/AzureFileCopy/Tests/L0GetAzureVMsCredentials.ps1 @@ -0,0 +1,16 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 +. $PSScriptRoot\MockVariable.ps1 +. $PSScriptRoot\..\Utility.ps1 +. $PSScriptRoot\MockHelper.ps1 + +$userName = "userName" +$password = "password" + +# Test 1 "Should return System.Net.NetworkCredential with valid values" +$result = Get-AzureVMsCredentials -vmsAdminUserName $userName -vmsAdminPassword $password +Assert-AreEqual "System.Net.NetworkCredential" $result.GetType().FullName +Assert-AreEqual $userName $result.userName +Assert-AreEqual $password $result.Password \ No newline at end of file diff --git a/Tasks/AzureFileCopy/Tests/L0GetFilteredAzureClassicVmsInRG.ps1 b/Tasks/AzureFileCopy/Tests/L0GetFilteredAzureClassicVmsInRG.ps1 new file mode 100644 index 000000000000..02b2e57cdca8 --- /dev/null +++ b/Tasks/AzureFileCopy/Tests/L0GetFilteredAzureClassicVmsInRG.ps1 @@ -0,0 +1,20 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 + +. $PSScriptRoot\..\Utility.ps1 +. $PSScriptRoot\MockVariable.ps1 +. $PSScriptRoot\MockHelper.ps1 + +$rgWithClassicVMs = "taskplatformtesttwovm" +$azureClassicVMResources = Get-AzureClassicVMsInResourceGroup -resourceGroupName $rgWithClassicVMs + +Register-Mock Get-FilteredAzureVMsInResourceGroup { } + +# Test 1 "should call Get-FilteredAzureVMsInResourceGroup" +$filteredAzureClassicVMResources = Get-FilteredAzureClassicVMsInResourceGroup -azureClassicVMResources $azureClassicVMResources -resourceFilteringMethod "tags" -filter "" +Assert-WasCalled Get-FilteredAzureVMsInResourceGroup -Times 1 -ParametersEvaluator { + $resourceFilteringMethod -eq "tags" -and $filter -eq "" -and $azureVMResources.Count -eq $azureClassicVMResources.Count +} + diff --git a/Tasks/AzureFileCopy/Tests/L0GetFilteredAzureRMVmsInResourceGroup.ps1 b/Tasks/AzureFileCopy/Tests/L0GetFilteredAzureRMVmsInResourceGroup.ps1 new file mode 100644 index 000000000000..73674a2f40d7 --- /dev/null +++ b/Tasks/AzureFileCopy/Tests/L0GetFilteredAzureRMVmsInResourceGroup.ps1 @@ -0,0 +1,19 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 + +. $PSScriptRoot\..\Utility.ps1 +. $PSScriptRoot\MockVariable.ps1 +. $PSScriptRoot\MockHelper.ps1 + +$validRG = "AzureFileCopyTaskPlatformTestDoNotDelete" +$azureRMVMResources = Get-AzureRMVMsInResourceGroup -resourceGroupName $validRG + +Register-Mock Get-FilteredAzureVMsInResourceGroup {} + +# Test 1 "should call Get-FilteredAzureVMsInResourceGroup with proper paramters" +Get-FilteredAzureRMVMsInResourceGroup -azureRMVMResources $azureRMVMResources -resourceFilteringMethod "tags" -filter "" +Assert-WasCalled Get-FilteredAzureVMsInResourceGroup -Times 1 -ParametersEvaluator { + $resourceFilteringMethod -eq "tags"-and $filter -eq "" -and $azureVMResources.Count -eq $azureRMVMResources.Count +} diff --git a/Tasks/AzureFileCopy/Tests/L0GetFilteredAzureVmsInResourceGroup.ps1 b/Tasks/AzureFileCopy/Tests/L0GetFilteredAzureVmsInResourceGroup.ps1 new file mode 100644 index 000000000000..987c1cbe2fac --- /dev/null +++ b/Tasks/AzureFileCopy/Tests/L0GetFilteredAzureVmsInResourceGroup.ps1 @@ -0,0 +1,27 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 + +. $PSScriptRoot\..\Utility.ps1 +. $PSScriptRoot\MockVariable.ps1 +. $PSScriptRoot\MockHelper.ps1 + +Register-Mock Write-Telemetry {} + +$validRG = "AzureFileCopyTaskPlatformTestDoNotDelete" +$azureRMVMResources = Get-AzureRMVMsInResourceGroup -resourceGroupName $validRG + +# Test 1 "should call tag filter if machineNames filter selected and no filter provided" +$filteredAzureVMResources = Get-FilteredAzureVMsInResourceGroup -azureVMResources $azureRMVMResources -resourceFilteringMethod "machineNames" -filter "" +Assert-AreEqual 3 $filteredAzureVMResources.Count + +# Test 2 "should call tag filter when tags filter selected and non-empty filter provided" +$filteredAzureVMResources = Get-FilteredAzureVMsInResourceGroup -azureVMResources $azureRMVMResources -resourceFilteringMethod "tags" -filter "role:web" +Assert-AreEqual 0 $filteredAzureVMResources.Count + +Register-Mock Get-MachineBasedFilteredAzureVMs { } + +# Test 3 "should call Get-MachineBasedFilteredAzureVMs for machineNames filter with non-empty filter" +$filteredAzureVMResources = Get-FilteredAzureVMsInResourceGroup -azureVMResources $azureRMVMResources -resourceFilteringMethod "machineNames" -filter "vm0" +Assert-AreEqual 0 $filteredAzureVMResources.Count diff --git a/Tasks/AzureFileCopy/Tests/L0GetFrontEndPorts.ps1 b/Tasks/AzureFileCopy/Tests/L0GetFrontEndPorts.ps1 new file mode 100644 index 000000000000..3a5fd3bcaa77 --- /dev/null +++ b/Tasks/AzureFileCopy/Tests/L0GetFrontEndPorts.ps1 @@ -0,0 +1,34 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 + +. $PSScriptRoot\..\Utility.ps1 +. $PSScriptRoot\MockVariable.ps1 +. $PSScriptRoot\MockHelper.ps1 + +$validRG = "AzureFileCopyTaskPlatformTestDoNotDelete" +$winrmPort1 = "40001" +$winrmPort2 = "40003" +$winrmPort3 = "40005" +$vmfqdn = "lbipac2b71e2680c44fd987d.westus.cloudapp.azure.com" +$azureRMVMResources = Get-AzureRMVMsInResourceGroup -resourceGroupName $validRG +$azureRGResourcesDetails = Get-AzureRMResourceGroupResourcesDetails -resourceGroupName $validRG -azureRMVMResources $azureRMVMResources +$networkInterfaceResources = $azureRGResourcesDetails["networkInterfaceResources"] +$publicIPAddressResources = $azureRGResourcesDetails["publicIPAddressResources"] +$loadBalancerResources = $azureRGResourcesDetails["loadBalancerResources"] + +# Test 1 "It should valid portList if RG deployed successfully" +[hashtable]$winRMHttpsPortMap = @{} +foreach($lbName in $loadBalancerResources.Keys){ + $lbDetails = $loadBalancerResources[$lbName] + $frontEndIPConfigs = $lbDetails["frontEndIPConfigs"] + $inboundRules = $lbDetails["inboundRules"] + $winRMHttpsPortMap = Get-FrontEndPorts -BackEndPort "5986" -PortList $winRMHttpsPortMap -networkInterfaceResources $networkInterfaceResources -inboundRules $inboundRules + + Assert-AreEqual $true $winRMHttpsPortMap.ContainsKey($azureRMVMResources[0].Id) + Assert-AreEqual $winrmPort1 $winRMHttpsPortMap[$azureRMVMResources[0].Id] + + Assert-AreEqual $true $winRMHttpsPortMap.ContainsKey($azureRMVMResources[1].Id) + Assert-AreEqual $winrmPort2 $winRMHttpsPortMap[$azureRMVMResources[1].Id] +} \ No newline at end of file diff --git a/Tasks/AzureFileCopy/Tests/L0GetMachineBasedFilteredAzureVMs.ps1 b/Tasks/AzureFileCopy/Tests/L0GetMachineBasedFilteredAzureVMs.ps1 new file mode 100644 index 000000000000..694e04918a38 --- /dev/null +++ b/Tasks/AzureFileCopy/Tests/L0GetMachineBasedFilteredAzureVMs.ps1 @@ -0,0 +1,30 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 + +. $PSScriptRoot\..\Utility.ps1 +. $PSScriptRoot\MockVariable.ps1 +. $PSScriptRoot\MockHelper.ps1 + +Register-Mock Write-Telemetry {} + +$rgWithClassicVMs = "taskplatformtesttwovm" +$classicvm0 = "vm0" +$classicvm1 = "VM1" +$azureClassicVMResources = Get-AzureClassicVMsInResourceGroup -resourceGroupName $rgWithClassicVMs + +# Test 1 "should return all vms corresponding to filter with case insensitive check" +$filteredAzureVMResources = Get-MachineBasedFilteredAzureVMs -azureVMResources $azureClassicVMResources -resourceFilteringMethod "machineNames" -filter "vM0, Vm1" +Assert-AreEqual 2 $filteredAzureVMResources.Count + +# Test 2 "should return only one vm corresponding to its filter even if filter is repeated more than once" +$filteredAzureVMResources = Get-MachineBasedFilteredAzureVMs -azureVMResources $azureClassicVMResources -resourceFilteringMethod "machineNames" -filter "vM0, VM0, vm0" +Assert-AreEqual 1 $filteredAzureVMResources.Count + +$nonExistingFilter = "vm2" + +# Test 3 "Should throw if for any filter there is not corresponding vm" +Assert-Throws { + $filteredAzureVMResources = Get-MachineBasedFilteredAzureVMs -azureVMResources $azureClassicVMResources -resourceFilteringMethod "machineNames" -filter "$nonExistingFilter, Vm1" +} -MessagePattern "AFC_MachineDoesNotExist vm2" diff --git a/Tasks/AzureFileCopy/Tests/L0GetMachineNameFromId.ps1 b/Tasks/AzureFileCopy/Tests/L0GetMachineNameFromId.ps1 new file mode 100644 index 000000000000..8e47c1e82e23 --- /dev/null +++ b/Tasks/AzureFileCopy/Tests/L0GetMachineNameFromId.ps1 @@ -0,0 +1,91 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 + +. $PSScriptRoot\..\Utility.ps1 +. $PSScriptRoot\MockVariable.ps1 +. $PSScriptRoot\MockHelper.ps1 + +$validRG = "AzureFileCopyTaskPlatformTestDoNotDelete" +$vm0Name = "myVM0" +$vm1Name = "mytestVM0" +$vm2Name = "mytestPTVM0" +$winrmPort1 = "40001" +$winrmPort2 = "40003" +$winrmPort3 = "40005" +$vmfqdn = "lbipac2b71e2680c44fd987d.westus.cloudapp.azure.com" +$azureRMVMResources = Get-AzureRMVMsInResourceGroup -resourceGroupName $validRG +$azureRGResourcesDetails = Get-AzureRMResourceGroupResourcesDetails -resourceGroupName $validRG -azureRMVMResources $azureRMVMResources +$networkInterfaceResources = $azureRGResourcesDetails["networkInterfaceResources"] +$publicIPAddressResources = $azureRGResourcesDetails["publicIPAddressResources"] +$loadBalancerResources = $azureRGResourcesDetails["loadBalancerResources"] + +[hashtable]$fqdnMap = @{} +[hashtable]$winRMHttpsPortMap = @{} +foreach($lbName in $loadBalancerResources.Keys) +{ + $lbDetails = $loadBalancerResources[$lbName] + $frontEndIPConfigs = $lbDetails["frontEndIPConfigs"] + $inboundRules = $lbDetails["inboundRules"] + + $fqdnMap = Get-MachinesFqdnsForLB -resourceGroupName $validRG -publicIPAddressResources $publicIPAddressResources -networkInterfaceResources $networkInterfaceResources -frontEndIPConfigs $frontEndIPConfigs -fqdnMap $fqdnMap + $winRMHttpsPortMap = Get-FrontEndPorts -BackEndPort "5986" -PortList $winRMHttpsPortMap -networkInterfaceResources $networkInterfaceResources -inboundRules $inboundRules +} +# Test 1 "should create valid map for map parameter FQDN" +$fqdnMap = Get-MachineNameFromId -resourceGroupName $validRG -Map $fqdnMap -MapParameter "FQDN" -azureRMVMResources $azureRMVMResources -ThrowOnTotalUnavaialbility $true + +Assert-AreEqual $true $fqdnMap.ContainsKey($vm0Name) +Assert-AreEqual $vmfqdn $fqdnMap[$vm0Name] +Assert-AreEqual $true $fqdnMap.ContainsKey($vm1Name) + +# Test 2 "should create valid map for map parameter Front End port" +$winRMHttpsPortMap = Get-MachineNameFromId -Map $winRMHttpsPortMap -MapParameter "Front End port" -azureRMVMResources $azureRMVMResources -ThrowOnTotalUnavaialbility $false + +Assert-AreEqual $true $winRMHttpsPortMap.ContainsKey($vm0Name) +Assert-AreEqual $winrmPort1 $winRMHttpsPortMap[$vm0Name] +Assert-AreEqual $true $winRMHttpsPortMap.ContainsKey($vm1Name) +Assert-AreEqual $winrmPort2 $winRMHttpsPortMap[$vm1Name] + + +# Test 3 "It should return partial map if for not all resources map is not configured properly" + +[hashtable]$fqdnMap = @{} +[hashtable]$winRMHttpsPortMap = @{} +foreach($lbName in $loadBalancerResources.Keys) +{ + $lbDetails = $loadBalancerResources[$lbName] + $frontEndIPConfigs = $lbDetails["frontEndIPConfigs"] + $inboundRules = $lbDetails["inboundRules"] + + $fqdnMap = Get-MachinesFqdnsForLB -resourceGroupName $validRG -publicIPAddressResources $publicIPAddressResources -networkInterfaceResources $networkInterfaceResources -frontEndIPConfigs $frontEndIPConfigs -fqdnMap $fqdnMap + $winRMHttpsPortMap = Get-FrontEndPorts -BackEndPort "5986" -PortList $winRMHttpsPortMap -networkInterfaceResources $networkInterfaceResources -inboundRules $inboundRules +} +$fqdnMap.Remove($azureRMVMResources[0].Id) + +$fqdnMap = Get-MachineNameFromId -resourceGroupName $validRG -Map $fqdnMap -MapParameter "FQDN" -azureRMVMResources $azureRMVMResources -ThrowOnTotalUnavaialbility $true + +Assert-AreEqual $false $fqdnMap.ContainsKey($vm0Name) +Assert-AreEqual $true $fqdnMap.ContainsKey($vm1Name) +Assert-AreEqual $vmfqdn $fqdnMap[$vm1Name] + +# Test 4 "throw error if no resource is available and ThrowOnTotalUnavailability is set to true" + +[hashtable]$fqdnMap = @{} +[hashtable]$winRMHttpsPortMap = @{} +foreach($lbName in $loadBalancerResources.Keys) +{ + $lbDetails = $loadBalancerResources[$lbName] + $frontEndIPConfigs = $lbDetails["frontEndIPConfigs"] + $inboundRules = $lbDetails["inboundRules"] + + $fqdnMap = Get-MachinesFqdnsForLB -resourceGroupName $validRG -publicIPAddressResources $publicIPAddressResources -networkInterfaceResources $networkInterfaceResources -frontEndIPConfigs $frontEndIPConfigs -fqdnMap $fqdnMap + $winRMHttpsPortMap = Get-FrontEndPorts -BackEndPort "5986" -PortList $winRMHttpsPortMap -networkInterfaceResources $networkInterfaceResources -inboundRules $inboundRules +} +$fqdnMap.Remove($azureRMVMResources[0].Id) +$fqdnMap.Remove($azureRMVMResources[1].Id) +$fqdnMap.Remove($azureRMVMResources[2].Id) + +Assert-Throws { + $fqdnMap = Get-MachineNameFromId -resourceGroupName $validRG -Map $fqdnMap -MapParameter "FQDN" -azureRMVMResources $azureRMVMResources -ThrowOnTotalUnavailability $true +} -MessagePattern "AFC_MachineNameFromIdErrorAllResources*" diff --git a/Tasks/AzureFileCopy/Tests/L0GetMachinesFqdnForLB.ps1 b/Tasks/AzureFileCopy/Tests/L0GetMachinesFqdnForLB.ps1 new file mode 100644 index 000000000000..df9b520cca4d --- /dev/null +++ b/Tasks/AzureFileCopy/Tests/L0GetMachinesFqdnForLB.ps1 @@ -0,0 +1,31 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 + +. $PSScriptRoot\..\Utility.ps1 +. $PSScriptRoot\MockVariable.ps1 +. $PSScriptRoot\MockHelper.ps1 + +$validRG = "AzureFileCopyTaskPlatformTestDoNotDelete" +$vmfqdn = "lbipac2b71e2680c44fd987d.westus.cloudapp.azure.com" +$azureRMVMResources = Get-AzureRMVMsInResourceGroup -resourceGroupName $validRG +$azureRGResourcesDetails = Get-AzureRMResourceGroupResourcesDetails -resourceGroupName $validRG -azureRMVMResources $azureRMVMResources +$networkInterfaceResources = $azureRGResourcesDetails["networkInterfaceResources"] +$publicIPAddressResources = $azureRGResourcesDetails["publicIPAddressResources"] +$loadBalancerResources = $azureRGResourcesDetails["loadBalancerResources"] +[hashtable]$fqdnMap = @{} + +# Test 1 "It should valid fqdnMap if RG deployed successfully" +foreach($lbName in $loadBalancerResources.Keys) { + $lbDetails = $loadBalancerResources[$lbName] + $frontEndIPConfigs = $lbDetails["frontEndIPConfigs"] + $inboundRules = $lbDetails["inboundRules"] + $fqdnMap = Get-MachinesFqdnsForLB -resourceGroupName $validRG -publicIPAddressResources $publicIPAddressResources -networkInterfaceResources $networkInterfaceResources -frontEndIPConfigs $frontEndIPConfigs -fqdnMap $fqdnMap + + Assert-AreEqual $true $fqdnMap.ContainsKey($azureRMVMResources[0].Id) + Assert-AreEqual $vmfqdn $fqdnMap[$azureRMVMResources[0].Id] + + Assert-AreEqual $true $fqdnMap.ContainsKey($azureRMVMResources[1].Id) + Assert-AreEqual $vmfqdn $fqdnMap[$azureRMVMResources[1].Id] +} \ No newline at end of file diff --git a/Tasks/AzureFileCopy/Tests/L0GetRMVMConnectionDetailsInRG.ps1 b/Tasks/AzureFileCopy/Tests/L0GetRMVMConnectionDetailsInRG.ps1 new file mode 100644 index 000000000000..938128a8bb64 --- /dev/null +++ b/Tasks/AzureFileCopy/Tests/L0GetRMVMConnectionDetailsInRG.ps1 @@ -0,0 +1,31 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 + +. $PSScriptRoot\..\Utility.ps1 +. $PSScriptRoot\MockVariable.ps1 +. $PSScriptRoot\MockHelper.ps1 + +$validRG = "AzureFileCopyTaskPlatformTestDoNotDelete" +$vmName = "myVM0" +$vmfqdn = "lbipac2b71e2680c44fd987d.westus.cloudapp.azure.com" +$vmWinRMHttpsPort = '40001' +$azureRMVMResources = Get-AzureRMVMsInResourceGroup -resourceGroupName $validRG + +# Test 1 "It should return azure vm connection details for valid input" +$response = Get-AzureRMVMsConnectionDetailsInResourceGroup -resourceGroupName $validRG -azureRMVMResources $azureRMVMResources + +Assert-IsNotNullOrEmpty $response +Assert-AreEqual 3 $response.Count + +$resource = $response[$vmName] + +Assert-AreEqual $vmName $resource.Name +Assert-AreEqual $vmfqdn $resource.fqdn +Assert-AreEqual $vmWinRMHttpsPort $resource.winRMHttpsPort + +#Test 2 "It should return null if no azure vms" +$response = Get-AzureRMVMsConnectionDetailsInResourceGroup -resourceGroupName $validRG -azureRMVMResources $null + +Assert-IsNullOrEmpty $response \ No newline at end of file diff --git a/Tasks/AzureFileCopy/Tests/L0GetSkipCACheckOption.ps1 b/Tasks/AzureFileCopy/Tests/L0GetSkipCACheckOption.ps1 new file mode 100644 index 000000000000..6e696432923b --- /dev/null +++ b/Tasks/AzureFileCopy/Tests/L0GetSkipCACheckOption.ps1 @@ -0,0 +1,15 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 +. $PSScriptRoot\MockVariable.ps1 +. $PSScriptRoot\..\Utility.ps1 +. $PSScriptRoot\MockHelper.ps1 + +# Test 1 "Check SkiCACheck flag value" +$result = Get-SkipCACheckOption -SkipCACheck "true" +Assert-AreEqual "-SkipCACheck" $result + +# Test 2 "Should return '' if passed false" +$result = Get-SkipCACheckOption -SkipCACheck "false" +Assert-IsNullOrEmpty $result "SkipCACheck Should be empty" \ No newline at end of file diff --git a/Tasks/AzureFileCopy/Tests/L0GetStorageAccountType.ps1 b/Tasks/AzureFileCopy/Tests/L0GetStorageAccountType.ps1 new file mode 100644 index 000000000000..cb89982d47a8 --- /dev/null +++ b/Tasks/AzureFileCopy/Tests/L0GetStorageAccountType.ps1 @@ -0,0 +1,36 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 + +. $PSScriptRoot\..\Utility.ps1 +. $PSScriptRoot\MockHelper.ps1 + +Register-Mock Validate-AzurePowershellVersion {} +Register-Mock Get-Endpoint { return $null } +Register-Mock Write-Telemetry { } + +$invalidClassicStorage = "invalidClassicStorage" +$invalidStorage = "invalidStorage" +$connectedServiceName = "DummyConnectedServiceName" +$invalidRGStorage = "invalidRGStorage" + +# Test 1 "Should throw if Blob storage not found for connection Certificate" +Assert-Throws { + Get-StorageAccountType -storageAccountName $invalidClassicStorage -connectionType 'Certificate' -connectedServiceName $connectedServiceName +} -MessagePattern "AFC_BlobStorageNotFound *" + +# Test 2 "Should throw if Blob storage not found for connection UserNamePassword" +Assert-Throws { + Get-StorageAccountType -storageAccountName $invalidStorage -connectionType 'UserNamePassword' -connectedServiceName $connectedServiceName +} -MessagePattern "AFC_BlobStorageNotFound *" + +Register-Mock Get-AzureStorageAccountTypeFromARM { + throw "Unable to find storage type $invalidRGStorage with Connection SPN" +} +# Test 3 "Should throw if Blob storage not found for connection ARM endpoint" +Assert-Throws { + Get-StorageAccountType -storageAccountName $invalidRGStorage -connectionType 'ServicePrincipal' -connectedServiceName $connectedServiceName +} -MessagePattern "Unable to find storage type $invalidRGStorage with Connection SPN" + +Assert-WasCalled -Times 1 Get-AzureStorageAccountTypeFromARM \ No newline at end of file diff --git a/Tasks/AzureFileCopy/Tests/L0GetStorageKey.ps1 b/Tasks/AzureFileCopy/Tests/L0GetStorageKey.ps1 new file mode 100644 index 000000000000..bb0982e7f6f4 --- /dev/null +++ b/Tasks/AzureFileCopy/Tests/L0GetStorageKey.ps1 @@ -0,0 +1,31 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 + +. $PSScriptRoot\..\Utility.ps1 +. $PSScriptRoot\MockHelper.ps1 +$invalidClassicStorage = "invalidClassicStorage" +$connectedServiceName = "DummyConnectedServiceName" + +Register-Mock Validate-AzurePowershellVersion {} +Register-Mock Get-Endpoint { return $null } + +Register-Mock Write-Telemetry { } + +# Test 1 "should throw if storage not found for connection certificate" +Assert-Throws { + Get-StorageKey -storageAccountName $invalidClassicStorage -connectionType 'Certificate' -connectedServiceName $connectedServiceName +} -MessagePattern "AFC_ClassicStorageAccountNotFound *" + +# Test 2 "should throw if storage not found for connection usernamepassword" +$invalidStorage = "invalidStorage" +Assert-Throws { + Get-StorageKey -storageAccountName $invalidStorage -connectionType 'UserNamePassword' -connectedServiceName $connectedServiceName +} -MessagePattern "AFC_GenericStorageAccountNotFound *" + +# Test 3 "should throw if storage not found for connection connection SPN" +$invalidRGStorage = "invalidRGStorage" +Assert-Throws { + Get-StorageKey -storageAccountName $invalidRGStorage -connectionType 'ServicePrincipal' -connectedServiceName $connectedServiceName +} -MessagePattern "Storage account: $invalidRGStorage not found. Selected Connection 'ServicePrincipal' supports storage account of Azure Resource Manager type only." diff --git a/Tasks/AzureFileCopy/Tests/L0GetTagBasedFilteredAzureVMs.ps1 b/Tasks/AzureFileCopy/Tests/L0GetTagBasedFilteredAzureVMs.ps1 new file mode 100644 index 000000000000..66522f4d90fb --- /dev/null +++ b/Tasks/AzureFileCopy/Tests/L0GetTagBasedFilteredAzureVMs.ps1 @@ -0,0 +1,22 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 + +. $PSScriptRoot\..\Utility.ps1 +. $PSScriptRoot\MockVariable.ps1 +. $PSScriptRoot\MockHelper.ps1 + +$validRG = "AzureFileCopyTaskPlatformTestDoNotDelete" +$vm0Name = "myVM0" +$azureRMVMResources = Get-AzureRMVMsInResourceGroup -resourceGroupName $validRG + +# Test 1 "Should Call Does-AzureVMMatchTagFilterCriteria for every VM for filter criteria" +$filteredAzureVMResources = Get-TagBasedFilteredAzureVMs -azureVMResources $azureRMVMResources -filter "role:web" + +#Assert-WasCalled Does-AzureVMMatchTagFilterCriteria -Times $azureRMVMResources.Count -ParametersEvaluator {$filter -eq "role:web"} + +# Test 2 "Should return VMs that matches tag filter criteria" +$filteredAzureVMResources = Get-TagBasedFilteredAzureVMs -azureVMResources $azureRMVMResources -filter "role:test" + +Assert-AreEqual $vm0Name $filteredAzureVMResources.Name \ No newline at end of file diff --git a/Tasks/AzureFileCopy/Tests/L0GetblobStorageEndpoint.ps1 b/Tasks/AzureFileCopy/Tests/L0GetblobStorageEndpoint.ps1 new file mode 100644 index 000000000000..21f0d9c89820 --- /dev/null +++ b/Tasks/AzureFileCopy/Tests/L0GetblobStorageEndpoint.ps1 @@ -0,0 +1,31 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 + +. $PSScriptRoot\..\Utility.ps1 +. $PSScriptRoot\MockHelper.ps1 + +Register-Mock Validate-AzurePowershellVersion {} +Register-Mock Get-Endpoint { return $null } +Register-Mock Write-Telemetry { } + +$invalidClassicStorage = "invalidClassicStorage" +$invalidStorage = "invalidStorage" +$connectedServiceName = "DummyConnectedServiceName" +$invalidRGStorage = "invalidRGStorage" + +# Test 1 "Should throw if Blob storage not found for connection Certificate" +Assert-Throws { + Get-blobStorageEndpoint -storageAccountName $invalidClassicStorage -connectionType 'Certificate' -connectedServiceName $connectedServiceName +} -MessagePattern "AFC_BlobStorageNotFound *" + +# Test 2 "Should throw if Blob storage not found for connection UserNamePassword" +Assert-Throws { + Get-blobStorageEndpoint -storageAccountName $invalidStorage -connectionType 'UserNamePassword' -connectedServiceName $connectedServiceName +} -MessagePattern "AFC_BlobStorageNotFound *" + +# Test 3 "Should throw if Blob storage not found for connection ARM endpoint" +Assert-Throws { + Get-blobStorageEndpoint -storageAccountName $invalidRGStorage -connectionType 'ServicePrincipal' -connectedServiceName $connectedServiceName +} -MessagePattern "Unable to find storage type $invalidRGStorage with Connection SPN" \ No newline at end of file diff --git a/Tasks/AzureFileCopy/Tests/L0IsWinRMCustomScriptExtensionExists.ps1 b/Tasks/AzureFileCopy/Tests/L0IsWinRMCustomScriptExtensionExists.ps1 new file mode 100644 index 000000000000..7c76ebec1b79 --- /dev/null +++ b/Tasks/AzureFileCopy/Tests/L0IsWinRMCustomScriptExtensionExists.ps1 @@ -0,0 +1,61 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 +. $PSScriptRoot\MockVariable.ps1 +. $PSScriptRoot\..\Utility.ps1 +. $PSScriptRoot\MockHelper.ps1 + +$extensionName="WinRMCustomScriptExtension" + +# Test 1 "Should not throw when Resource group us null" +$isExtensionExists = Is-WinRMCustomScriptExtensionExists -resourceGroupName $null -vmName $vm0Name -extensionName $extensionName -connectedServiceName $connectedServiceName +Assert-AreEqual $false $isExtensionExists + +# Test 2 "Should not throw when VM name is null" +$isExtensionExists = Is-WinRMCustomScriptExtensionExists -resourceGroupName $validRG -vmName $null -extensionName $extensionName -connectedServiceName $connectedServiceName +Assert-AreEqual $false $isExtensionExists + +# Test 3 "Should not throw when VM name is invalid" +$isExtensionExists = Is-WinRMCustomScriptExtensionExists -resourceGroupName $validRG -vmName $invalidMachineName -extensionName $extensionName -connectedServiceName $connectedServiceName +Assert-AreEqual $false $isExtensionExists + +# Test 4 "Should not throw Extension name is null" +$isExtensionExists = Is-WinRMCustomScriptExtensionExists -resourceGroupName $validRG -vmName $vm0Name -extensionName $null -connectedServiceName $connectedServiceName +Assert-AreEqual $false $isExtensionExists + +# Test 5 "Should not throw when Extension name is invalid" +$invalidExtensionName="InvalidWinRMCustomScriptExtension" + +$isExtensionExists = Is-WinRMCustomScriptExtensionExists -resourceGroupName $validRG -vmName $vm0Name -extensionName $invalidExtensionName -connectedServiceName $connectedServiceName +Assert-AreEqual $false $isExtensionExists + +# Test 6 "Should return true for valid values, if previous extension deployed successfully" +Register-Mock Get-AzureMachineCustomScriptExtension { return @{"ProvisioningState"="Succeeded"} } +Register-Mock Validate-CustomScriptExecutionStatus { return } +Register-Mock Remove-AzureMachineCustomScriptExtension { return @{}} +Register-Mock Get-Endpoint {} + +$isExtensionExists = Is-WinRMCustomScriptExtensionExists -resourceGroupName $validRG -vmName $vm0Name -extensionName $extensionName -connectedServiceName $connectedServiceName +Assert-AreEqual $true $isExtensionExists +Assert-WasCalled Get-AzureMachineCustomScriptExtension -Times 1 +Assert-WasCalled Validate-CustomScriptExecutionStatus -Times 1 +Assert-WasCalled Remove-AzureMachineCustomScriptExtension -Times 0 + +# Test 7 "Should return false For valid values, if previous extension failed to deploy" +Unregister-Mock Validate-CustomScriptExecutionStatus +Register-Mock Validate-CustomScriptExecutionStatus { throw "error" } + +$isExtensionExists = Is-WinRMCustomScriptExtensionExists -resourceGroupName $validRG -vmName $vm0Name -extensionName $extensionName -connectedServiceName $connectedServiceName + +Assert-AreEqual $false $isExtensionExists +Assert-WasCalled Validate-CustomScriptExecutionStatus -Times 1 + +# Test 8 "Should return false For valid values, if previous extension failed to provision" +Unregister-Mock Get-AzureMachineCustomScriptExtension +Register-Mock Get-AzureMachineCustomScriptExtension { return @{properties=@{ProvisioningState="Failed"}} } + +$isExtensionExists = Is-WinRMCustomScriptExtensionExists -resourceGroupName $validRG -vmName $vm0Name -extensionName $extensionName -connectedServiceName $connectedServiceName + +Assert-AreEqual $false $isExtensionExists +Assert-WasCalled Get-AzureMachineCustomScriptExtension -Times 1 diff --git a/Tasks/AzureFileCopy/Tests/L0UploadFilesToAzureContainer.ps1 b/Tasks/AzureFileCopy/Tests/L0UploadFilesToAzureContainer.ps1 new file mode 100644 index 000000000000..1d72d979ee77 --- /dev/null +++ b/Tasks/AzureFileCopy/Tests/L0UploadFilesToAzureContainer.ps1 @@ -0,0 +1,37 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 +. $PSScriptRoot\MockVariable.ps1 +. $PSScriptRoot\..\Utility.ps1 + +$invalidInputStorageAccount = "invalidInputStorageAccount" +$exceptionMessage = "Exception thrown" + +Register-Mock Write-Telemetry { } + +# Test 1 "Should throw if destination blob is invalid" +Register-Mock Copy-FilesToAzureBlob { throw $exceptionMessage } -ParametersEvaluator {$StorageAccountName -eq $invalidInputStorageAccount} +Assert-Throws { + Upload-FilesToAzureContainer -sourcePath $validInputSourcePath -storageAccountName $invalidInputStorageAccount -containerName $validInputContainerName ` + -blobPrefix $validInputBlobPrefix -storageKey $validStorageKey -azCopyLocation $validAzCopyLocation -destinationType $validInputAzureBlobDestinationType +} -MessagePattern "*AFC_UploadContainerStorageAccount*invalidInputStorageAccount*" + +# Test 2 "Should throw and delete container if destination azureVM" +Register-Mock Remove-AzureContainer { } + +Assert-Throws { + Upload-FilesToAzureContainer -sourcePath $validInputSourcePath -storageAccountName $invalidInputStorageAccount -containerName $validInputContainerName ` + -blobPrefix $validInputBlobPrefix -storageKey $validStorageKey -azCopyLocation $validAzCopyLocation -destinationType $validInputAzureVmsDestinationType +} -MessagePattern "*AFC_UploadContainerStorageAccount*invalidInputStorageAccount*" + +Assert-WasCalled Remove-AzureContainer -Times 1 + + +# Test 3 "Success in Upload blob destination" +Register-Mock Copy-FilesToAzureBlob { return $succeededCopyResponse } -ParametersEvaluator {$StorageAccountName -eq $validInputStorageAccount} + +Upload-FilesToAzureContainer -sourcePath $validInputSourcePath -storageAccountName $validInputStorageAccount -containerName $validInputContainerName ` + -blobPrefix $validInputBlobPrefix -storageKey $validStorageKey -azCopyLocation $validAzCopyLocation -destinationType $validInputAzureBlobDestinationType + +Assert-WasCalled Copy-FilesToAzureBlob -Times 1 -ParametersEvaluator {$StorageAccountName -eq $validInputStorageAccount} \ No newline at end of file diff --git a/Tasks/AzureFileCopy/Tests/L0UtilityThrowError.ps1 b/Tasks/AzureFileCopy/Tests/L0UtilityThrowError.ps1 new file mode 100644 index 000000000000..0736af738f66 --- /dev/null +++ b/Tasks/AzureFileCopy/Tests/L0UtilityThrowError.ps1 @@ -0,0 +1,12 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 + +. $PSScriptRoot\..\Utility.ps1 + + $exceptionMessage = "Exception thrown" + +Assert-Throws { + ThrowError -errorMessage $exceptionMessage +} -MessagePattern "$exceptionMessage AFC_AzureFileCopyMoreHelp https://aka.ms/azurefilecopyreadme" diff --git a/Tasks/AzureFileCopy/Tests/L0ValidateAzurePSVersion.ps1 b/Tasks/AzureFileCopy/Tests/L0ValidateAzurePSVersion.ps1 new file mode 100644 index 000000000000..941f6bd65080 --- /dev/null +++ b/Tasks/AzureFileCopy/Tests/L0ValidateAzurePSVersion.ps1 @@ -0,0 +1,25 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 + +. $PSScriptRoot\..\Utility.ps1 + +$lowerThanMinimumAzureVersion = New-Object -TypeName System.Version -ArgumentList "0.8.8" +$minimumAzureVersion = New-Object -TypeName System.Version -ArgumentList "0.9.0" +$greaterThanMinimumAzureVersion = New-Object -TypeName System.Version -ArgumentList "0.9.8" + +Register-Mock Get-AzureCmdletsVersion { return $lowerThanMinimumAzureVersion } +Register-Mock Write-Telemetry + +#Test 1 "Should throw if lower azureps version" +Assert-Throws { + Validate-AzurePowershellVersion +} -MessagePattern "*AFC_AzurePSNotInstalled*" + +#Test 2 "Should throw if lower azureps version" +Unregister-Mock Get-AzureCmdletsVersion +Register-Mock Get-AzureCmdletsVersion { return $greaterThanMinimumAzureVersion } + +Validate-AzurePowershellVersion +Assert-WasCalled -Times 1 Get-AzureCmdletsVersion diff --git a/Tasks/AzureFileCopy/Tests/L0ValidateCustomScriptExecutionStatus.ps1 b/Tasks/AzureFileCopy/Tests/L0ValidateCustomScriptExecutionStatus.ps1 new file mode 100644 index 000000000000..87807e415b4c --- /dev/null +++ b/Tasks/AzureFileCopy/Tests/L0ValidateCustomScriptExecutionStatus.ps1 @@ -0,0 +1,66 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 +. $PSScriptRoot\MockVariable.ps1 +. $PSScriptRoot\..\Utility.ps1 +. $PSScriptRoot\MockHelper.ps1 + +$extensionName="WinRMCustomScriptExtension" + +# Test 1 "Should throw Resource group name is null" +Assert-Throws { + $response = Validate-CustomScriptExecutionStatus -resourceGroupName $null -vmName $vm0Name -extensionName $extensionName +} -MessagePattern "AFC_SetCustomScriptExtensionFailed *" + +# Test 2 "Should throw when VM name is null" +Assert-Throws { + $response = Validate-CustomScriptExecutionStatus -resourceGroupName $validRG -vmName $null -extensionName $extensionName +} -MessagePattern "AFC_SetCustomScriptExtensionFailed *" + + +# Test 3 "Should throw when VM name is invalid" +Assert-Throws { + $response = Validate-CustomScriptExecutionStatus -resourceGroupName $validRG -vmName $invalidMachineName -extensionName $extensionName +} -MessagePattern "AFC_SetCustomScriptExtensionFailed *" + +# Test 4 "Should throw Extension name is null" +Assert-Throws { + $response = Validate-CustomScriptExecutionStatus -resourceGroupName $validRG -vmName $vm0Name -extensionName $null +} -MessagePattern "AFC_SetCustomScriptExtensionFailed *" + +# Test 5 "should throw when Extension name is invalid" +$invalidExtensionName="InvalidWinRMCustomScriptExtension" +Assert-Throws { + $response = Validate-CustomScriptExecutionStatus -resourceGroupName $validRG -vmName $vm0Name -extensionName $invalidExtensionName +} -MessagePattern "AFC_SetCustomScriptExtensionFailed *" + +# Test 6 "Should not throw" "For valid values, if previous extension deployed successfully" +Register-Mock Remove-AzureMachineCustomScriptExtension { return @{}} +$vmInstanceViews[$vm0Name]["Extensions"]=$extensions + +Validate-CustomScriptExecutionStatus -resourceGroupName $validRG -vmName $vm0Name -extensionName $extensionName +Assert-WasCalled Remove-AzureMachineCustomScriptExtension -Times 0 + +# Test 7 "Should throw for valid values, if previous extension failed to deploy" +$extensions[0]["SubStatuses"][1]["Message"]="Extension script execution failed." +$vmInstanceViews[$vm0Name]["Extensions"]=$extensions + +Assert-Throws { + Validate-CustomScriptExecutionStatus -resourceGroupName $validRG -vmName $vm0Name -extensionName $extensionName +} -MessagePattern "AFC_SetCustomScriptExtensionFailed *" +Assert-WasCalled Remove-AzureMachineCustomScriptExtension -Times 1 + +# Test 8 "For valid values, if previous extension failed to provision" +Unregister-Mock Remove-AzureMachineCustomScriptExtension +Register-Mock Remove-AzureMachineCustomScriptExtension { return @{}} +$extensions[0]["SubStatuses"][1]["Message"]="Failed to apply the extension." +$vmInstanceViews[$vm0Name]["Extensions"]=$extensions + +Assert-Throws { + Validate-CustomScriptExecutionStatus -resourceGroupName $validRG -vmName $vm0Name -extensionName $extensionName +} -MessagePattern "AFC_SetCustomScriptExtensionFailed *" +Assert-WasCalled Remove-AzureMachineCustomScriptExtension -Times 1 + +#Clean the extension +$vmInstanceViews[$vm0Name]["Extensions"]=@() diff --git a/Tasks/AzureFileCopy/Tests/MockHelper.ps1 b/Tasks/AzureFileCopy/Tests/MockHelper.ps1 new file mode 100644 index 000000000000..e785b4859988 --- /dev/null +++ b/Tasks/AzureFileCopy/Tests/MockHelper.ps1 @@ -0,0 +1,678 @@ +############## Constants ########## +$invalidParam = "invalidParam" +$validRG = "AzureFileCopyTaskPlatformTestDoNotDelete" +$rgWithNoVM = "AzureFIleCopyPTRGNoVMDoNotDelete" +$rgNameWithSecurityGroup = "AzureFIleCopyPTRGWithSGDoNotDelete" +$validStorage = "azurefilecopyptsstore" +$validStorageKey = "validStorageKey" +$storageAccounts = @{} +$storageAccounts.Add($validStorage, $validStorageKey) +$validClassicStorage = "ptclassicstoredontdelete" +$validClassicStorageKey = "validClassicStorageKey" +$storageAccounts.Add($validClassicStorage, $validClassicStorageKey) + +$storageAccountsRG = @{} +$storageAccountsRG.Add($validStorage, $validRG) +$storageAccountsRG.Add($validClassicStorage, $validClassicStorageKey) + +$storageAccountsContext = @{} +$storageAccountContext = @{} +$storageAccountContext.StorageAccountName = $validStorage +$storageAccountsContext.Add($validStorage, $storageAccountContext) + +$validSasToken = 'anyValidSaasToken' + +$location = "West US" +$vm0Name = "myVM0" +$vm1Name = "mytestVM0" +$vm2Name = "mytestPTVM1" +$lbName = "myLB" +$classicvmfqdn = "taskplatformtesttwovm.cloudapp.net" +$rgWithNoClassicVms = "taskplatformtestnovm" +$rgWithClassicVMs = "taskplatformtesttwovm" +$classicvm0 = "vm0" +$classicvm1 = "VM1" +$azurevmFqdn = "azurefilecopyplatformtestsdns.westus.cloudapp.azure.com" +$winrmPort1 = "40001" +$winrmPort2 = "40003" +$winrmPort3 = "40005" +$classicWinrmPort1 = "5986" +$classicWinrmPort2 = "57148" +$classicWinrmPort3 = "57149" + +# creating resourcegroups dictionary +$resourceGroups = @{} +$resourceGroup = @{} +$resourceGroup.ResourceGroupName = $validRG +$resourceGroup.Location = $location +$resourceGroups.Add($validRG, $resourceGroup) + +$resourceGroup.ResourceGroupName = $rgWithNoVM +$resourceGroups.Add($rgWithNoVM, $resourceGroup) +$resourceGroup.ResourceGroupName = $rgWithNoClassicVms +$resourceGroups.Add($rgWithNoClassicVms, $resourceGroup) + +$validActionResponse = @{"Status" = "Succeeded"} +$VMsStatus = @{$vm0Name = "Running"; $vm1Name = "Running";$vm2Name = "Running"} + +$resourceGroups[$validRG].VMsDetails = $VMsStatus + +$vmInstanceView = @{"Statuses" = @(@{"DisplayStatus" = "Provisioning succeeded"},@{"DisplayStatus" = "VM running"}); "Extensions" = @(); "VMAgent" = @{"ExtensionHandlers" = @()}} +$vmInstanceViews = @{$vm0Name = $vmInstanceView; $vm1Name = $vmInstanceView ; $vm2Name = $vmInstanceView} +$vmResources = @(@{"Id" = "Microsoft.Compute/virtualMachines/myVM0"; "Name" = $vm0Name; "Location" = $location; "Tags" = @{"role" = "Test"}}, @{"Id" = "Microsoft.Compute/virtualMachines/mytestVM0"; "Name" = $vm1Name; "Location" = $location; "Tags" = @{"role" = "mytest"}} , @{"Id" = "Microsoft.Compute/virtualMachines/mytestPTVM1"; "Name" = $vm2Name; "Location" = $location; "Tags" = @{"role" = "mytestPT"}}) + +$virtualMachine1 = @{"Id" = "Microsoft.Compute/virtualMachines/myVM0"} +$IpConfigurations1 = @(@{"Name" = "ipconfig1"; "Id" = "Microsoft.Network/networkInterfaces/nic0/ipConfigurations/ipconfig1"; "LoadBalancerInboundNatRules" = @(@{"Id" = "Microsoft.Network/loadBalancers/myLB/inboundNatRules/RDP-VM0"}, @{"Id" = "Microsoft.Network/loadBalancers/myLB/inboundNatRules/WINRM-VM0"})}) +$networkInterface1 = @{"Name" = "nic0"; "VirtualMachine" = $virtualMachine1; "IpConfigurations" = $IpConfigurations1} + +$virtualMachine2 = @{"Id" = "Microsoft.Compute/virtualMachines/mytestVM0"} +$IpConfigurations2 = @(@{"Name" = "ipconfig2"; "Id" = "Microsoft.Network/networkInterfaces/nicN0/ipConfigurations/ipconfig2"; "LoadBalancerInboundNatRules" = @(@{"Id" = "Microsoft.Network/loadBalancers/myLB/inboundNatRules/NRDP-VM0"}, @{"Id" = "Microsoft.Network/loadBalancers/myLB/inboundNatRules/NWINRM-VM0"})}) +$networkInterface2 = @{"Name" = "nicN0"; "Id" = "Microsoft.Network/networkInterfaces/nicN0"; "VirtualMachine" = $virtualMachine2; "IpConfigurations" = $IpConfigurations2} + +$virtualMachine3 = @{"Id" = "Microsoft.Compute/virtualMachines/mytestPTVM1"} +$IpConfigurations3 = @(@{"Name" = "ipconfig3"; "Id" = "Microsoft.Network/networkInterfaces/mytestptvm0456/ipConfigurations/ipconfig3"; "LoadBalancerInboundNatRules" = @(@{"Id" = "Microsoft.Network/loadBalancers/myLB/inboundNatRules/MRDP-VM0"}, @{"Id" = "Microsoft.Network/loadBalancers/myLB/inboundNatRules/MWINRM-VM0"})}) +$networkInterface3 = @{"Name" = "mytestptvm0456"; "Id" = "Microsoft.Network/networkInterfaces/mytestptvm0456"; "VirtualMachine" = $virtualMachine3; "IpConfigurations" = $IpConfigurations3} + +$networkInterfaceResources = @($networkInterface1, $networkInterface2,$networkInterface3) + +$IpConfiguration3 = @{"Id" = "Microsoft.Network/loadBalancers/myLB/frontendIPConfigurations/LoadBalancerFrontend"} +$publicIPAddressResources = @(@{"Name" = "myPublicIP"; "Id" = "Microsoft.Network/publicIPAddresses/myPublicIP"; "IpConfiguration" = $IpConfiguration3; "IpAddress" = "40.118.129.77"; "DnsSettings" = @{"Fqdn" = "lbipac2b71e2680c44fd987d.westus.cloudapp.azure.com"}},@{"Name" = "myTestPTVM0"; "Id" = "Microsoft.Network/publicIPAddresses/myTestPTVM0"; "IpConfiguration" = $IpConfiguration3; "IpAddress" = "13.91.111.214"; "DnsSettings" = @{"Fqdn" = "lbipeca3f178ce794301af12.westus.cloudapp.azure.com"}}) + +$inboundNatRules = @(@{"Id" = "Microsoft.Network/loadBalancers/myLB/inboundNatRules/RDP-VM0"}, @{"Id" = "Microsoft.Network/loadBalancers/myLB/inboundNatRules/RDP-VM1"}, @{"Id" = "Microsoft.Network/loadBalancers/myLB/inboundNatRules/WINRM-VM0"}, @{"Id" = "Microsoft.Network/loadBalancers/myLB/inboundNatRules/WINRM-VM1"}, @{"Id" = "Microsoft.Network/loadBalancers/myLB/inboundNatRules/NRDP-VM0"}, @{"Id" = "Microsoft.Network/loadBalancers/myLB/inboundNatRules/NRDP-VM1"}, @{"Id" = "Microsoft.Network/loadBalancers/myLB/inboundNatRules/NWINRM-VM0"}, @{"Id" = "Microsoft.Network/loadBalancers/myLB/inboundNatRules/NWINRM-VM1"},@{"Id" = "Microsoft.Network/loadBalancers/myLB/inboundNatRules/MRDP-VM0"}, @{"Id" = "Microsoft.Network/loadBalancers/myLB/inboundNatRules/MRDP-VM1"}, @{"Id" = "Microsoft.Network/loadBalancers/myLB/inboundNatRules/MWINRM-VM0"}, @{"Id" = "Microsoft.Network/loadBalancers/myLB/inboundNatRules/MWINRM-VM1"}) +$frontEndIPConfigs = @(@{"Name" = "LoadBalancerFrontend"; "PublicIpAddress" = @{"Id" = "Microsoft.Network/publicIPAddresses/myPublicIP"}; "InboundNatRules" = $inboundNatRules}) + +$inboundRule1 = @{"Name" = "RDP-VM0"; "FrontendPort" = "50001"; "BackendPort" = "3389"; "BackendIPConfiguration" = @{"Id" = "Microsoft.Network/networkInterfaces/nic0/ipConfigurations/ipconfig1"}} +$inboundRule2 = @{"Name" = "RDP-VM1"; "FrontendPort" = "50002"; "BackendPort" = "3389"; "BackendIPConfiguration" = $null} +$inboundRule3 = @{"Name" = "WINRM-VM0"; "FrontendPort" = $winrmPort1; "BackendPort" = "5986"; "BackendIPConfiguration" = @{"Id" = "Microsoft.Network/networkInterfaces/nic0/ipConfigurations/ipconfig1"}} +$inboundRule4 = @{"Name" = "WINRM-VM1"; "FrontendPort" = "40002"; "BackendPort" = "5986"; "BackendIPConfiguration" = $null} +$inboundRule5 = @{"Name" = "NRDP-VM0"; "FrontendPort" = "50003"; "BackendPort" = "3389"; "BackendIPConfiguration" = @{"Id" = "Microsoft.Network/networkInterfaces/nicN0/ipConfigurations/ipconfig2"}} +$inboundRule6 = @{"Name" = "NRDP-VM1"; "FrontendPort" = "50004"; "BackendPort" = "3389"; "BackendIPConfiguration" = $null} +$inboundRule7 = @{"Name" = "NWINRM-VM0"; "FrontendPort" = "$winrmPort2"; "BackendPort" = "5986"; "BackendIPConfiguration" = @{"Id" = "Microsoft.Network/networkInterfaces/nicN0/ipConfigurations/ipconfig2"}} +$inboundRule8 = @{"Name" = "NWINRM-VM1"; "FrontendPort" = "40004"; "BackendPort" = "5986"; "BackendIPConfiguration" = $null} +$inboundRule9 = @{"Name" = "MRDP-VM0"; "FrontendPort" = "50005"; "BackendPort" = "3389"; "BackendIPConfiguration" = @{"Id" = "Microsoft.Network/networkInterfaces/mytestptvm0456/ipConfigurations/ipconfig3"}} +$inboundRule10 = @{"Name" = "MRDP-VM1"; "FrontendPort" = "50006"; "BackendPort" = "3389"; "BackendIPConfiguration" = $null} +$inboundRule11 = @{"Name" = "MWINRM-VM0"; "FrontendPort" = "$winrmPort3"; "BackendPort" = "5986"; "BackendIPConfiguration" = @{"Id" = "Microsoft.Network/networkInterfaces/mytestptvm0456/ipConfigurations/ipconfig3"}} +$inboundRule12 = @{"Name" = "MWINRM-VM1"; "FrontendPort" = "40006"; "BackendPort" = "5986"; "BackendIPConfiguration" = $null} +$inboundRules = @($inboundRule1, $inboundRule2, $inboundRule3, $inboundRule4, $inboundRule5, $inboundRule6, $inboundRule7, $inboundRule8,$inboundRule9,$inboundRule10,$inboundRule11,$inboundRule12) + +$loadBalancerDetails = @{"frontEndIPConfigs" = $frontEndIPConfigs; "inboundRules" = $inboundRules} +$loadBalancerResources = @{$lbName = $loadBalancerDetails} + +$azureResourceGroupDeploymentResponse = @{"networkInterfaceResources" = $networkInterfaceResources; "publicIPAddressResources" = $publicIPAddressResources; "loadBalancerResources" = $loadBalancerResources} + +#creating one RG deployment to be used through out test +$resourceGroupDeployments = @{} +$resourceGroupVMs = @{} +$resourceGroupDeployments.Add($validRG, $azureResourceGroupDeploymentResponse) +$resourceGroupVMs.Add($validRG, $VMsStatus) + +$cloudServices = @{} +$cloudServiceWithNoVM = @{"vms" = $null; "vmConnectionDetails" = $null} +$vmConnectionDetailsWithTwoVms = @{$classicvm0 = @{"Name" = $classicvm0; "fqdn" = $classicvmfqdn; "winRMHttpsPort" = $classicWinrmPort1}; $classicvm1 = @{"Name" = $classicvm1; "fqdn" = $classicvmfqdn; "winRMHttpsPort" = $classicWinrmPort2}} +$cloudServiceWithTwoVM = @{"vms" = @(@{"Name" = $classicvm0}, @{"Name" = $classicvm1}); "vmConnectionDetails" = $vmConnectionDetailsWithTwoVms} + +$cloudServices.Add($rgWithNoClassicVms, $cloudServiceWithNoVM) +$cloudServices.Add($rgWithClassicVMs, $cloudServiceWithTwoVM) + +#Extensions +$winRMcustomScripExtensionObject = @{} +$winRMcustomScripExtensionObject["ExtensionType"]="Microsoft.Compute.CustomScriptExtension" +$winRMcustomScripExtensionObject["Name"]="winrmcustomscriptextension" +$winRMcustomScripExtensionObject["TypeHandlerVersion"]="1.4" + +$subStatus0 = @{} +$subStatus0["Code"]="ComponentStatus/StdOut/succeeded" +$subStatus0["DisplayStatus"]="Provisioning succeeded" +$subStatus0["Level"]="Info" +$subStatus0["Message"]="Succeeded\\n\\nDeleted 1 rule(s).\\nOk.\\n\\nOk.\\n" +$subStatus0["Time"]=$null + + +$subStatus1 = @{} +$subStatus1["Code"]="ComponentStatus/StdErr/succeeded" +$subStatus1["DisplayStatus"]="Provisioning succeeded" +$subStatus1["Level"]="Info" +$subStatus1["Message"]="" +$subStatus1["Time"]=$null + +$substatuses = @() +$substatuses+=$subStatus0 +$substatuses+=$subStatus1 + +$winRMcustomScripExtensionObject["SubStatuses"]=@() +$winRMcustomScripExtensionObject["SubStatuses"]+=$substatuses + + +$status0 = @{} +$status0["Code"]="ProvisioningState/succeeded" +$status0["DisplayStatus"]="Provisioning succeeded" +$status0["Level"]="Info" +$status0["Message"]="Finished executing command" +$status0["Time"]=$null + +$statuses = @() +$statuses += $status0 + +$winRMcustomScripExtensionObject["Statuses"]=@() +$winRMcustomScripExtensionObject["Statuses"]+=$statuses + +$extensions = @() +$extensions += $winRMcustomScripExtensionObject + +$getCustomScriptExtensionResponse = @{"Status"="Succeeded"} +$setCustomScriptExtensionResponse = @{"Status"="Succeeded"} +$rgustomScriptExtensionResponse = @{"Status"="Succeeded"} +$winrmCustomScriptExtension="WinRmCustomScriptExtension" +$invalidCustomScriptName = "InvalidConfigureWinRM.ps1" + +$securityGroups = New-Object System.Collections.Generic.List[System.Object] +$securityRules = New-Object System.Collections.Generic.List[System.Object] + +$validSecurityGroupProps = @{"Name"="VMWithSG";"SecurityRules"=$securityRules} +$validSecurityGroup = New-Object PSObject -Property $validSecurityGroupProps +$securityGroups.Add($validSecurityGroup) + + +$securityGroupsRecommended = New-Object System.Collections.Generic.List[System.Object] +$securityRulesRecommended = New-Object System.Collections.Generic.List[System.Object] + +$validSecurityGroupPropsRecommended = @{"Name"="VMWithSGRecPS";"SecurityRules"=$securityRulesRecommended} +$validSecurityGroupRecommended = New-Object PSObject -Property $validSecurityGroupPropsRecommended +$securityGroupsRecommended.Add($validSecurityGroupRecommended) + +$securityGroupsLatest = New-Object System.Collections.Generic.List[System.Object] +$securityRulesLatest = New-Object System.Collections.Generic.List[System.Object] + +$validSecurityGroupPropsLatest = @{"Name"="VMWithSGHighPS";"SecurityRules"=$securityRulesLatest} +$validSecurityGroupLatest = New-Object PSObject -Property $validSecurityGroupPropsLatest +$securityGroupsLatest.Add($validSecurityGroupLatest) + +$vmIdWhichHasSecurityGroupPrevious = "/subscriptions/c94bda7a-0577-4374-9c53-0e46a9fb0f70/resourceGroups/AzureFIleCopyPTRGWithSGDoNotDelete/providers/Microsoft.Compute/virtualMachines/VMWithSG" +$vmIdWhichHasSecurityGroupRecommended = "/subscriptions/c94bda7a-0577-4374-9c53-0e46a9fb0f70/resourceGroups/AzureFIleCopyPTRGWithSGDoNotDelete/providers/Microsoft.Compute/virtualMachines/VMWithSGRecPS" +$vmIdWhichHasSecurityGroupLatest = "/subscriptions/c94bda7a-0577-4374-9c53-0e46a9fb0f70/resourceGroups/AzureFIleCopyPTRGWithSGDoNotDelete/providers/Microsoft.Compute/virtualMachines/VMWithSGHighPS" +$vmIdWhichHasNoSecurityGroup = "/subscriptions/c94bda7a-0577-4374-9c53-0e46a9fb0f70/resourceGroups/AzureFileCopyTaskPlatformTestDoNotDelete/providers/Microsoft.Compute/virtualMachines/mytestVM0" +$duplicateRuleName = "VSO-Custom-WinRM-Https-Port-Deplicate" + +#Create Mock Object type for Hyak.Common.CloudException +$Source = @" + using System; +namespace Hyak.Common { + public class CloudException : Exception { + } +} +"@ +Add-Type -TypeDefinition $Source -Language CSharp + +function Get-AzureStorageKeyFromRDFE +{ + param([string]$storageAccountName) + + if(-not [string]::IsNullOrEmpty($storageAccountName)) + { + if(-not $storageAccounts.ContainsKey($storageAccountName)) + { + throw New-Object Hyak.Common.CloudException + } + + return $storageAccounts[$storageAccountName] + } +} + +function Get-AzureStorageAccountTypeFromRDFE +{ + param([string]$storageAccountName) + + if(-not [string]::IsNullOrEmpty($storageAccountName)) + { + if(-not $storageAccounts.ContainsKey($storageAccountName)) + { + throw New-Object Hyak.Common.CloudException + } + + return $storageAccounts[$storageAccountName] + } +} + +function Get-AzureBlobStorageEndpointFromRDFE +{ + param([string]$storageAccountName) + + if(-not [string]::IsNullOrEmpty($storageAccountName)) + { + if(-not $storageAccounts.ContainsKey($storageAccountName)) + { + throw New-Object Hyak.Common.CloudException + } + + return $storageAccounts[$storageAccountName] + } +} + +function Get-AzureBlobStorageEndpointFromARM +{ + param([string]$storageAccountName) + + if(-not [string]::IsNullOrEmpty($storageAccountName)) + { + if(-not $storageAccounts.ContainsKey($storageAccountName)) + { + throw "Unable to find storage type $storageAccountName with Connection SPN" + } + + return $storageAccounts[$storageAccountName] + } +} + +function Get-AzureStorageAccountResourceGroupName +{ + param([string]$storageAccountName) + + if (-not [string]::IsNullOrEmpty($storageAccountName)) + { + if(-not $storageAccountsRG.ContainsKey($storageAccountName)) + { + throw "Storage account: $storageAccountName not found. Selected Connection 'ServicePrincipal' supports storage account of Azure Resource Manager type only." + } + + return $storageAccountsRG[$storageAccountName] + } +} + +function Get-AzureStorageKeyFromARM +{ + param([string]$storageAccountName) + + if(-not [string]::IsNullOrEmpty($storageAccountName)) + { + if(-not $storageAccounts.ContainsKey($storageAccountName)) + { + throw "Storage account: $storageAccountName not found. Selected Connection 'ServicePrincipal' supports storage account of Azure Resource Manager type only." + } + + return $storageAccounts[$storageAccountName] + } +} + +function Create-AzureStorageContext +{ + param([string]$storageAccountName, + [string]$storageAccountKey) + + if(-not [string]::IsNullOrEmpty($storageAccountName) -and -not [string]::IsNullOrEmpty($storageAccountKey)) + { + if(-not $storageAccounts.ContainsKey($storageAccountName)) + { + return + } + + return $storageAccountsContext[$storageAccountName] + } +} + +function Get-AzureCloudService +{ + param([string]$cloudServiceName) + + if(-not [string]::IsNullOrEmpty($cloudServiceName)) + { + if(-not $cloudServices.ContainsKey($cloudServiceName)) + { + throw New-Object Hyak.Common.CloudException + } + + return + } +} + +function Get-AzureClassicVMsInResourceGroup +{ + param([string]$resourceGroupName) + + if(-not [string]::IsNullOrEmpty($resourceGroupName) -and $cloudServices.ContainsKey($resourceGroupName)) + { + return $($cloudServices[$resourceGroupName])["vms"] + } +} + +function Get-AzureClassicVMsConnectionDetailsInResourceGroup +{ + param([string]$resourceGroupName, + [object]$azureClassicVMResources) + + if(-not [string]::IsNullOrEmpty($resourceGroupName) -and $cloudServices.ContainsKey($resourceGroupName)) + { + return $($cloudServices[$resourceGroupName])["vmConnectionDetails"] + } +} + +function Get-AzureRMVMsInResourceGroup +{ + param([string]$resourceGroupName) + + if(-not [string]::IsNullOrEmpty($resourceGroupName)) + { + if(-not $resourceGroups.ContainsKey($resourceGroupName)) + { + throw "Provided resource group '$resourceGroupName' does not exist." + } + + if($resourceGroupDeployments.ContainsKey($resourceGroupName)) + { + return $vmResources + } + } +} + +function Get-AzureRMResourceGroupResourcesDetails +{ + param([string]$resourceGroupName, + [object]$azureRMVMResources) + + if(-not [string]::IsNullOrEmpty($resourceGroupName)) + { + if(-not $resourceGroups.ContainsKey($resourceGroupName)) + { + throw "Resource group '$resourceGroupName' could not be found." + } + + if($resourceGroupDeployments.ContainsKey($resourceGroupName)) + { + return $resourceGroupDeployments[$resourceGroupName] + } + } + + return @{} +} + +function Generate-AzureStorageContainerSASToken +{ + param([string]$containerName, + [object]$storageContext, + [System.Int32]$tokenTimeOutInHours) + + if(-not [string]::IsNullOrEmpty($containerName) -and $storageContext) + { + return $validSasToken + } +} + +function Remove-AzureContainer +{ + +} + +function Get-AzureMachineStatus +{ + param([string]$resourceGroupName, + [string]$name) + + if(-not [string]::IsNullOrEmpty($resourceGroupName) -and -not [string]::IsNullOrEmpty($name)) + { + if(-not $resourceGroups.ContainsKey($resourceGroupName)) + { + throw "Resource group '$resourceGroupName' could not be found." + } + + $VMs = $resourceGroups[$resourceGroupName].VMsDetails + if($VMs -and $VMs.ContainsKey($name)) + { + $tempExts = $vmInstanceViews[$name]["Extensions"] + if($tempExts -and $tempExts.Count -ge 1) + { + $status = @{} + $status["Extensions"] = $tempExts + #$customScriptExtension=$tempExts[0] + } + else + { + throw "No extension exists with name '$winrmCustomScriptExtension'" + } + } + else + { + throw "The Resource 'Microsoft.Compute/virtualMachines/$name/extensions/$winrmCustomScriptExtension' under resource group '$resourceGroupName' was not found." + } + } + + return $status +} + +function Get-AzureMachineCustomScriptExtension +{ + param([string]$resourceGroupName, + [string]$vmName, + [string]$name) + + $errMsg="The Resource 'Microsoft.Compute/virtualMachines/$vmName/extensions/$name' under resource group '$resourceGroupName' was not found." + + if(-not [string]::IsNullOrEmpty($resourceGroupName) -and -not [string]::IsNullOrEmpty($vmName)) + { + if(-not $resourceGroups.ContainsKey($resourceGroupName)) + { + throw "Resource group '$resourceGroupName' could not be found." + } + + $VMs = $resourceGroups[$resourceGroupName].VMsDetails + if($VMs -and $VMs.ContainsKey($vmName)) + { + if($name) + { + $tempExts = $vmInstanceViews[$vmName]["Extensions"] + if($tempExts -and $tempExts.Count -ge 1) + { + $response = @{} + if($tempExts[0]["SubStatuses"][1]["Message"] -and $extension[0]["SubStatuses"][1]["Message"] -ne "") + { + $response["ProvisioningState"]="Failed" + } + else + { + $response["ProvisioningState"]="Succeeded" + } + } + else + { + throw $errMsg + } + } + else + { + throw $errMsg + } + } + else + { + throw $errMsg + } + } + + return $response +} + +function Set-AzureMachineCustomScriptExtension +{ + param([string]$resourceGroupName, + [string]$vmName, + [string]$name, + [string[]]$fileUri, + [string]$run, + [string]$argument, + [string]$location) + + if(-not [string]::IsNullOrEmpty($resourceGroupName) -and -not [string]::IsNullOrEmpty($vmName) -and -not [string]::IsNullOrEmpty($name)) + { + if(-not [string]::IsNullOrEmpty($resourceGroupName) -and -not [string]::IsNullOrEmpty($vmName)) + { + if(-not $resourceGroups.ContainsKey($resourceGroupName)) + { + throw "Resource group '$resourceGroupName' could not be found." + } + + $VMs = $resourceGroups[$resourceGroupName].VMsDetails + if($VMs -and $VMs.ContainsKey($vmName)) + { + $response = @{} + + if(-not $fileUri) + { + throw "Cannot validate argument on parameter 'FileUri'. The argument is null or empty." + } + + if(-not $run) + { + throw "Cannot validate argument on parameter 'Run'. The argument is null or empty." + } + + if(-not $argument) + { + throw "Cannot validate argument on parameter 'Argument'. The argument is null or empty." + } + + if(-not $location) + { + throw "Cannot validate argument on parameter 'Location'. The argument is null or empty." + } + + if($fileUri.Count -eq 2) + { + $extensions[0]["SubStatuses"][1]["Message"]="'.\winrmconf.cmd' is not recognized as an internal or external command,\noperable program or batch file." + $response["Status"]="Succeeded" + } + elseif($run -eq $invalidCustomScriptName) + { + $extensions[0]["SubStatuses"][1]["Message"]="The argument '$invalidCustomScriptName' to the -File parameter does not exist. Provide the path to an existing '.ps1' file as an argument to the -File parameter." + $errorDetails = @{"Message" = "VM has reported a failure when processing extension 'WinRMCustomScriptExtension'. Error message: Finished executing command."} + $response["Error"]= $errorDetails + $response["Status"]="Failed" + } + else + { + $extensions[0]["SubStatuses"][1]["Message"]="" + $response["Status"]="Succeeded" + } + + $vmInstanceViews[$vmName]["Extensions"]=$extensions + } + else + { + throw "Can not perform requested operation on nested resource. Parent resource '$vmName' not found." + } + } + } + + return $response +} + +function Remove-AzureMachineCustomScriptExtension +{ + param([string]$resourceGroupName, + [string]$vmName, + [string]$name) + + if(-not [string]::IsNullOrEmpty($resourceGroupName) -and -not [string]::IsNullOrEmpty($vmName) -and -not [string]::IsNullOrEmpty($name)) + { + + if(-not [string]::IsNullOrEmpty($resourceGroupName) -and -not [string]::IsNullOrEmpty($vmName)) + { + $response = @{} + $VMs = $resourceGroups[$resourceGroupName].VMsDetails + if($VMs -and $VMs.ContainsKey($vmName)) + { + $tempExts = $vmInstanceViews[$vmName]["Extensions"] + if($tempExts -and $tempExts.Count -ge 1) + { + $vmInstanceViews[$vmName]["extensions"]=@() + $response["Status"]="Succeeded" + } + else + { + $response["Status"]="Succeeded" + } + } + else + { + $response["Status"]="Succeeded" + } + } + } + + return $response +} + +function Add-AzureNetworkSecurityRuleConfig +{ +} + +function Add-NetworkSecurityRuleConfig +{ + param([string]$resourceGroupName, + [object]$securityGroups, + [string]$ruleName, + [string]$rulePriotity, + [string]$winrmHttpsPort) + + if(($securityGroups.Count -gt 0) -and (-not $securityGroups[0].SecurityRules -or $ruleName -eq $duplicateRuleName)) + { + Add-AzureNetworkSecurityRuleConfig + + $tempRulePriority = "3986" + if($ruleName -eq $duplicateRuleName) + { + $tempRulePriority = "4036" + } + + $securityRuleProps = @{"Name"=$ruleName;"Priority"=$tempRulePriority} + $securityRule = New-Object PSObject -Property $securityRuleProps + $securityGroups[0].SecurityRules += $securityRule + } + + return $securityGroups +} + +function Set-AzureNetworkSecurityGroup +{ + param([object]$NetworkSecurityGroup) + + if($NetworkSecurityGroup.Name -eq $validSecurityGroup.Name) + { + $validSecurityGroup = $NetworkSecurityGroup + } + + return $validSecurityGroup +} + +function Get-NetworkSecurityGroups +{ + param([string] $resourceGroupName, + [string] $vmId) + + if($vmId -eq $vmIdWhichHasNoSecurityGroup) + { + return @() + } + elseif($vmId -eq $vmIdWhichHasSecurityGroupPrevious) + { + return $securityGroups + } + elseif($vmId -eq $vmIdWhichHasSecurityGroupRecommended) + { + return $securityGroupsRecommended + } + elseif($vmId -eq $vmIdWhichHasSecurityGroupLatest) + { + return $securityGroupsLatest + } + else + { + throw "[Azure Call]No network interface found with virtual machine id $vmId under resource group $rgNameWithSecurityGroup" + } +} + +# Used only in test code +function Remove-NetworkSecurityRuleConfig +{ + param([object] $securityGroups, + [string] $ruleName) + + $validSecurityGroup["SecurityRules"]=@() +} \ No newline at end of file diff --git a/Tasks/AzureFileCopy/Tests/MockVariable.ps1 b/Tasks/AzureFileCopy/Tests/MockVariable.ps1 new file mode 100644 index 000000000000..373cb5bc6502 --- /dev/null +++ b/Tasks/AzureFileCopy/Tests/MockVariable.ps1 @@ -0,0 +1,45 @@ + +$validInputSourcePath = Join-Path $env:windir "Source" +$validInputAzureBlobDestinationType = "AzureBlob" +$validInputAzureVmsDestinationType = "AzureVms" +$validInputStorageAccount = "validInputStorageAccount" +$validInputContainerName = "validContainerName" +$validInputBlobPrefix = "validBlobPrefix" +$validResourceGroupName = "validResourceGroupName" +$validInputVmsAdminUserName = "validInputVmsAdminUserName" +$validInputVmsAdminPassword = "validInputVmsAdminPassword" +$validSasToken = '?sv=2015-02-21&sr=c&sig=Ncs6hCfAhzwwWd19eP7ToJATsS3xS1laFfPmRwO90qY%3D&se=2016-01-04T18%3A13%3A12Z&sp=rwdl' + +$validStorageKey = "validsotrageKey" +$validAzCopyLocation = Join-Path $env:windir "AzCopyLocation" +$validInputTargetPath = Join-Path $env:windir "Target" + +$failedStatus = "Failed" +$failedCopyLog = "Failed Copy Operation" +$failedCopyError = $failedCopyLog +$failedDeploymentResponseForCopy = @{"MachineName" = "vm0"; "Status" = $failedStatus; "DeploymentLog" = $failedCopyLog; "ServiceLog" = $null; "Error" = @{"Message" = $failedCopyError}} + +$passedStatus = "Passed" +$successLog = "Success Logs" +$passedDeploymentResponseForCopy = @{"Status" = $passedStatus; "DeploymentLog" = $successLog; "ServiceLog" = $null; "Error" = $null} +$passedLatestDeploymentResponseForCopy = @{"Status" = $passedStatus; "DeploymentLog" = $successLog; "ServiceLog" = $null; "Error" = $null} + +$guidingMessageForAzureFileCopy = "For more info please refer to https://aka.ms/azurefilecopyreadme" +$winrmHelpMsg = "To fix WinRM connection related issues, select the 'Enable Copy Prerequisites' option in the task. If set already, and the target Virtual Machines are backed by a Load balancer, ensure Inbound NAT rules are configured for target port (5986). Applicable only for ARM VMs." + +$succeededStatus = "Succeeded" +$succeededCopyResponse = @{"Status" = $succeededStatus; "Log" = $null; "Error" = $null} + +$assembly = New-Object System.Collections.Generic.List``1[System.Object] + +$testJobs = New-Object System.Collections.Generic.List``1[System.Object] +$failedJob = @{"Id" = "1"; "Status" = "Completed"} +$passedJob = @{"Id" = "2"; "Status" = "Completed"} +$passedLatestJob = @{"Id" = "3"; "Status" = "Completed"} +$passedJob1 = @{"Id" = "1"; "Status" = "Completed"} + +$jobFailedResponse = @{"Status" = $failedStatus; "DeploymentLog" = $failedCopyLog; "ServiceLog" = $null; "Error" = $null} +$jobPassedResponse = @{"Status" = $passedStatus; "DeploymentLog" = $successLog; "ServiceLog" = $null; "Error" = $null} +$jobPassedLatestResponse = @{"Status" = $passedStatus; "DeploymentLog" = $successLog; "ServiceLog" = $null; "Error" = $null} + +$connectedServiceName = "DummyConnectedServiceName" diff --git a/Tasks/XamarinLicense/tsconfig.json b/Tasks/AzureFileCopy/tsconfig.json similarity index 60% rename from Tasks/XamarinLicense/tsconfig.json rename to Tasks/AzureFileCopy/tsconfig.json index 0438b79f69ac..79a868c8d1e3 100644 --- a/Tasks/XamarinLicense/tsconfig.json +++ b/Tasks/AzureFileCopy/tsconfig.json @@ -2,5 +2,8 @@ "compilerOptions": { "target": "ES6", "module": "commonjs" - } + }, + "exclude": [ + "node_modules" + ] } \ No newline at end of file diff --git a/Tasks/AzurePowerShell/task.loc.json b/Tasks/AzurePowerShell/task.loc.json index 38ff7718d49a..380ffcc47ef9 100644 --- a/Tasks/AzurePowerShell/task.loc.json +++ b/Tasks/AzurePowerShell/task.loc.json @@ -84,4 +84,4 @@ "InvalidScriptArguments0": "ms-resource:loc.messages.InvalidScriptArguments0", "InvalidScriptPath0": "ms-resource:loc.messages.InvalidScriptPath0" } -} +} \ No newline at end of file diff --git a/Tasks/AzureRmWebAppDeployment/Strings/resources.resjson/en-US/resources.resjson b/Tasks/AzureRmWebAppDeployment/Strings/resources.resjson/en-US/resources.resjson index 23c19f692894..7c2698f2c9a0 100644 --- a/Tasks/AzureRmWebAppDeployment/Strings/resources.resjson/en-US/resources.resjson +++ b/Tasks/AzureRmWebAppDeployment/Strings/resources.resjson/en-US/resources.resjson @@ -5,7 +5,6 @@ "loc.instanceNameFormat": "Deploy AzureRM App Service: $(WebAppName)", "loc.group.displayName.AdditionalDeploymentOptions": "Additional Deployment Options", "loc.group.displayName.output": "Output", - "loc.group.displayName.FileTransformsAndVariableSubstitution": "File Transforms and Variable Substitutions", "loc.input.label.ConnectedServiceName": "AzureRM Subscription", "loc.input.help.ConnectedServiceName": "Select the Azure Resource Manager subscription for the deployment.", "loc.input.label.WebAppName": "App Service Name", @@ -34,9 +33,6 @@ "loc.input.help.AdditionalArguments": "Additional Web Deploy arguments that will be applied when deploying the Azure Web App like,-disableLink:AppPoolExtension -disableLink:ContentExtension.", "loc.input.label.TakeAppOfflineFlag": "Take App Offline", "loc.input.help.TakeAppOfflineFlag": "Select the option to take the AzureRM Web App offline by placing an app_offline.htm file in the root directory of the Web App before the sync operation begins. The file will be removed after the sync operation completes successfully.", - "loc.input.label.XmlTransformsAndVariableSubstitutions": "XML Transforms & Variable Substitutions", - "loc.input.label.VariableSubstitution": "Variable Substitution", - "loc.input.help.VariableSubstitution": "Variables defined in the Build or Release Definition will be automatically substituted in the appSettings, applicationSettings, and connectionStrings section of the config files. If same variables are defined in the Release Definition and in the Environment, then the Environment variables will supersede the Release Definition variables. Variable Substitution is run after Config Transforms.", "loc.messages.Invalidwebapppackageorfolderpathprovided": "Invalid webapp package or folder path provided: %s", "loc.messages.SetParamFilenotfound0": "Set parameters file not found: %s", "loc.messages.GotconnectiondetailsforazureRMWebApp0": "Got connection details for azureRM WebApp:'%s'", @@ -84,5 +80,6 @@ "loc.messages.PublishusingwebdeployoptionsaresupportedonlywhenusingWindowsagent": "Publish using webdeploy options are supported only when using Windows agent", "loc.messages.WebAppDoesntExist": "Webapp '%s' doesn't exist. Webapp should exist before deployment.", "loc.messages.EncodeNotSupported": "Detected file encoding of the file %s as %s. Variable substitution and Transformation is not supported with file encoding %s. Supported encodings are UTF-8 and UTF-16 LE.", - "loc.messages.UnknownFileEncodeError": "Unable to detect encoding of the file %s. Supported encodings are UTF-8 and UTF-16 LE." + "loc.messages.UnknownFileEncodeError": "Unable to detect encoding of the file %s (typeCode: %s). Supported encodings are UTF-8 and UTF-16 LE.", + "loc.messages.ShortFileBufferError": "File buffer is too short to detect encoding type : %s" } \ No newline at end of file diff --git a/Tasks/AzureRmWebAppDeployment/Tests/L0.ts b/Tasks/AzureRmWebAppDeployment/Tests/L0.ts index 808db8f3bc61..0e108234e70f 100644 --- a/Tasks/AzureRmWebAppDeployment/Tests/L0.ts +++ b/Tasks/AzureRmWebAppDeployment/Tests/L0.ts @@ -189,7 +189,9 @@ describe('AzureRmWebAppDeployment Suite', function() { assert(tr.stderr.length > 0 || tr.errorIssues.length > 0, 'should have written to stderr'); var expectedErr = 'Error: loc_mock_SetParamFilenotfound0'; assert(tr.stdErrContained(expectedErr) || tr.createdErrorIssue(expectedErr), 'should have said: ' + expectedErr); - assert(tr.failed, 'task should have succeeded'); + var expectedOut = 'Failed to update history to kudu'; + assert(tr.stdout.search(expectedOut) >= 0, 'should have said: ' + expectedOut); + assert(tr.failed, 'task should have failed'); done(); }); @@ -202,6 +204,8 @@ describe('AzureRmWebAppDeployment Suite', function() { assert(tr.stderr.length > 0 || tr.errorIssues.length > 0, 'should have written to stderr'); var expectedErr = 'Error: loc_mock_MorethanonepackagematchedwithspecifiedpatternPleaserestrainthesearchpatern'; assert(tr.stdErrContained(expectedErr) || tr.createdErrorIssue(expectedErr), 'should have said: ' + expectedErr); + var expectedOut = 'Failed to update history to kudu'; + assert(tr.stdout.search(expectedOut) >= 0, 'should have said: ' + expectedOut); assert(tr.failed, 'task should have failed'); done(); }); @@ -214,7 +218,9 @@ describe('AzureRmWebAppDeployment Suite', function() { assert(tr.invokedToolCount == 0, 'should not have invoked any tool'); assert(tr.stderr.length > 0 || tr.errorIssues.length > 0, 'should have written to stderr'); var expectedErr = 'Error: Not found Invalid_webAppPkg'; - assert(tr.stdErrContained(expectedErr) || tr.createdErrorIssue(expectedErr), 'should have said: ' + expectedErr); + assert(tr.stdErrContained(expectedErr) || tr.createdErrorIssue(expectedErr), 'should have said: ' + expectedErr); + var expectedOut = 'Failed to update history to kudu'; + assert(tr.stdout.search(expectedOut) >= 0, 'should have said: ' + expectedOut); assert(tr.failed, 'task should have failed'); done(); }); @@ -226,7 +232,9 @@ describe('AzureRmWebAppDeployment Suite', function() { assert(tr.invokedToolCount == 1, 'should have invoked tool once'); assert(tr.stderr.length == 0 && tr.errorIssues.length == 0, 'should not have written to stderr'); - assert(tr.succeeded, 'task should have failed'); + assert(tr.succeeded, 'task should have succeeded'); + var expectedOut = 'Updated history to kudu'; + assert(tr.stdout.search(expectedOut) > 0, 'should have said: ' + expectedOut); done(); }); @@ -249,7 +257,7 @@ describe('AzureRmWebAppDeployment Suite', function() { let tp = path.join(__dirname, 'L0NonWindowsFolderPkg.js'); let tr : ttm.MockTestRunner = new ttm.MockTestRunner(tp); tr.run(); - + assert(tr.invokedToolCount == 0, 'should not have invoked any tool'); assert(tr.stderr.length == 0 && tr.errorIssues.length == 0, 'should not have written to stderr'); var expectedOut = 'loc_mock_Compressedfolderintozip'; @@ -286,6 +294,8 @@ describe('AzureRmWebAppDeployment Suite', function() { assert(tr.stderr.length > 0 || tr.errorIssues.length > 0, 'should have written to stderr'); var expectedErr = 'Error: Error: Folder Archiving Failed'; assert(tr.stdErrContained(expectedErr) || tr.createdErrorIssue(expectedErr), 'should have said: ' + expectedErr); + var expectedOut = 'Failed to update history to kudu'; + assert(tr.stdout.search(expectedOut) > 0, 'should have said: ' + expectedOut); assert(tr.failed, 'task should have failed'); done(); }); @@ -328,7 +338,9 @@ describe('AzureRmWebAppDeployment Suite', function() { var expectedErr = "Error: loc_mock_XdtTransformationErrorWhileTransforming"; assert(tr.invokedToolCount == 1, 'should have invoked tool only once'); assert(tr.stderr.length > 0 || tr.errorIssues.length > 0, 'should have written to stderr'); - assert(tr.stdErrContained(expectedErr) || tr.createdErrorIssue(expectedErr), 'E should have said: ' + expectedErr); + assert(tr.stdErrContained(expectedErr) || tr.createdErrorIssue(expectedErr), 'E should have said: ' + expectedErr); + var expectedOut = 'Failed to update history to kudu'; + assert(tr.stdout.search(expectedOut) > 0, 'should have said: ' + expectedOut); assert(tr.failed, 'task should have failed'); done(); }); @@ -341,7 +353,9 @@ describe('AzureRmWebAppDeployment Suite', function() { var expectedErr = "Error: loc_mock_CannotPerformXdtTransformationOnNonWindowsPlatform"; assert(tr.invokedToolCount == 0, 'should not have invoked tool any tool'); assert(tr.stderr.length > 0 || tr.errorIssues.length > 0, 'should have written to stderr'); - assert(tr.stdErrContained(expectedErr) || tr.createdErrorIssue(expectedErr), 'E should have said: ' + expectedErr); + assert(tr.stdErrContained(expectedErr) || tr.createdErrorIssue(expectedErr), 'E should have said: ' + expectedErr); + var expectedOut = 'Failed to update history to kudu'; + assert(tr.stdout.search(expectedOut) > 0, 'should have said: ' + expectedOut); assert(tr.failed, 'task should have failed'); done(); }); @@ -358,6 +372,8 @@ describe('AzureRmWebAppDeployment Suite', function() { var resultFile = ltx.parse(fs.readFileSync(path.join(__dirname, 'L1XmlVarSub/Web_test.Debug.config'))); var expectFile = ltx.parse(fs.readFileSync(path.join(__dirname, 'L1XmlVarSub/Web_Expected.Debug.config'))); assert(ltx.equal(resultFile, expectFile) , 'Should have substituted variables in Web.Debug.config file'); + var expectedOut = 'Updated history to kudu'; + assert(tr.stdout.search(expectedOut) > 0, 'should have said: ' + expectedOut); done(); }); @@ -378,4 +394,25 @@ describe('AzureRmWebAppDeployment Suite', function() { done(); }); + it('Validate File Encoding', (done:MochaDone) => { + let tp = path.join(__dirname, 'L0ValidateFileEncoding.js'); + let tr : ttm.MockTestRunner = new ttm.MockTestRunner(tp); + tr.run(); + + assert(tr.stdout.search('UTF-8 with BOM validated') >= 0, 'Should have validated UTF-8 with BOM'); + assert(tr.stdout.search('UTF-16LE with BOM validated') >= 0, 'Should have validated UTF-16LE with BOM'); + assert(tr.stdout.search('UTF-16BE with BOM validated') >= 0, 'Should have validated UTF-16BE with BOM'); + assert(tr.stdout.search('UTF-32LE with BOM validated') >= 0, 'Should have validated UTF-32LE with BOM'); + assert(tr.stdout.search('UTF-32BE with BOM validated') >= 0, 'Should have validated UTF-32BE with BOM'); + + assert(tr.stdout.search('UTF-8 without BOM validated') >= 0, 'Should have validated UTF-8 without BOM'); + assert(tr.stdout.search('UTF-16LE without BOM validated') >= 0, 'Should have validated UTF-16LE without BOM'); + assert(tr.stdout.search('UTF-16BE without BOM validated') >= 0, 'Should have validated UTF-16BE without BOM'); + assert(tr.stdout.search('UTF-32LE without BOM validated') >= 0, 'Should have validated UTF-32LE without BOM'); + assert(tr.stdout.search('UTF-32BE without BOM validated') >= 0, 'Should have validated UTF-32BE without BOM'); + + assert(tr.stdout.search('Short File Buffer Error') >= 0, 'Should have validated short Buffer'); + assert(tr.stdout.search('Unknown encoding type') >= 0, 'Should throw for Unknown File Buffer'); + done(); + }); }); diff --git a/Tasks/AzureRmWebAppDeployment/Tests/L0JsonVarSub.ts b/Tasks/AzureRmWebAppDeployment/Tests/L0JsonVarSub.ts index 4ab159261cf0..737f96d92af0 100644 --- a/Tasks/AzureRmWebAppDeployment/Tests/L0JsonVarSub.ts +++ b/Tasks/AzureRmWebAppDeployment/Tests/L0JsonVarSub.ts @@ -146,10 +146,7 @@ tr.registerMock('webdeployment-common/azurerestutility.js', { } return config; - } -}); - -tr.registerMock('./azurerestutility.js', { + }, updateDeploymentStatus: function(publishingProfile, isDeploymentSuccess ) { if(isDeploymentSuccess) { console.log('Updated history to kudu'); diff --git a/Tasks/AzureRmWebAppDeployment/Tests/L0NonWindowsFailArchive.ts b/Tasks/AzureRmWebAppDeployment/Tests/L0NonWindowsFailArchive.ts index 9ce66d807c39..e1451545debf 100644 --- a/Tasks/AzureRmWebAppDeployment/Tests/L0NonWindowsFailArchive.ts +++ b/Tasks/AzureRmWebAppDeployment/Tests/L0NonWindowsFailArchive.ts @@ -139,6 +139,7 @@ tr.registerMock('webdeployment-common/azurerestutility.js', { } var webAppPublishKuduUrl = publishingProfile.publishUrl; var requestDetails = kuduDeploymentLog.getUpdateHistoryRequest(webAppPublishKuduUrl, isDeploymentSuccess); + requestDetails["requestBody"].author = 'author'; console.log("kudu log requestBody is:" + JSON.stringify(requestDetails["requestBody"])); }, getAzureRMWebAppConfigDetails: function(SPN, webAppName, resourceGroupName, deployToSlotFlag, slotName) { @@ -153,24 +154,7 @@ tr.registerMock('webdeployment-common/azurerestutility.js', { } }); -tr.registerMock('./azurerestutility.js', { - updateDeploymentStatus: function(publishingProfile, isDeploymentSuccess ) { - if(isDeploymentSuccess) { - console.log('Updated history to kudu'); - } - else { - console.log('Failed to update history to kudu'); - } - var webAppPublishKuduUrl = publishingProfile.publishUrl; - var requestDetails = kuduDeploymentLog.getUpdateHistoryRequest(webAppPublishKuduUrl, isDeploymentSuccess); - console.log("kudu log requestBody is:" + JSON.stringify(requestDetails["requestBody"])); - } -}); - tr.registerMock('./kuduutility.js', { - archiveFolder: function(webAppPackage, webAppZipFile) { - throw new Error('Folder Archiving Failed'); - }, getVirtualAndPhysicalPaths: function (virtualApplication, virtualApplicationMappings) { // construct URL depending on virtualApplication or root of webapplication var physicalPath = "/site/wwwroot"; diff --git a/Tasks/AzureRmWebAppDeployment/Tests/L0NonWindowsFolderPkg.ts b/Tasks/AzureRmWebAppDeployment/Tests/L0NonWindowsFolderPkg.ts index 698442b877c8..5f033ed4c8a4 100644 --- a/Tasks/AzureRmWebAppDeployment/Tests/L0NonWindowsFolderPkg.ts +++ b/Tasks/AzureRmWebAppDeployment/Tests/L0NonWindowsFolderPkg.ts @@ -139,6 +139,7 @@ tr.registerMock('webdeployment-common/azurerestutility.js', { } var webAppPublishKuduUrl = publishingProfile.publishUrl; var requestDetails = kuduDeploymentLog.getUpdateHistoryRequest(webAppPublishKuduUrl, isDeploymentSuccess); + requestDetails["requestBody"].author = 'author'; console.log("kudu log requestBody is:" + JSON.stringify(requestDetails["requestBody"])); }, getAzureRMWebAppConfigDetails: function(SPN, webAppName, resourceGroupName, deployToSlotFlag, slotName) { @@ -153,20 +154,6 @@ tr.registerMock('webdeployment-common/azurerestutility.js', { } }); -tr.registerMock('./azurerestutility.js', { - updateDeploymentStatus: function(publishingProfile, isDeploymentSuccess ) { - if(isDeploymentSuccess) { - console.log('Updated history to kudu'); - } - else { - console.log('Failed to update history to kudu'); - } - var webAppPublishKuduUrl = publishingProfile.publishUrl; - var requestDetails = kuduDeploymentLog.getUpdateHistoryRequest(webAppPublishKuduUrl, isDeploymentSuccess); - console.log("kudu log requestBody is:" + JSON.stringify(requestDetails["requestBody"])); - } -}); - tr.registerMock('./kuduutility.js', { deployWebAppPackage: function(webAppPackage, webAppZipFile) { console.log ('Deployed using KuduDeploy'); @@ -190,7 +177,10 @@ tr.registerMock('./kuduutility.js', { containsParamFile: function (webAppPackage) { var isParamFilePresent = false; return isParamFilePresent; - }, + } +}); + +tr.registerMock('webdeployment-common/ziputility.js', { archiveFolder : function() { console.log('Folder Archiving Successful'); } diff --git a/Tasks/AzureRmWebAppDeployment/Tests/L0NonWindowsParamFileinPkg.ts b/Tasks/AzureRmWebAppDeployment/Tests/L0NonWindowsParamFileinPkg.ts index ba63698f309f..ca6b3ab76e63 100644 --- a/Tasks/AzureRmWebAppDeployment/Tests/L0NonWindowsParamFileinPkg.ts +++ b/Tasks/AzureRmWebAppDeployment/Tests/L0NonWindowsParamFileinPkg.ts @@ -132,6 +132,7 @@ tr.registerMock('webdeployment-common/azurerestutility.js', { } var webAppPublishKuduUrl = publishingProfile.publishUrl; var requestDetails = kuduDeploymentLog.getUpdateHistoryRequest(webAppPublishKuduUrl, isDeploymentSuccess); + requestDetails["requestBody"].author = 'author'; console.log("kudu log requestBody is:" + JSON.stringify(requestDetails["requestBody"])); }, getAzureRMWebAppConfigDetails: function(SPN, webAppName, resourceGroupName, deployToSlotFlag, slotName) { @@ -146,21 +147,6 @@ tr.registerMock('webdeployment-common/azurerestutility.js', { } }); -tr.registerMock('./azurerestutility.js', { - - updateDeploymentStatus: function(publishingProfile, isDeploymentSuccess ) { - if(isDeploymentSuccess) { - console.log('Updated history to kudu'); - } - else { - console.log('Failed to update history to kudu'); - } - var webAppPublishKuduUrl = publishingProfile.publishUrl; - var requestDetails = kuduDeploymentLog.getUpdateHistoryRequest(webAppPublishKuduUrl, isDeploymentSuccess); - console.log("kudu log requestBody is:" + JSON.stringify(requestDetails["requestBody"])); - } -}); - tr.registerMock('./kuduutility.js', { deployWebAppPackage: function(webAppPackage, webAppZipFile) { console.log ('Deployed using KuduDeploy'); diff --git a/Tasks/AzureRmWebAppDeployment/Tests/L0ValidateFileEncoding.ts b/Tasks/AzureRmWebAppDeployment/Tests/L0ValidateFileEncoding.ts new file mode 100644 index 000000000000..e6b26fc39c86 --- /dev/null +++ b/Tasks/AzureRmWebAppDeployment/Tests/L0ValidateFileEncoding.ts @@ -0,0 +1,77 @@ +var fileEncoding = require('../node_modules/webdeployment-common/fileencoding.js'); + +var fileEncodeType = fileEncoding.detectFileEncoding('utf-8.txt', new Buffer([239, 187, 191, 0])); +if(fileEncodeType[0] === 'utf-8' && fileEncodeType[1]) { + console.log('UTF-8 with BOM validated'); +} + +try { + var fileEncodeType = fileEncoding.detectFileEncoding('utf-32le.txt', new Buffer([255, 254, 0, 0])); +} +catch(exception) { + console.log('UTF-32LE with BOM validated'); +} + +try { + var fileEncodeType = fileEncoding.detectFileEncoding('utf-16be.txt', new Buffer([254, 255, 0 ,0])); +} +catch(exception) { + console.log('UTF-16BE with BOM validated'); +} + +var fileEncodeType = fileEncoding.detectFileEncoding('utf-16le.txt', new Buffer([255, 254, 10, 10])); +if(fileEncodeType[0] === 'utf-16le' && fileEncodeType[1]) { + console.log('UTF-16LE with BOM validated'); +} + +try { + var fileEncodeType = fileEncoding.detectFileEncoding('utf-32BE.txt', new Buffer([0, 0, 254, 255])); +} +catch(exception) { + console.log('UTF-32BE with BOM validated'); +} + +var fileEncodeType = fileEncoding.detectFileEncoding('utf-8.txt', new Buffer([10, 11, 12, 13])); +if(fileEncodeType[0] === 'utf-8' && !fileEncodeType[1]) { + console.log('UTF-8 without BOM validated'); +} + +try { + var fileEncodeType = fileEncoding.detectFileEncoding('utf-32le.txt', new Buffer([255, 0, 0, 0])); +} +catch(exception) { + console.log('UTF-32LE without BOM validated'); +} + +try { + var fileEncodeType = fileEncoding.detectFileEncoding('utf-32be.txt', new Buffer([0, 0, 0, 255])); +} +catch(exception) { + console.log('UTF-32BE without BOM validated'); +} + +try { + var fileEncodeType = fileEncoding.detectFileEncoding('utf-16be.txt', new Buffer([0, 10, 0 ,20])); +} +catch(exception) { + console.log('UTF-16BE without BOM validated'); +} + +var fileEncodeType = fileEncoding.detectFileEncoding('utf-16le.txt', new Buffer([20, 0, 10, 0])); +if(fileEncodeType[0] === 'utf-16le' && !fileEncodeType[1]) { + console.log('UTF-16LE without BOM validated'); +} + +try { + fileEncoding.detectFileEncoding('utfShort.txt', new Buffer([20, 0])); +} +catch(exception) { + console.log('Short File Buffer Error'); +} + +try { + fileEncoding.detectFileEncoding('utfUnknown.txt', new Buffer([0, 10, 20, 30])); +} +catch(exception) { + console.log('Unknown encoding type') +} \ No newline at end of file diff --git a/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsAllInput.ts b/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsAllInput.ts index 5402694f8b0b..fd6fa3363a30 100644 --- a/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsAllInput.ts +++ b/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsAllInput.ts @@ -150,11 +150,8 @@ tr.registerMock('webdeployment-common/azurerestutility.js', { } return config; - } -}); - -tr.registerMock('./azurerestutility.js', { - updateDeploymentStatus: function(publishingProfile, isDeploymentSuccess ) { + }, + updateDeploymentStatus: function(publishingProfile, isDeploymentSuccess ) { if(isDeploymentSuccess) { console.log('Updated history to kudu'); } @@ -163,6 +160,7 @@ tr.registerMock('./azurerestutility.js', { } var webAppPublishKuduUrl = publishingProfile.publishUrl; var requestDetails = kuduDeploymentLog.getUpdateHistoryRequest(webAppPublishKuduUrl, isDeploymentSuccess); + requestDetails["requestBody"].author = 'author'; console.log("kudu log requestBody is:" + JSON.stringify(requestDetails["requestBody"])); } }); diff --git a/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsDefault.ts b/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsDefault.ts index 0d89e6e081a1..737ac10c3881 100644 --- a/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsDefault.ts +++ b/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsDefault.ts @@ -143,10 +143,7 @@ tr.registerMock('webdeployment-common/azurerestutility.js', { } return config; - } -}); - -tr.registerMock('./azurerestutility.js', { + }, updateDeploymentStatus: function(publishingProfile, isDeploymentSuccess ) { if(isDeploymentSuccess) { console.log('Updated history to kudu'); diff --git a/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsFailDefault.ts b/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsFailDefault.ts index 69f2f442c540..e94b9e3a5058 100644 --- a/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsFailDefault.ts +++ b/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsFailDefault.ts @@ -130,10 +130,7 @@ tr.registerMock('webdeployment-common/azurerestutility.js', { } return config; - } -}); - -tr.registerMock('./azurerestutility.js', { + }, updateDeploymentStatus: function(publishingProfile, isDeploymentSuccess ) { if(isDeploymentSuccess) { console.log('Updated history to kudu'); @@ -148,6 +145,5 @@ tr.registerMock('./azurerestutility.js', { } }); - tr.setAnswers(a); tr.run(); \ No newline at end of file diff --git a/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsFailSetParamFile.ts b/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsFailSetParamFile.ts index b743ca93facc..651fdd9b43b0 100644 --- a/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsFailSetParamFile.ts +++ b/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsFailSetParamFile.ts @@ -132,10 +132,7 @@ tr.registerMock('webdeployment-common/azurerestutility.js', { } return config; - } -}); - -tr.registerMock('./azurerestutility.js', { + }, updateDeploymentStatus: function(publishingProfile, isDeploymentSuccess ) { if(isDeploymentSuccess) { console.log('Updated history to kudu'); @@ -145,6 +142,7 @@ tr.registerMock('./azurerestutility.js', { } var webAppPublishKuduUrl = publishingProfile.publishUrl; var requestDetails = kuduDeploymentLog.getUpdateHistoryRequest(webAppPublishKuduUrl, isDeploymentSuccess); + requestDetails["requestBody"].author = 'author'; console.log("kudu log requestBody is:" + JSON.stringify(requestDetails["requestBody"])); } }); diff --git a/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsFolderPkg.ts b/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsFolderPkg.ts index f4c8f0a7d638..9aae2cf5c690 100644 --- a/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsFolderPkg.ts +++ b/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsFolderPkg.ts @@ -144,10 +144,7 @@ tr.registerMock('webdeployment-common/azurerestutility.js', { } return config; - } -}); - -tr.registerMock('./azurerestutility.js', { + }, updateDeploymentStatus: function(publishingProfile, isDeploymentSuccess ) { if(isDeploymentSuccess) { console.log('Updated history to kudu'); @@ -157,6 +154,7 @@ tr.registerMock('./azurerestutility.js', { } var webAppPublishKuduUrl = publishingProfile.publishUrl; var requestDetails = kuduDeploymentLog.getUpdateHistoryRequest(webAppPublishKuduUrl, isDeploymentSuccess); + requestDetails["requestBody"].author = 'author'; console.log("kudu log requestBody is:" + JSON.stringify(requestDetails["requestBody"])); } }); diff --git a/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsManyPackage.ts b/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsManyPackage.ts index 0a2834a15e91..dc9b46e1d4b6 100644 --- a/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsManyPackage.ts +++ b/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsManyPackage.ts @@ -145,10 +145,7 @@ tr.registerMock('webdeployment-common/azurerestutility.js', { } return config; -} -}); - -tr.registerMock('./azurerestutility.js', { + }, updateDeploymentStatus: function(publishingProfile, isDeploymentSuccess ) { if(isDeploymentSuccess) { console.log('Updated history to kudu'); diff --git a/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsNoPackage.ts b/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsNoPackage.ts index ccc807733bda..c124b6fbe333 100644 --- a/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsNoPackage.ts +++ b/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsNoPackage.ts @@ -139,11 +139,7 @@ tr.registerMock('webdeployment-common/azurerestutility.js', { } return config; -} -}); - - -tr.registerMock('./azurerestutility.js', { + }, updateDeploymentStatus: function(publishingProfile, isDeploymentSuccess ) { if(isDeploymentSuccess) { console.log('Updated history to kudu'); diff --git a/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsParamFileinPkg.ts b/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsParamFileinPkg.ts index 5893548cb5e7..62ae8698d2ce 100644 --- a/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsParamFileinPkg.ts +++ b/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsParamFileinPkg.ts @@ -137,10 +137,7 @@ tr.registerMock('webdeployment-common/azurerestutility.js', { } return config; -} -}); - -tr.registerMock('./azurerestutility.js', { + }, updateDeploymentStatus: function(publishingProfile, isDeploymentSuccess ) { if(isDeploymentSuccess) { console.log('Updated history to kudu'); diff --git a/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsSpecificSlot.ts b/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsSpecificSlot.ts index ede56297c0c8..24d8266909c1 100644 --- a/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsSpecificSlot.ts +++ b/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsSpecificSlot.ts @@ -148,10 +148,7 @@ tr.registerMock('webdeployment-common/azurerestutility.js', { } return config; -} -}); - -tr.registerMock('./azurerestutility.js', { + }, updateDeploymentStatus: function(publishingProfile, isDeploymentSuccess ) { if(isDeploymentSuccess) { console.log('Updated history to kudu'); diff --git a/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsXdtTransformation.ts b/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsXdtTransformation.ts index b0c01ef029c2..93f71d2aafeb 100644 --- a/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsXdtTransformation.ts +++ b/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsXdtTransformation.ts @@ -150,10 +150,7 @@ tr.registerMock('webdeployment-common/azurerestutility.js', { } return config; -} -}); - -tr.registerMock('./azurerestutility.js', { + }, updateDeploymentStatus: function(publishingProfile, isDeploymentSuccess ) { if(isDeploymentSuccess) { console.log('Updated history to kudu'); diff --git a/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsXdtTransformationFail.ts b/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsXdtTransformationFail.ts index e75548a814c5..e2f759f3b33b 100644 --- a/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsXdtTransformationFail.ts +++ b/Tasks/AzureRmWebAppDeployment/Tests/L0WindowsXdtTransformationFail.ts @@ -145,10 +145,7 @@ tr.registerMock('webdeployment-common/azurerestutility.js', { } return config; -} -}); - -tr.registerMock('./azurerestutility.js', { + }, updateDeploymentStatus: function(publishingProfile, isDeploymentSuccess ) { if(isDeploymentSuccess) { console.log('Updated history to kudu'); diff --git a/Tasks/AzureRmWebAppDeployment/Tests/L0XdtTransform.ts b/Tasks/AzureRmWebAppDeployment/Tests/L0XdtTransform.ts index c05cf463851c..8730810c2960 100644 --- a/Tasks/AzureRmWebAppDeployment/Tests/L0XdtTransform.ts +++ b/Tasks/AzureRmWebAppDeployment/Tests/L0XdtTransform.ts @@ -146,10 +146,7 @@ tr.registerMock('webdeployment-common/azurerestutility.js', { } return config; - } -}); - -tr.registerMock('./azurerestutility.js', { + }, updateDeploymentStatus: function(publishingProfile, isDeploymentSuccess ) { if(isDeploymentSuccess) { console.log('Updated history to kudu'); diff --git a/Tasks/AzureRmWebAppDeployment/Tests/L0XmlVarSub.ts b/Tasks/AzureRmWebAppDeployment/Tests/L0XmlVarSub.ts index 9ae211efbe6c..07b8b4e8079c 100644 --- a/Tasks/AzureRmWebAppDeployment/Tests/L0XmlVarSub.ts +++ b/Tasks/AzureRmWebAppDeployment/Tests/L0XmlVarSub.ts @@ -159,10 +159,7 @@ tr.registerMock('webdeployment-common/azurerestutility.js', { } return config; - } -}); - -tr.registerMock('./azurerestutility.js', { + }, updateDeploymentStatus: function(publishingProfile, isDeploymentSuccess ) { if(isDeploymentSuccess) { console.log('Updated history to kudu'); diff --git a/Tasks/AzureRmWebAppDeployment/azurermwebappdeployment.ts b/Tasks/AzureRmWebAppDeployment/azurermwebappdeployment.ts index 3eec8872e5e4..170270572b4f 100644 --- a/Tasks/AzureRmWebAppDeployment/azurermwebappdeployment.ts +++ b/Tasks/AzureRmWebAppDeployment/azurermwebappdeployment.ts @@ -38,11 +38,18 @@ async function run() { var variableSubstitution: boolean = tl.getBoolInput('VariableSubstitution', false); var endPointAuthCreds = tl.getEndpointAuthorization(connectedServiceName, true); + var isDeploymentSuccess: boolean = true; + var deploymentErrorMessage: string; + var SPN = new Array(); SPN["servicePrincipalClientID"] = endPointAuthCreds.parameters["serviceprincipalid"]; SPN["servicePrincipalKey"] = endPointAuthCreds.parameters["serviceprincipalkey"]; SPN["tenantID"] = endPointAuthCreds.parameters["tenantid"]; SPN["subscriptionId"] = tl.getEndpointDataParameter(connectedServiceName, 'subscriptionid', true); + + var publishingProfile = await azureRESTUtility.getAzureRMWebAppPublishProfile(SPN, webAppName, resourceGroupName, deployToSlotFlag, slotName); + tl._writeLine(tl.loc('GotconnectiondetailsforazureRMWebApp0', webAppName)); + var availableWebPackages = utility.findfiles(webDeployPkg); if(availableWebPackages.length == 0) { throw new Error(tl.loc('Nopackagefoundwithspecifiedpattern')); @@ -55,9 +62,6 @@ async function run() { var isFolderBasedDeployment = utility.isInputPkgIsFolder(webDeployPkg); - var publishingProfile = await azureRESTUtility.getAzureRMWebAppPublishProfile(SPN, webAppName, resourceGroupName, deployToSlotFlag, slotName); - tl._writeLine(tl.loc('GotconnectiondetailsforazureRMWebApp0', webAppName)); - if(jsonVariableSubsFlag || (xmlTransformsAndVariableSubstitutions && (xmlTransformation || variableSubstitution))) { var folderPath = path.join(tl.getVariable('System.DefaultWorkingDirectory'), 'temp_web_package_folder'); if(isFolderBasedDeployment) { @@ -108,9 +112,23 @@ async function run() { tl.debug(tl.loc("Initiateddeploymentviakuduserviceforwebapppackage", webDeployPkg)); var azureWebAppDetails = await azureRESTUtility.getAzureRMWebAppConfigDetails(SPN, webAppName, resourceGroupName, deployToSlotFlag, slotName); await DeployUsingKuduDeploy(webDeployPkg, azureWebAppDetails, publishingProfile, virtualApplication, isFolderBasedDeployment, takeAppOfflineFlag); + } + } catch (error) { - tl.setResult(tl.TaskResult.Failed, error); + isDeploymentSuccess = false; + deploymentErrorMessage = error; + } + if(publishingProfile != null) { + try { + tl._writeLine(await azureRESTUtility.updateDeploymentStatus(publishingProfile, isDeploymentSuccess)); + } + catch(error) { + tl.warning(error); + } + } + if(!isDeploymentSuccess) { + tl.setResult(tl.TaskResult.Failed, deploymentErrorMessage); } } @@ -127,9 +145,6 @@ async function run() { */ async function DeployUsingKuduDeploy(webDeployPkg, azureWebAppDetails, publishingProfile, virtualApplication, isFolderBasedDeployment, takeAppOfflineFlag) { - var isDeploymentSuccess = true; - var deploymentError = null; - try { var virtualApplicationMappings = azureWebAppDetails.properties.virtualApplications; var webAppZipFile = webDeployPkg; @@ -147,19 +162,7 @@ async function DeployUsingKuduDeploy(webDeployPkg, azureWebAppDetails, publishin } catch(error) { tl.error(tl.loc('Failedtodeploywebsite')); - isDeploymentSuccess = false; - deploymentError = error; - } - - try { - tl._writeLine(await azureRESTUtility.updateDeploymentStatus(publishingProfile, isDeploymentSuccess)); - } - catch(error) { - tl.warning(error); - } - - if(!isDeploymentSuccess) { - throw Error(deploymentError); + throw Error(error); } } diff --git a/Tasks/AzureRmWebAppDeployment/kuduutility.ts b/Tasks/AzureRmWebAppDeployment/kuduutility.ts index ecf98869d5cf..9f3d4a03872b 100644 --- a/Tasks/AzureRmWebAppDeployment/kuduutility.ts +++ b/Tasks/AzureRmWebAppDeployment/kuduutility.ts @@ -4,8 +4,6 @@ import path = require("path"); import fs = require("fs"); import httpClient = require('vso-node-api/HttpClient'); var httpObj = new httpClient.HttpClient(tl.getVariable("AZURE_HTTP_USER_AGENT")); -var gulp = require('gulp'); -var zip = require('gulp-zip'); var zipUtility = require('webdeployment-common/ziputility.js'); export async function appOffineKuduService(publishUrl: string, physicalPath: string, headers, enableFeature: boolean) { diff --git a/Tasks/AzureRmWebAppDeployment/package.json b/Tasks/AzureRmWebAppDeployment/package.json index 8da9c1c0fd37..0f05112cf867 100644 --- a/Tasks/AzureRmWebAppDeployment/package.json +++ b/Tasks/AzureRmWebAppDeployment/package.json @@ -17,8 +17,7 @@ }, "homepage": "https://github.com/Microsoft/vsts-tasks#readme", "dependencies": { - - "q": "^1.4.1" + "q": "1.4.1" }, "devDependencies": { "mocha": "^3.1.0" diff --git a/Tasks/AzureRmWebAppDeployment/task.json b/Tasks/AzureRmWebAppDeployment/task.json index dbb404c584cb..91333657444b 100644 --- a/Tasks/AzureRmWebAppDeployment/task.json +++ b/Tasks/AzureRmWebAppDeployment/task.json @@ -13,7 +13,7 @@ "version": { "Major": 2, "Minor": 1, - "Patch": 5 + "Patch": 8 }, "minimumAgentVersion": "1.102.0", "groups": [ @@ -26,11 +26,6 @@ "name": "output", "displayName": "Output", "isExpanded": true - }, - { - "name": "FileTransformsAndVariableSubstitution", - "displayName": "File Transforms and Variable Substitutions", - "isExpanded": false } ], "inputs": [ @@ -167,26 +162,7 @@ "required": false, "groupName": "AdditionalDeploymentOptions", "helpMarkDown": "Select the option to take the AzureRM Web App offline by placing an app_offline.htm file in the root directory of the Web App before the sync operation begins. The file will be removed after the sync operation completes successfully." - }, - { - "name": "XmlTransformsAndVariableSubstitutions", - "type": "boolean", - "label": "XML Transforms & Variable Substitutions", - "required": false, - "defaultValue": false, - "groupName": "FileTransformsAndVariableSubstitution", - "helpMarkDown": "" - }, - { - "name": "VariableSubstitution", - "type": "boolean", - "label": "Variable Substitution", - "required": false, - "defaultValue": false, - "groupName": "FileTransformsAndVariableSubstitution", - "visibleRule": "XmlTransformsAndVariableSubstitutions == true", - "helpMarkDown": "Variables defined in the Build or Release Definition will be automatically substituted in the appSettings, applicationSettings, and connectionStrings section of the config files. If same variables are defined in the Release Definition and in the Environment, then the Environment variables will supersede the Release Definition variables. Variable Substitution is run after Config Transforms." - } + } ], "dataSourceBindings": [ { @@ -267,6 +243,7 @@ "PublishusingwebdeployoptionsaresupportedonlywhenusingWindowsagent": "Publish using webdeploy options are supported only when using Windows agent", "WebAppDoesntExist": "Webapp '%s' doesn't exist. Webapp should exist before deployment.", "EncodeNotSupported": "Detected file encoding of the file %s as %s. Variable substitution and Transformation is not supported with file encoding %s. Supported encodings are UTF-8 and UTF-16 LE.", - "UnknownFileEncodeError": "Unable to detect encoding of the file %s. Supported encodings are UTF-8 and UTF-16 LE." + "UnknownFileEncodeError": "Unable to detect encoding of the file %s (typeCode: %s). Supported encodings are UTF-8 and UTF-16 LE.", + "ShortFileBufferError": "File buffer is too short to detect encoding type : %s" } } diff --git a/Tasks/AzureRmWebAppDeployment/task.loc.json b/Tasks/AzureRmWebAppDeployment/task.loc.json index 444d6db99bf8..763462956a6c 100644 --- a/Tasks/AzureRmWebAppDeployment/task.loc.json +++ b/Tasks/AzureRmWebAppDeployment/task.loc.json @@ -13,7 +13,7 @@ "version": { "Major": 2, "Minor": 1, - "Patch": 5 + "Patch": 8 }, "minimumAgentVersion": "1.102.0", "groups": [ @@ -26,11 +26,6 @@ "name": "output", "displayName": "ms-resource:loc.group.displayName.output", "isExpanded": true - }, - { - "name": "FileTransformsAndVariableSubstitution", - "displayName": "ms-resource:loc.group.displayName.FileTransformsAndVariableSubstitution", - "isExpanded": false } ], "inputs": [ @@ -167,25 +162,6 @@ "required": false, "groupName": "AdditionalDeploymentOptions", "helpMarkDown": "ms-resource:loc.input.help.TakeAppOfflineFlag" - }, - { - "name": "XmlTransformsAndVariableSubstitutions", - "type": "boolean", - "label": "ms-resource:loc.input.label.XmlTransformsAndVariableSubstitutions", - "required": false, - "defaultValue": false, - "groupName": "FileTransformsAndVariableSubstitution", - "helpMarkDown": "" - }, - { - "name": "VariableSubstitution", - "type": "boolean", - "label": "ms-resource:loc.input.label.VariableSubstitution", - "required": false, - "defaultValue": false, - "groupName": "FileTransformsAndVariableSubstitution", - "visibleRule": "XmlTransformsAndVariableSubstitutions == true", - "helpMarkDown": "ms-resource:loc.input.help.VariableSubstitution" } ], "dataSourceBindings": [ @@ -267,6 +243,7 @@ "PublishusingwebdeployoptionsaresupportedonlywhenusingWindowsagent": "ms-resource:loc.messages.PublishusingwebdeployoptionsaresupportedonlywhenusingWindowsagent", "WebAppDoesntExist": "ms-resource:loc.messages.WebAppDoesntExist", "EncodeNotSupported": "ms-resource:loc.messages.EncodeNotSupported", - "UnknownFileEncodeError": "ms-resource:loc.messages.UnknownFileEncodeError" + "UnknownFileEncodeError": "ms-resource:loc.messages.UnknownFileEncodeError", + "ShortFileBufferError": "ms-resource:loc.messages.ShortFileBufferError" } } \ No newline at end of file diff --git a/Tasks/AzureWebPowerShellDeployment/Publish-AzureWebDeployment.ps1 b/Tasks/AzureWebPowerShellDeployment/Publish-AzureWebDeployment.ps1 deleted file mode 100644 index aa37d4fa8ef3..000000000000 --- a/Tasks/AzureWebPowerShellDeployment/Publish-AzureWebDeployment.ps1 +++ /dev/null @@ -1,207 +0,0 @@ -Trace-VstsEnteringInvocation $MyInvocation -Import-VstsLocStrings "$PSScriptRoot\Task.json" - -Write-Warning "'Azure App Service: Classic' task will be deprecated soon. 'Azure App Service Deploy' task will replace 'Azure App Service: Classic' task and the recommendation is to migrate your Build or Release process to use the 'Azure App Service Deploy' task. Refer https://go.microsoft.com/fwlink/?LinkID=613750 for more details." - -function Get-SingleFile($files, $pattern) -{ - if ($files -is [system.array]) - { - throw (Get-VstsLocString -Key "Foundmorethanonefiletodeploywithsearchpattern0Therecanbeonlyone" -ArgumentList $pattern) - } - else - { - if (!$files) - { - throw (Get-VstsLocString -Key "Nofileswerefoundtodeploywithsearchpattern0" -ArgumentList $pattern) - } - return $files - } -} - -try{ - - $WebSiteName = Get-VstsInput -Name WebSiteName -Require - $WebSiteLocation = Get-VstsInput -Name WebSiteLocation - $Package = Get-VstsInput -Name Package -Require - $Slot = Get-VstsInput -Name Slot - $DoNotDelete = Get-VstsInput -Name DoNotDelete -AsBool - $AdditionalArguments = Get-VstsInput -Name AdditionalArguments - - # Initialize Azure. - Import-Module $PSScriptRoot\ps_modules\VstsAzureHelpers_ - Initialize-Azure - - # adding System.Web explicitly, since we use http utility - Add-Type -AssemblyName System.Web - - Write-Host "Finding $Package" - $packageFile = Find-VstsFiles -LegacyPattern $Package - Write-Host "packageFile= $packageFile" - - #Ensure that at most a single package (.zip) file is found - $packageFile = Get-SingleFile $packageFile $Package - $azureWebSiteError = $null - - #If we're provided a WebSiteLocation, check for it and create it if necessary - if($WebSiteLocation) - { - #using production slot for website if website name provided doesnot contain any slot - if ([String]::IsNullOrEmpty($Slot)) - { - if($WebSiteName -notlike '*(*)*') - { - $Slot = 'Production' - } - } - - $extraParameters = @{ } - if ($Slot) { $extraParameters['Slot'] = $Slot } - - Write-Host "##[command]Get-AzureWebSite -Name $WebSiteName -ErrorAction SilentlyContinue -ErrorVariable azureWebSiteError $(if ($Slot) { "-Slot $Slot" })" - $azureWebSite = Get-AzureWebSite -Name $WebSiteName -ErrorAction SilentlyContinue -ErrorVariable azureWebSiteError @extraParameters - if($azureWebSiteError){ - $azureWebSiteError | ForEach-Object { Write-Verbose $_.Exception.ToString() } - } - - if($azureWebSite) - { - Write-Host "WebSite '$($azureWebSite.Name)' found." - } - else - { - Write-Host "WebSite '$WebSiteName' not found. Creating it now." - - if ($Slot) - { - Write-Host "##[command]New-AzureWebSite -Name $WebSiteName -Location $WebSiteLocation -Slot $Slot" - $azureWebSite = New-AzureWebSite -Name $WebSiteName -Location $WebSiteLocation -Slot $Slot - } - else - { - Write-Host "##[command]New-AzureWebSite -Name $WebSiteName -Location $WebSiteLocation" - $azureWebSite = New-AzureWebSite -Name $WebSiteName -Location $WebSiteLocation - } - } - } - - #Deploy the package - $azureCommand = "Publish-AzureWebsiteProject" - - if($DoNotDelete) { - $AdditionalArguments = $AdditionalArguments + " -DoNotDelete" - } - - if ($Slot) - { - $azureCommandArguments = "-Name `"$WebSiteName`" -Package `"$packageFile`" -Slot `"$Slot`" $AdditionalArguments -ErrorVariable publishAzureWebsiteError -ErrorAction SilentlyContinue" - } - else - { - $azureCommandArguments = "-Name `"$WebSiteName`" -Package `"$packageFile`" $AdditionalArguments -ErrorVariable publishAzureWebSiteError -ErrorAction SilentlyContinue" - } - - $finalCommand = "$azureCommand $azureCommandArguments" - Write-Host "$finalCommand" - Invoke-Expression -Command $finalCommand - - #Update Deployment status - https://github.com/projectkudu/kudu/wiki/REST-API#deployment - - if($azureWebSite) { - $matchedWebSiteName = $azureWebSite.EnabledHostNames | Where-Object { $_ -like '*.scm*azurewebsites.net*' } | Select-Object -First 1 - if ($matchedWebSiteName) { - $status = 3 #failed - if(!$publishAzureWebsiteError) { - $status = 4 #succeeded - } - - $username = $azureWebSite.PublishingUsername - $securePwd = ConvertTo-SecureString $azureWebSite.PublishingPassword -AsPlainText -Force - $credential = New-Object System.Management.Automation.PSCredential ($username, $securePwd) - - $author = Get-VstsTaskVariable -Name "build.sourceVersionAuthor" - if(!$author) { - # fall back to build/release requestedfor - $author = Get-VstsTaskVariable -Name "build.requestedfor" - if(!$author) { - $author = Get-VstsTaskVariable -Name "release.requestedfor" - } - # At this point if this is still null, let's use agent name - if(!$author) { - $author = Get-VstsTaskVariable -Name "agent.name" - } - } - - # using buildId/releaseId to update deployment status - # using buildUrl/releaseUrl to update deployment message - $buildUrlTaskVar = Get-VstsTaskVariable -Name "build.buildUri" - $releaseUrlTaskVar = Get-VstsTaskVariable -Name "release.releaseUri" - $buildIdTaskVar = Get-VstsTaskVariable -Name "build.buildId" - $releaseIdTaskVar = Get-VstsTaskVariable -Name "release.releaseId" - if($releaseUrlTaskVar) { - $deploymentId = $releaseIdTaskVar - $message = Get-VstsLocString -Key "Updatingdeploymenthistoryfordeployment0" -ArgumentList $releaseUrlTaskVar - } - else - { - $deploymentId = $buildIdTaskVar - $message = Get-VstsLocString -Key "Updatingdeploymenthistoryfordeployment0" -ArgumentList $buildUrlTaskVar - } - - Write-Verbose "Using deploymentId as: '$deploymentId' to update deployment Status" - Write-Verbose "Using message as: '$message' to update deployment Status" - - if(!$deploymentId) { - #No point in proceeding further - Write-Warning (Get-VstsLocString -Key "CannotupdatedeploymentstatusuniquedeploymentIdcannotberetrieved") - Return - } - - $collectionUrl = Get-VstsTaskVariable -Name System.TeamFoundationCollectionUri -Require - $teamproject = Get-VstsTaskVariable -Name System.TeamProject -Require - $buildUrl = [string]::Format("{0}/{1}/_build#buildId={2}&_a=summary", $collectionUrl, $teamproject, $buildIdTaskVar) - - $body = ConvertTo-Json (New-Object -TypeName psobject -Property @{ - status = $status - message = $message - author = $author - deployer = 'VSTS' - details = $buildUrl - }) - - $userAgent = Get-VstsTaskVariable -Name AZURE_HTTP_USER_AGENT - - $url = [string]::Format("https://{0}/deployments/{1}",[System.Web.HttpUtility]::UrlEncode($matchedWebSiteName),[System.Web.HttpUtility]::UrlEncode($deploymentId)) - - Write-Verbose "##[command]Invoke-RestMethod $url -Credential $credential -Method PUT -Body $body -ContentType `"application/json`" -UserAgent `"$userAgent`"" - Write-Host (Get-VstsLocString -Key "Updatingdeploymentstatus") - try { - Invoke-RestMethod $url -Credential $credential -Method PUT -Body $body -ContentType "application/json" -UserAgent "$userAgent" - } - catch { - Write-Verbose $_.Exception.ToString() - $response = $_.Exception.Response - $responseStream = $response.GetResponseStream() - $streamReader = New-Object System.IO.StreamReader($responseStream) - $streamReader.BaseStream.Position = 0 - $streamReader.DiscardBufferedData() - $responseBody = $streamReader.ReadToEnd() - $streamReader.Close() - Write-Warning (Get-VstsLocString -Key "Cannotupdatedeploymentstatusfor01" -ArgumentList $WebSiteName, $responseBody) - } - } - else { - Write-Warning (Get-VstsLocString -Key "CannotupdatedeploymentstatusSCMendpointisnotenabledforthiswebsite") - } - } - else { - Write-Warning (Get-VstsLocString -Key "Cannotgetwebsitedeploymentstatusisnotupdated") - } - - -} finally { - if($publishAzureWebsiteError) { - throw (Get-VstsLocString -Key "FailedtodeployWebsiteError0" -ArgumentList $publishAzureWebsiteError) - } - Trace-VstsLeavingInvocation $MyInvocation -} diff --git a/Tasks/AzureWebPowerShellDeployment/Readme.md b/Tasks/AzureWebPowerShellDeployment/Readme.md deleted file mode 100644 index 56ac15a9ebd5..000000000000 --- a/Tasks/AzureWebPowerShellDeployment/Readme.md +++ /dev/null @@ -1,7 +0,0 @@ -## **Important Notice** -The "Azure App Service Deployment: Classic" task has been **deprecated and will be removed soon**. To update Azure App Services using Web Deploy / Kudu REST APIs, please use the [**Azure App Service Deployment: ARM** task](https://github.com/Microsoft/vsts-tasks/tree/master/Tasks/AzureRmWebAppDeployment). -We recommend you to migrate your Build or Release definitions to replace the deprecating task with the 'Azure App Service Deployment: ARM' task. - - - - diff --git a/Tasks/AzureWebPowerShellDeployment/Strings/resources.resjson/de-de/resources.resjson b/Tasks/AzureWebPowerShellDeployment/Strings/resources.resjson/de-de/resources.resjson deleted file mode 100644 index c484d5d8021f..000000000000 --- a/Tasks/AzureWebPowerShellDeployment/Strings/resources.resjson/de-de/resources.resjson +++ /dev/null @@ -1,27 +0,0 @@ -{ - "loc.friendlyName": "Azure Web App-Bereitstellung", - "loc.helpMarkDown": "[More Information](https://go.microsoft.com/fwlink/?LinkID=613750)", - "loc.description": "Ein Visual Studio-Webprojekt mithilfe von Web Deploy als Microsoft Azure Web App veröffentlichen", - "loc.instanceNameFormat": "Azure-Bereitstellung: $(WebSiteName)", - "loc.input.label.ConnectedServiceName": "Azure Subscription (Classic)", - "loc.input.help.ConnectedServiceName": "Azure Classic subscription to target for deployment.", - "loc.input.label.WebSiteLocation": "Web App-Ort", - "loc.input.help.WebSiteLocation": "Wählen Sie einen Speicherort für die Website aus.", - "loc.input.label.WebSiteName": "Web App-Name", - "loc.input.help.WebSiteName": "Wählen Sie den Webseitenamen ein, oder wählen Sie ihn in der Liste aus.
Hinweis: Nur die Websites, die dem App Service-Standardplan für die ausgewählte Region zugeordnet sind, werden aufgeführt.", - "loc.input.label.Slot": "Platz", - "loc.input.help.Slot": "Platz", - "loc.input.label.Package": "Web Deploy-Paket", - "loc.input.help.Package": "Pfad des Visual Studio Web Deploy-Pakets unter dem Artefaktstandardverzeichnis.", - "loc.input.label.doNotDelete": "Kennzeichen \"DoNotDelete\" festlegen", - "loc.input.help.doNotDelete": "Durch Aktivieren dieser Option werden zusätzliche Dateien im Webbereitstellungspaket beim Veröffentlichen der Website beibehalten.", - "loc.input.label.AdditionalArguments": "Zusätzliche Argumente", - "loc.messages.Cannotgetwebsitedeploymentstatusisnotupdated": "Cannot get website, deployment status is not updated", - "loc.messages.CannotupdatedeploymentstatusSCMendpointisnotenabledforthiswebsite": "Cannot update deployment status, SCM endpoint is not enabled for this website", - "loc.messages.Cannotupdatedeploymentstatusfor01": "Cannot update deployment status for {0} - {1}", - "loc.messages.Updatingdeploymentstatus": "Updating deployment status", - "loc.messages.CannotupdatedeploymentstatusuniquedeploymentIdcannotberetrieved": "Cannot update deployment status, unique deploymentId cannot be retrieved", - "loc.messages.Updatingdeploymenthistoryfordeployment0": "Updating deployment history for deployment {0}", - "loc.messages.Nofileswerefoundtodeploywithsearchpattern0": "No files were found to deploy with search pattern {0}", - "loc.messages.Foundmorethanonefiletodeploywithsearchpattern0Therecanbeonlyone": "Found more than one file to deploy with search pattern {0}. There can be only one." -} \ No newline at end of file diff --git a/Tasks/AzureWebPowerShellDeployment/Strings/resources.resjson/en-US/resources.resjson b/Tasks/AzureWebPowerShellDeployment/Strings/resources.resjson/en-US/resources.resjson deleted file mode 100644 index 2f87acce26da..000000000000 --- a/Tasks/AzureWebPowerShellDeployment/Strings/resources.resjson/en-US/resources.resjson +++ /dev/null @@ -1,28 +0,0 @@ -{ - "loc.friendlyName": "Azure App Service: Classic (Deprecated)", - "loc.helpMarkDown": "More Information : “Azure App Service: Classic” Task will be deprecated. We recommend migrating your definition to use “Azure App Service Deploy” Task instead. For more information please refer [this](https://go.microsoft.com/fwlink/?LinkID=613750).", - "loc.description": "Create or update Azure App Service using Azure PowerShell", - "loc.instanceNameFormat": "Azure Deployment: $(WebSiteName)", - "loc.input.label.ConnectedServiceName": "Azure Subscription (Classic)", - "loc.input.help.ConnectedServiceName": "Azure Classic subscription to target for deployment.", - "loc.input.label.WebSiteLocation": "Web App Location", - "loc.input.help.WebSiteLocation": "Select a location for website.", - "loc.input.label.WebSiteName": "Web App Name", - "loc.input.help.WebSiteName": "Enter the website name or Select from the list.
Note: Only the websites associated with Default App Service plan for the selected region are listed.", - "loc.input.label.Slot": "Slot", - "loc.input.help.Slot": "Slot", - "loc.input.label.Package": "Web Deploy Package", - "loc.input.help.Package": "Path to the Visual Studio Web Deploy package under the default artifact directory.", - "loc.input.label.doNotDelete": "Set DoNotDelete flag", - "loc.input.help.doNotDelete": "By enabling this, additional files in web deployment package are preserved while publishing website.", - "loc.input.label.AdditionalArguments": "Additional Arguments", - "loc.messages.Cannotgetwebsitedeploymentstatusisnotupdated": "Cannot get website, deployment status is not updated", - "loc.messages.CannotupdatedeploymentstatusSCMendpointisnotenabledforthiswebsite": "Cannot update deployment status, SCM endpoint is not enabled for this website", - "loc.messages.Cannotupdatedeploymentstatusfor01": "Cannot update deployment status for {0} - {1}", - "loc.messages.Updatingdeploymentstatus": "Updating deployment status", - "loc.messages.CannotupdatedeploymentstatusuniquedeploymentIdcannotberetrieved": "Cannot update deployment status, unique deploymentId cannot be retrieved", - "loc.messages.Updatingdeploymenthistoryfordeployment0": "Updating deployment history for deployment {0}", - "loc.messages.Nofileswerefoundtodeploywithsearchpattern0": "No files were found to deploy with search pattern {0}", - "loc.messages.Foundmorethanonefiletodeploywithsearchpattern0Therecanbeonlyone": "Found more than one file to deploy with search pattern {0}. There can be only one.", - "loc.messages.FailedtodeployWebsiteError0": "Failed to deploy Website. Error : {0}" -} \ No newline at end of file diff --git a/Tasks/AzureWebPowerShellDeployment/Strings/resources.resjson/es-es/resources.resjson b/Tasks/AzureWebPowerShellDeployment/Strings/resources.resjson/es-es/resources.resjson deleted file mode 100644 index 00457ff1e52a..000000000000 --- a/Tasks/AzureWebPowerShellDeployment/Strings/resources.resjson/es-es/resources.resjson +++ /dev/null @@ -1,27 +0,0 @@ -{ - "loc.friendlyName": "Implementación de aplicaciones web de Azure", - "loc.helpMarkDown": "[More Information](https://go.microsoft.com/fwlink/?LinkID=613750)", - "loc.description": "Publicar un proyecto web de Visual Studio en una aplicación web de Microsoft Azure con Web Deploy", - "loc.instanceNameFormat": "Implementación de Azure: $(WebSiteName)", - "loc.input.label.ConnectedServiceName": "Azure Subscription (Classic)", - "loc.input.help.ConnectedServiceName": "Azure Classic subscription to target for deployment.", - "loc.input.label.WebSiteLocation": "Ubicación de la aplicación web", - "loc.input.help.WebSiteLocation": "Seleccione una ubicación para el sitio web.", - "loc.input.label.WebSiteName": "Nombre de la aplicación web", - "loc.input.help.WebSiteName": "Escriba el nombre del sitio web o selecciónelo de la lista.
Nota: Solo se muestran los sitios web asociados al plan del Servicio de aplicaciones predeterminado de la región seleccionada.", - "loc.input.label.Slot": "Ranura", - "loc.input.help.Slot": "Ranura", - "loc.input.label.Package": "Paquete de Web Deploy", - "loc.input.help.Package": "Ruta de acceso al paquete de Web Deploy de Visual Studio en el directorio de artefacto predeterminado.", - "loc.input.label.doNotDelete": "Establecer el indicador DoNotDelete", - "loc.input.help.doNotDelete": "Al habilitar esta opción, se conservan los archivos adicionales del paquete de implementación web al tiempo que se publica el sitio web.", - "loc.input.label.AdditionalArguments": "Argumentos adicionales", - "loc.messages.Cannotgetwebsitedeploymentstatusisnotupdated": "Cannot get website, deployment status is not updated", - "loc.messages.CannotupdatedeploymentstatusSCMendpointisnotenabledforthiswebsite": "Cannot update deployment status, SCM endpoint is not enabled for this website", - "loc.messages.Cannotupdatedeploymentstatusfor01": "Cannot update deployment status for {0} - {1}", - "loc.messages.Updatingdeploymentstatus": "Updating deployment status", - "loc.messages.CannotupdatedeploymentstatusuniquedeploymentIdcannotberetrieved": "Cannot update deployment status, unique deploymentId cannot be retrieved", - "loc.messages.Updatingdeploymenthistoryfordeployment0": "Updating deployment history for deployment {0}", - "loc.messages.Nofileswerefoundtodeploywithsearchpattern0": "No files were found to deploy with search pattern {0}", - "loc.messages.Foundmorethanonefiletodeploywithsearchpattern0Therecanbeonlyone": "Found more than one file to deploy with search pattern {0}. There can be only one." -} \ No newline at end of file diff --git a/Tasks/AzureWebPowerShellDeployment/Strings/resources.resjson/fr-fr/resources.resjson b/Tasks/AzureWebPowerShellDeployment/Strings/resources.resjson/fr-fr/resources.resjson deleted file mode 100644 index 63103da406e8..000000000000 --- a/Tasks/AzureWebPowerShellDeployment/Strings/resources.resjson/fr-fr/resources.resjson +++ /dev/null @@ -1,27 +0,0 @@ -{ - "loc.friendlyName": "Déploiement d'application web Azure", - "loc.helpMarkDown": "[More Information](https://go.microsoft.com/fwlink/?LinkID=613750)", - "loc.description": "Publier un projet web Visual Studio dans une application web Microsoft Azure à l'aide de Web Deploy", - "loc.instanceNameFormat": "Déploiement Azure : $(WebSiteName)", - "loc.input.label.ConnectedServiceName": "Azure Subscription (Classic)", - "loc.input.help.ConnectedServiceName": "Azure Classic subscription to target for deployment.", - "loc.input.label.WebSiteLocation": "Emplacement de l'application web", - "loc.input.help.WebSiteLocation": "Sélectionnez un emplacement pour le site web.", - "loc.input.label.WebSiteName": "Nom de l'application web", - "loc.input.help.WebSiteName": "Entrez le nom du site web ou sélectionnez-le dans la liste.
Remarque : Seuls les sites web associés au plan App Service par défaut pour la région sélectionnée sont répertoriés.", - "loc.input.label.Slot": "Emplacement", - "loc.input.help.Slot": "Emplacement", - "loc.input.label.Package": "Package Web Deploy", - "loc.input.help.Package": "Chemin d'accès au package Web Deploy de Visual Studio dans le répertoire de l'artefact par défaut.", - "loc.input.label.doNotDelete": "Définir l'indicateur DoNotDelete", - "loc.input.help.doNotDelete": "Une fois cette option activée, les fichiers supplémentaires du package de déploiement web sont conservés durant la publication du site web.", - "loc.input.label.AdditionalArguments": "Arguments supplémentaires", - "loc.messages.Cannotgetwebsitedeploymentstatusisnotupdated": "Cannot get website, deployment status is not updated", - "loc.messages.CannotupdatedeploymentstatusSCMendpointisnotenabledforthiswebsite": "Cannot update deployment status, SCM endpoint is not enabled for this website", - "loc.messages.Cannotupdatedeploymentstatusfor01": "Cannot update deployment status for {0} - {1}", - "loc.messages.Updatingdeploymentstatus": "Updating deployment status", - "loc.messages.CannotupdatedeploymentstatusuniquedeploymentIdcannotberetrieved": "Cannot update deployment status, unique deploymentId cannot be retrieved", - "loc.messages.Updatingdeploymenthistoryfordeployment0": "Updating deployment history for deployment {0}", - "loc.messages.Nofileswerefoundtodeploywithsearchpattern0": "No files were found to deploy with search pattern {0}", - "loc.messages.Foundmorethanonefiletodeploywithsearchpattern0Therecanbeonlyone": "Found more than one file to deploy with search pattern {0}. There can be only one." -} \ No newline at end of file diff --git a/Tasks/AzureWebPowerShellDeployment/Strings/resources.resjson/it-IT/resources.resjson b/Tasks/AzureWebPowerShellDeployment/Strings/resources.resjson/it-IT/resources.resjson deleted file mode 100644 index 44514b6a9d69..000000000000 --- a/Tasks/AzureWebPowerShellDeployment/Strings/resources.resjson/it-IT/resources.resjson +++ /dev/null @@ -1,27 +0,0 @@ -{ - "loc.friendlyName": "Distribuzione app Web di Azure", - "loc.helpMarkDown": "[More Information](https://go.microsoft.com/fwlink/?LinkID=613750)", - "loc.description": "Consente di pubblicare un progetto Web di Visual Studio in un'app Web di Microsoft Azure con Distribuzione Web", - "loc.instanceNameFormat": "Distribuzione Azure: $(WebSiteName)", - "loc.input.label.ConnectedServiceName": "Azure Subscription (Classic)", - "loc.input.help.ConnectedServiceName": "Azure Classic subscription to target for deployment.", - "loc.input.label.WebSiteLocation": "Percorso app Web", - "loc.input.help.WebSiteLocation": "Selezionare una località per il sito Web.", - "loc.input.label.WebSiteName": "Nome app Web", - "loc.input.help.WebSiteName": "Immettere il nome del sito Web o selezionarlo dall'elenco.
Nota: sono elencati solo i siti Web associati al piano del servizio app predefinito per l'area geografica selezionata.", - "loc.input.label.Slot": "Slot", - "loc.input.help.Slot": "Slot", - "loc.input.label.Package": "Pacchetto Distribuzione Web", - "loc.input.help.Package": "Percorso del pacchetto Distribuzione Web di Visual Studio nella directory di artefatti predefiniti.", - "loc.input.label.doNotDelete": "Imposta flag DoNotDelete", - "loc.input.help.doNotDelete": "Se si abilita questa opzione, i file aggiuntivi presenti nel pacchetto di distribuzione Web verranno mantenuti durante la pubblicazione del sito Web.", - "loc.input.label.AdditionalArguments": "Argomenti aggiuntivi", - "loc.messages.Cannotgetwebsitedeploymentstatusisnotupdated": "Cannot get website, deployment status is not updated", - "loc.messages.CannotupdatedeploymentstatusSCMendpointisnotenabledforthiswebsite": "Cannot update deployment status, SCM endpoint is not enabled for this website", - "loc.messages.Cannotupdatedeploymentstatusfor01": "Cannot update deployment status for {0} - {1}", - "loc.messages.Updatingdeploymentstatus": "Updating deployment status", - "loc.messages.CannotupdatedeploymentstatusuniquedeploymentIdcannotberetrieved": "Cannot update deployment status, unique deploymentId cannot be retrieved", - "loc.messages.Updatingdeploymenthistoryfordeployment0": "Updating deployment history for deployment {0}", - "loc.messages.Nofileswerefoundtodeploywithsearchpattern0": "No files were found to deploy with search pattern {0}", - "loc.messages.Foundmorethanonefiletodeploywithsearchpattern0Therecanbeonlyone": "Found more than one file to deploy with search pattern {0}. There can be only one." -} \ No newline at end of file diff --git a/Tasks/AzureWebPowerShellDeployment/Strings/resources.resjson/ja-jp/resources.resjson b/Tasks/AzureWebPowerShellDeployment/Strings/resources.resjson/ja-jp/resources.resjson deleted file mode 100644 index e1a42cba6313..000000000000 --- a/Tasks/AzureWebPowerShellDeployment/Strings/resources.resjson/ja-jp/resources.resjson +++ /dev/null @@ -1,27 +0,0 @@ -{ - "loc.friendlyName": "Azure Web アプリの配置", - "loc.helpMarkDown": "[More Information](https://go.microsoft.com/fwlink/?LinkID=613750)", - "loc.description": "Web 配置を使用した Microsoft Azure Web アプリへの Visual Studio Web プロジェクトの発行", - "loc.instanceNameFormat": "Azure 配置: $(WebSiteName)", - "loc.input.label.ConnectedServiceName": "Azure Subscription (Classic)", - "loc.input.help.ConnectedServiceName": "Azure Classic subscription to target for deployment.", - "loc.input.label.WebSiteLocation": "Web アプリの場所", - "loc.input.help.WebSiteLocation": "Web サイトの場所を選びます。", - "loc.input.label.WebSiteName": "Web アプリの名前", - "loc.input.help.WebSiteName": "Web サイト名を入力するか、一覧から選びます。
注: 選んだ地域の既定の App Service プランに関連付けられている Web サイトのみが一覧表示されます。", - "loc.input.label.Slot": "スロット", - "loc.input.help.Slot": "スロット", - "loc.input.label.Package": "Web 配置パッケージ", - "loc.input.help.Package": "成果物の既定のディレクトリにある Visual Studio Web 配置パッケージへのパス。", - "loc.input.label.doNotDelete": "DoNotDelete フラグの設定", - "loc.input.help.doNotDelete": "これを有効にすると、Web 配置のパッケージ内の追加ファイルが Web サイトの発行中に保持されます。", - "loc.input.label.AdditionalArguments": "追加引数", - "loc.messages.Cannotgetwebsitedeploymentstatusisnotupdated": "Cannot get website, deployment status is not updated", - "loc.messages.CannotupdatedeploymentstatusSCMendpointisnotenabledforthiswebsite": "Cannot update deployment status, SCM endpoint is not enabled for this website", - "loc.messages.Cannotupdatedeploymentstatusfor01": "Cannot update deployment status for {0} - {1}", - "loc.messages.Updatingdeploymentstatus": "Updating deployment status", - "loc.messages.CannotupdatedeploymentstatusuniquedeploymentIdcannotberetrieved": "Cannot update deployment status, unique deploymentId cannot be retrieved", - "loc.messages.Updatingdeploymenthistoryfordeployment0": "Updating deployment history for deployment {0}", - "loc.messages.Nofileswerefoundtodeploywithsearchpattern0": "No files were found to deploy with search pattern {0}", - "loc.messages.Foundmorethanonefiletodeploywithsearchpattern0Therecanbeonlyone": "Found more than one file to deploy with search pattern {0}. There can be only one." -} \ No newline at end of file diff --git a/Tasks/AzureWebPowerShellDeployment/Strings/resources.resjson/ko-KR/resources.resjson b/Tasks/AzureWebPowerShellDeployment/Strings/resources.resjson/ko-KR/resources.resjson deleted file mode 100644 index 5d56ad16a378..000000000000 --- a/Tasks/AzureWebPowerShellDeployment/Strings/resources.resjson/ko-KR/resources.resjson +++ /dev/null @@ -1,27 +0,0 @@ -{ - "loc.friendlyName": "Azure 웹앱 배포", - "loc.helpMarkDown": "[More Information](https://go.microsoft.com/fwlink/?LinkID=613750)", - "loc.description": "웹 배포를 사용하여 Microsoft Azure 웹앱에 Visual Studio Web 프로젝트 게시", - "loc.instanceNameFormat": "Azure 배포: $(WebSiteName)", - "loc.input.label.ConnectedServiceName": "Azure Subscription (Classic)", - "loc.input.help.ConnectedServiceName": "Azure Classic subscription to target for deployment.", - "loc.input.label.WebSiteLocation": "웹앱 위치", - "loc.input.help.WebSiteLocation": "웹 사이트의 지역을 선택하세요.", - "loc.input.label.WebSiteName": "웹앱 이름", - "loc.input.help.WebSiteName": "웹 사이트 이름을 입력하거나 목록에서 선택하세요.
참고: 선택한 지역의 기본 앱 서비스 계획과 연결된 웹 사이트만 나열됩니다.", - "loc.input.label.Slot": "슬롯", - "loc.input.help.Slot": "슬롯", - "loc.input.label.Package": "웹 배포 패키지", - "loc.input.help.Package": "기본 아티팩트 디렉터리의 Visual Studio 웹 배포 패키지 경로입니다.", - "loc.input.label.doNotDelete": "DoNotDelete 플래그 설정", - "loc.input.help.doNotDelete": "이 기능을 사용하도록 설정하면 웹 사이트를 게시하는 동안 웹 배포 패키지의 추가 파일이 유지됩니다.", - "loc.input.label.AdditionalArguments": "추가 인수", - "loc.messages.Cannotgetwebsitedeploymentstatusisnotupdated": "Cannot get website, deployment status is not updated", - "loc.messages.CannotupdatedeploymentstatusSCMendpointisnotenabledforthiswebsite": "Cannot update deployment status, SCM endpoint is not enabled for this website", - "loc.messages.Cannotupdatedeploymentstatusfor01": "Cannot update deployment status for {0} - {1}", - "loc.messages.Updatingdeploymentstatus": "Updating deployment status", - "loc.messages.CannotupdatedeploymentstatusuniquedeploymentIdcannotberetrieved": "Cannot update deployment status, unique deploymentId cannot be retrieved", - "loc.messages.Updatingdeploymenthistoryfordeployment0": "Updating deployment history for deployment {0}", - "loc.messages.Nofileswerefoundtodeploywithsearchpattern0": "No files were found to deploy with search pattern {0}", - "loc.messages.Foundmorethanonefiletodeploywithsearchpattern0Therecanbeonlyone": "Found more than one file to deploy with search pattern {0}. There can be only one." -} \ No newline at end of file diff --git a/Tasks/AzureWebPowerShellDeployment/Strings/resources.resjson/ru-RU/resources.resjson b/Tasks/AzureWebPowerShellDeployment/Strings/resources.resjson/ru-RU/resources.resjson deleted file mode 100644 index 493ad4c445f7..000000000000 --- a/Tasks/AzureWebPowerShellDeployment/Strings/resources.resjson/ru-RU/resources.resjson +++ /dev/null @@ -1,27 +0,0 @@ -{ - "loc.friendlyName": "Развертывание веб-приложения Azure", - "loc.helpMarkDown": "[More Information](https://go.microsoft.com/fwlink/?LinkID=613750)", - "loc.description": "Публикация веб-проекта Visual Studio в веб-приложении Microsoft Azure с помощью веб-развертывания", - "loc.instanceNameFormat": "Развертывание Azure: $(WebSiteName)", - "loc.input.label.ConnectedServiceName": "Azure Subscription (Classic)", - "loc.input.help.ConnectedServiceName": "Azure Classic subscription to target for deployment.", - "loc.input.label.WebSiteLocation": "Расположение веб-приложения", - "loc.input.help.WebSiteLocation": "Выберите расположение для веб-сайта.", - "loc.input.label.WebSiteName": "Имя веб-приложения", - "loc.input.help.WebSiteName": "Введите имя веб-сайта или выберите его в списке.
Примечание. В списке приводятся только веб-сайты, связанные с планом службы приложений по умолчанию для выбранного региона.", - "loc.input.label.Slot": "Слот", - "loc.input.help.Slot": "Слот", - "loc.input.label.Package": "Пакет веб-развертывания", - "loc.input.help.Package": "Путь к пакету веб-развертывания Visual Studio в каталоге артефактов по умолчанию.", - "loc.input.label.doNotDelete": "Задать флаг DoNotDelete", - "loc.input.help.doNotDelete": "При включении этого параметра дополнительные файлы в пакете веб-развертывания сохраняются при публикации веб-сайта.", - "loc.input.label.AdditionalArguments": "Дополнительные аргументы", - "loc.messages.Cannotgetwebsitedeploymentstatusisnotupdated": "Cannot get website, deployment status is not updated", - "loc.messages.CannotupdatedeploymentstatusSCMendpointisnotenabledforthiswebsite": "Cannot update deployment status, SCM endpoint is not enabled for this website", - "loc.messages.Cannotupdatedeploymentstatusfor01": "Cannot update deployment status for {0} - {1}", - "loc.messages.Updatingdeploymentstatus": "Updating deployment status", - "loc.messages.CannotupdatedeploymentstatusuniquedeploymentIdcannotberetrieved": "Cannot update deployment status, unique deploymentId cannot be retrieved", - "loc.messages.Updatingdeploymenthistoryfordeployment0": "Updating deployment history for deployment {0}", - "loc.messages.Nofileswerefoundtodeploywithsearchpattern0": "No files were found to deploy with search pattern {0}", - "loc.messages.Foundmorethanonefiletodeploywithsearchpattern0Therecanbeonlyone": "Found more than one file to deploy with search pattern {0}. There can be only one." -} \ No newline at end of file diff --git a/Tasks/AzureWebPowerShellDeployment/Strings/resources.resjson/zh-CN/resources.resjson b/Tasks/AzureWebPowerShellDeployment/Strings/resources.resjson/zh-CN/resources.resjson deleted file mode 100644 index 63e5ebea7d17..000000000000 --- a/Tasks/AzureWebPowerShellDeployment/Strings/resources.resjson/zh-CN/resources.resjson +++ /dev/null @@ -1,27 +0,0 @@ -{ - "loc.friendlyName": "Azure Web 应用部署", - "loc.helpMarkDown": "[More Information](https://go.microsoft.com/fwlink/?LinkID=613750)", - "loc.description": "使用 Web 部署将 Visual Studio Web 项目发布到 Microsoft Azure Web 应用", - "loc.instanceNameFormat": "Azure 部署: $(WebSiteName)", - "loc.input.label.ConnectedServiceName": "Azure Subscription (Classic)", - "loc.input.help.ConnectedServiceName": "Azure Classic subscription to target for deployment.", - "loc.input.label.WebSiteLocation": "Web 应用位置", - "loc.input.help.WebSiteLocation": "选择网站的位置。", - "loc.input.label.WebSiteName": "Web 应用名称", - "loc.input.help.WebSiteName": "输入网站名称或从列表选择。
注意: 仅列出了与所选地区的默认应用服务计划相关的网站。", - "loc.input.label.Slot": "槽", - "loc.input.help.Slot": "槽", - "loc.input.label.Package": "Web 部署包", - "loc.input.help.Package": "默认项目目录下 Visual Studio Web 部署包的路径。", - "loc.input.label.doNotDelete": "设置 DoNotDelete 标记", - "loc.input.help.doNotDelete": "启用此项后,将在发布网站时保留 Web 部署包中的其他文件。", - "loc.input.label.AdditionalArguments": "其他参数", - "loc.messages.Cannotgetwebsitedeploymentstatusisnotupdated": "Cannot get website, deployment status is not updated", - "loc.messages.CannotupdatedeploymentstatusSCMendpointisnotenabledforthiswebsite": "Cannot update deployment status, SCM endpoint is not enabled for this website", - "loc.messages.Cannotupdatedeploymentstatusfor01": "Cannot update deployment status for {0} - {1}", - "loc.messages.Updatingdeploymentstatus": "Updating deployment status", - "loc.messages.CannotupdatedeploymentstatusuniquedeploymentIdcannotberetrieved": "Cannot update deployment status, unique deploymentId cannot be retrieved", - "loc.messages.Updatingdeploymenthistoryfordeployment0": "Updating deployment history for deployment {0}", - "loc.messages.Nofileswerefoundtodeploywithsearchpattern0": "No files were found to deploy with search pattern {0}", - "loc.messages.Foundmorethanonefiletodeploywithsearchpattern0Therecanbeonlyone": "Found more than one file to deploy with search pattern {0}. There can be only one." -} \ No newline at end of file diff --git a/Tasks/AzureWebPowerShellDeployment/Strings/resources.resjson/zh-TW/resources.resjson b/Tasks/AzureWebPowerShellDeployment/Strings/resources.resjson/zh-TW/resources.resjson deleted file mode 100644 index 53cb51cccd5a..000000000000 --- a/Tasks/AzureWebPowerShellDeployment/Strings/resources.resjson/zh-TW/resources.resjson +++ /dev/null @@ -1,27 +0,0 @@ -{ - "loc.friendlyName": "Azure Web 應用程式部署", - "loc.helpMarkDown": "[More Information](https://go.microsoft.com/fwlink/?LinkID=613750)", - "loc.description": "使用 Web Deploy 將 Visual Studio Web 專案發行到 Microsoft Azure Web 應用程式", - "loc.instanceNameFormat": "Azure 部署: $(WebSiteName)", - "loc.input.label.ConnectedServiceName": "Azure Subscription (Classic)", - "loc.input.help.ConnectedServiceName": "Azure Classic subscription to target for deployment.", - "loc.input.label.WebSiteLocation": "Web 應用程式位置", - "loc.input.help.WebSiteLocation": "選取網站的位置。", - "loc.input.label.WebSiteName": "Web 應用程式名稱", - "loc.input.help.WebSiteName": "輸入網站名稱,或從清單中選取。
注意: 只會列出與所選取區域的預設 App Service 方案相關聯的網站。", - "loc.input.label.Slot": "位置", - "loc.input.help.Slot": "位置", - "loc.input.label.Package": "Web Deploy 封裝", - "loc.input.help.Package": "預設成品目錄下之 Visual Studio Web Deploy 封裝的路徑。", - "loc.input.label.doNotDelete": "設定 DoNotDelete 旗標 ", - "loc.input.help.doNotDelete": "啟用此項目後,便會在發行網站時保留 Web 部署套件中的其他檔案。", - "loc.input.label.AdditionalArguments": "其他引數", - "loc.messages.Cannotgetwebsitedeploymentstatusisnotupdated": "Cannot get website, deployment status is not updated", - "loc.messages.CannotupdatedeploymentstatusSCMendpointisnotenabledforthiswebsite": "Cannot update deployment status, SCM endpoint is not enabled for this website", - "loc.messages.Cannotupdatedeploymentstatusfor01": "Cannot update deployment status for {0} - {1}", - "loc.messages.Updatingdeploymentstatus": "Updating deployment status", - "loc.messages.CannotupdatedeploymentstatusuniquedeploymentIdcannotberetrieved": "Cannot update deployment status, unique deploymentId cannot be retrieved", - "loc.messages.Updatingdeploymenthistoryfordeployment0": "Updating deployment history for deployment {0}", - "loc.messages.Nofileswerefoundtodeploywithsearchpattern0": "No files were found to deploy with search pattern {0}", - "loc.messages.Foundmorethanonefiletodeploywithsearchpattern0Therecanbeonlyone": "Found more than one file to deploy with search pattern {0}. There can be only one." -} \ No newline at end of file diff --git a/Tasks/AzureWebPowerShellDeployment/icon.png b/Tasks/AzureWebPowerShellDeployment/icon.png deleted file mode 100644 index 9ee7be815737..000000000000 Binary files a/Tasks/AzureWebPowerShellDeployment/icon.png and /dev/null differ diff --git a/Tasks/AzureWebPowerShellDeployment/icon.svg b/Tasks/AzureWebPowerShellDeployment/icon.svg deleted file mode 100644 index dc1c04af05ad..000000000000 --- a/Tasks/AzureWebPowerShellDeployment/icon.svg +++ /dev/null @@ -1,74 +0,0 @@ - - - -image/svg+xml \ No newline at end of file diff --git a/Tasks/AzureWebPowerShellDeployment/make.json b/Tasks/AzureWebPowerShellDeployment/make.json deleted file mode 100644 index b91cbd7b08db..000000000000 --- a/Tasks/AzureWebPowerShellDeployment/make.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "common": [ - { - "module": "../Common/VstsAzureHelpers_", - "type": "ps" - } - ] -} diff --git a/Tasks/AzureWebPowerShellDeployment/task.json b/Tasks/AzureWebPowerShellDeployment/task.json deleted file mode 100644 index d8eaf142aa82..000000000000 --- a/Tasks/AzureWebPowerShellDeployment/task.json +++ /dev/null @@ -1,117 +0,0 @@ -{ - "id": "DCBEF2C9-E4F4-4929-82B2-EA7FC9166109", - "name": "AzureWebPowerShellDeployment", - "friendlyName": "Azure App Service: Classic (Deprecated)", - "description": "Create or update Azure App Service using Azure PowerShell", - "helpMarkDown": "More Information : “Azure App Service: Classic” Task will be deprecated. We recommend migrating your definition to use “Azure App Service Deploy” Task instead. For more information please refer [this](https://go.microsoft.com/fwlink/?LinkID=613750).", - "category": "Deploy", - "visibility": [ - "Build", - "Release" - ], - "author": "Microsoft Corporation", - "version": { - "Major": 1, - "Minor": 0, - "Patch": 42 - }, - "demands": [ - "azureps" - ], - "minimumAgentVersion": "1.103.0", - "inputs": [ - { - "name": "ConnectedServiceName", - "type": "connectedService:Azure:Certificate,UsernamePassword", - "label": "Azure Subscription (Classic)", - "defaultValue": "", - "required": true, - "helpMarkDown": "Azure Classic subscription to target for deployment." - }, - { - "name": "WebSiteLocation", - "type": "pickList", - "label": "Web App Location", - "defaultValue": "", - "required": true, - "helpMarkDown": "Select a location for website.", - "properties": { - "EditableOptions": "True" - } - }, - { - "name": "WebSiteName", - "type": "pickList", - "label": "Web App Name", - "defaultValue": "", - "required": true, - "helpMarkDown": "Enter the website name or Select from the list.
Note: Only the websites associated with Default App Service plan for the selected region are listed.", - "properties": { - "EditableOptions": "True" - } - }, - { - "name": "Slot", - "type": "string", - "label": "Slot", - "defaultValue": "", - "required": false, - "helpMarkDown": "Slot" - }, - { - "name": "Package", - "type": "filePath", - "label": "Web Deploy Package", - "defaultValue": "", - "helpMarkDown": "Path to the Visual Studio Web Deploy package under the default artifact directory.", - "required": true - }, - { - "name": "doNotDelete", - "type": "boolean", - "label": "Set DoNotDelete flag", - "defaultValue": "false", - "helpMarkDown": "By enabling this, additional files in web deployment package are preserved while publishing website.", - "required": false - }, - { - "name": "AdditionalArguments", - "type": "string", - "label": "Additional Arguments", - "defaultValue": "", - "required": false - } - ], - "dataSourceBindings": [ - { - "target": "WebSiteLocation", - "endpointId": "$(ConnectedServiceName)", - "dataSourceName": "AzureWebsiteLocations" - }, - { - "target": "WebSiteName", - "endpointId": "$(ConnectedServiceName)", - "dataSourceName": "AzureWebSiteNames", - "parameters": { - "WebSiteLocation": "$(WebSiteLocation)" - } - } - ], - "instanceNameFormat": "Azure Deployment: $(WebSiteName)", - "execution": { - "PowerShell3": { - "target": "Publish-AzureWebDeployment.ps1" - } - }, - "messages": { - "Cannotgetwebsitedeploymentstatusisnotupdated": "Cannot get website, deployment status is not updated", - "CannotupdatedeploymentstatusSCMendpointisnotenabledforthiswebsite": "Cannot update deployment status, SCM endpoint is not enabled for this website", - "Cannotupdatedeploymentstatusfor01": "Cannot update deployment status for {0} - {1}", - "Updatingdeploymentstatus": "Updating deployment status", - "CannotupdatedeploymentstatusuniquedeploymentIdcannotberetrieved": "Cannot update deployment status, unique deploymentId cannot be retrieved", - "Updatingdeploymenthistoryfordeployment0": "Updating deployment history for deployment {0}", - "Nofileswerefoundtodeploywithsearchpattern0": "No files were found to deploy with search pattern {0}", - "Foundmorethanonefiletodeploywithsearchpattern0Therecanbeonlyone": "Found more than one file to deploy with search pattern {0}. There can be only one.", - "FailedtodeployWebsiteError0": "Failed to deploy Website. Error : {0}" - } -} \ No newline at end of file diff --git a/Tasks/AzureWebPowerShellDeployment/task.loc.json b/Tasks/AzureWebPowerShellDeployment/task.loc.json deleted file mode 100644 index 134b07464364..000000000000 --- a/Tasks/AzureWebPowerShellDeployment/task.loc.json +++ /dev/null @@ -1,117 +0,0 @@ -{ - "id": "DCBEF2C9-E4F4-4929-82B2-EA7FC9166109", - "name": "AzureWebPowerShellDeployment", - "friendlyName": "ms-resource:loc.friendlyName", - "description": "ms-resource:loc.description", - "helpMarkDown": "ms-resource:loc.helpMarkDown", - "category": "Deploy", - "visibility": [ - "Build", - "Release" - ], - "author": "Microsoft Corporation", - "version": { - "Major": 1, - "Minor": 0, - "Patch": 42 - }, - "demands": [ - "azureps" - ], - "minimumAgentVersion": "1.103.0", - "inputs": [ - { - "name": "ConnectedServiceName", - "type": "connectedService:Azure:Certificate,UsernamePassword", - "label": "ms-resource:loc.input.label.ConnectedServiceName", - "defaultValue": "", - "required": true, - "helpMarkDown": "ms-resource:loc.input.help.ConnectedServiceName" - }, - { - "name": "WebSiteLocation", - "type": "pickList", - "label": "ms-resource:loc.input.label.WebSiteLocation", - "defaultValue": "", - "required": true, - "helpMarkDown": "ms-resource:loc.input.help.WebSiteLocation", - "properties": { - "EditableOptions": "True" - } - }, - { - "name": "WebSiteName", - "type": "pickList", - "label": "ms-resource:loc.input.label.WebSiteName", - "defaultValue": "", - "required": true, - "helpMarkDown": "ms-resource:loc.input.help.WebSiteName", - "properties": { - "EditableOptions": "True" - } - }, - { - "name": "Slot", - "type": "string", - "label": "ms-resource:loc.input.label.Slot", - "defaultValue": "", - "required": false, - "helpMarkDown": "ms-resource:loc.input.help.Slot" - }, - { - "name": "Package", - "type": "filePath", - "label": "ms-resource:loc.input.label.Package", - "defaultValue": "", - "helpMarkDown": "ms-resource:loc.input.help.Package", - "required": true - }, - { - "name": "doNotDelete", - "type": "boolean", - "label": "ms-resource:loc.input.label.doNotDelete", - "defaultValue": "false", - "helpMarkDown": "ms-resource:loc.input.help.doNotDelete", - "required": false - }, - { - "name": "AdditionalArguments", - "type": "string", - "label": "ms-resource:loc.input.label.AdditionalArguments", - "defaultValue": "", - "required": false - } - ], - "dataSourceBindings": [ - { - "target": "WebSiteLocation", - "endpointId": "$(ConnectedServiceName)", - "dataSourceName": "AzureWebsiteLocations" - }, - { - "target": "WebSiteName", - "endpointId": "$(ConnectedServiceName)", - "dataSourceName": "AzureWebSiteNames", - "parameters": { - "WebSiteLocation": "$(WebSiteLocation)" - } - } - ], - "instanceNameFormat": "ms-resource:loc.instanceNameFormat", - "execution": { - "PowerShell3": { - "target": "Publish-AzureWebDeployment.ps1" - } - }, - "messages": { - "Cannotgetwebsitedeploymentstatusisnotupdated": "ms-resource:loc.messages.Cannotgetwebsitedeploymentstatusisnotupdated", - "CannotupdatedeploymentstatusSCMendpointisnotenabledforthiswebsite": "ms-resource:loc.messages.CannotupdatedeploymentstatusSCMendpointisnotenabledforthiswebsite", - "Cannotupdatedeploymentstatusfor01": "ms-resource:loc.messages.Cannotupdatedeploymentstatusfor01", - "Updatingdeploymentstatus": "ms-resource:loc.messages.Updatingdeploymentstatus", - "CannotupdatedeploymentstatusuniquedeploymentIdcannotberetrieved": "ms-resource:loc.messages.CannotupdatedeploymentstatusuniquedeploymentIdcannotberetrieved", - "Updatingdeploymenthistoryfordeployment0": "ms-resource:loc.messages.Updatingdeploymenthistoryfordeployment0", - "Nofileswerefoundtodeploywithsearchpattern0": "ms-resource:loc.messages.Nofileswerefoundtodeploywithsearchpattern0", - "Foundmorethanonefiletodeploywithsearchpattern0Therecanbeonlyone": "ms-resource:loc.messages.Foundmorethanonefiletodeploywithsearchpattern0Therecanbeonlyone", - "FailedtodeployWebsiteError0": "ms-resource:loc.messages.FailedtodeployWebsiteError0" - } -} \ No newline at end of file diff --git a/Tasks/CocoaPods/task.json b/Tasks/CocoaPods/task.json index 8055b01a8a55..863c6c2a5569 100644 --- a/Tasks/CocoaPods/task.json +++ b/Tasks/CocoaPods/task.json @@ -7,12 +7,16 @@ "category": "Package", "visibility": [ "Build" + ], + "runsOn": [ + "Agent", + "MachineGroup" ], "author": "Microsoft Corporation", "version": { "Major": 0, "Minor": 1, - "Patch": 18 + "Patch": 19 }, "instanceNameFormat": "pod install", "inputs": [ diff --git a/Tasks/CocoaPods/task.loc.json b/Tasks/CocoaPods/task.loc.json index 59973ad5c584..4b1ffe9aa7a1 100644 --- a/Tasks/CocoaPods/task.loc.json +++ b/Tasks/CocoaPods/task.loc.json @@ -8,11 +8,15 @@ "visibility": [ "Build" ], + "runsOn": [ + "Agent", + "MachineGroup" + ], "author": "Microsoft Corporation", "version": { "Major": 0, "Minor": 1, - "Patch": 18 + "Patch": 19 }, "instanceNameFormat": "ms-resource:loc.instanceNameFormat", "inputs": [ diff --git a/Tasks/Common/VstsAzureRestHelpers_/VstsAzureRestHelpers_.psm1 b/Tasks/Common/VstsAzureRestHelpers_/VstsAzureRestHelpers_.psm1 index 4cb2820a0d56..45a95b7557c0 100644 --- a/Tasks/Common/VstsAzureRestHelpers_/VstsAzureRestHelpers_.psm1 +++ b/Tasks/Common/VstsAzureRestHelpers_/VstsAzureRestHelpers_.psm1 @@ -498,14 +498,18 @@ function Get-AzureSqlDatabaseServerResourceId $uri = "$script:azureRmUri/subscriptions/$subscriptionId/resources?api-version=$apiVersion" $headers = @{Authorization=("{0} {1}" -f $accessToken.token_type, $accessToken.access_token)} - $ResourceDetails = (Invoke-RestMethod -Uri $uri -Method $method -Headers $headers -ContentType $script:jsonContentType) - foreach ($resourceDetail in $ResourceDetails.Value) - { - if ($resourceDetail.name -eq $serverName -and $resourceDetail.type -eq $serverType) + do { + Write-Verbose "Fetching Resources from $uri" + $ResourceDetails = (Invoke-RestMethod -Uri $uri -Method $method -Headers $headers -ContentType $script:jsonContentType) + foreach ($resourceDetail in $ResourceDetails.Value) { - return $resourceDetail.id + if ($resourceDetail.name -eq $serverName -and $resourceDetail.type -eq $serverType) + { + return $resourceDetail.id + } } - } + $uri = $ResourceDetails.nextLink + } until([string]::IsNullOrEmpty($ResourceDetails.nextLink)) throw (Get-VstsLocString -Key AZ_NoValidResourceIdFound -ArgumentList $serverName, $serverType, $subscriptionId) } diff --git a/Tasks/Common/webdeployment-common/deployusingmsdeploy.ts b/Tasks/Common/webdeployment-common/deployusingmsdeploy.ts index b4a95366ac57..ed2707435b2f 100644 --- a/Tasks/Common/webdeployment-common/deployusingmsdeploy.ts +++ b/Tasks/Common/webdeployment-common/deployusingmsdeploy.ts @@ -3,7 +3,6 @@ import fs = require('fs'); var msDeployUtility = require('./msdeployutility.js'); var utility = require('./utility.js'); -var azureRESTUtility = require ('./azurerestutility.js'); // should be removed /** * Executes Web Deploy command @@ -29,8 +28,6 @@ export async function DeployUsingMSDeploy(webDeployPkg, webAppName, publishingPr excludeFilesFromAppDataFlag, takeAppOfflineFlag, virtualApplication, setParametersFile, additionalArguments, isParamFilePresentInPackage, isFolderBasedDeployment, useWebDeploy); - var isDeploymentSuccess = true; - var deploymentError = null; try { var msDeployBatchFile = tl.getVariable('System.DefaultWorkingDirectory') + '\\' + 'msDeployCommand.bat'; @@ -46,21 +43,7 @@ export async function DeployUsingMSDeploy(webDeployPkg, webAppName, publishingPr } catch(error) { tl.error(tl.loc('Failedtodeploywebsite')); - isDeploymentSuccess = false; - deploymentError = error; msDeployUtility.redirectMSDeployErrorToConsole(); - } - - if(publishingProfile != null){ - try { - tl._writeLine(await azureRESTUtility.updateDeploymentStatus(publishingProfile, isDeploymentSuccess)); - } - catch(error) { - tl.warning(error); - } - } - - if(!isDeploymentSuccess) { - throw Error(deploymentError); + throw Error(error); } } \ No newline at end of file diff --git a/Tasks/Common/webdeployment-common/fileencoding.ts b/Tasks/Common/webdeployment-common/fileencoding.ts index 19d0373b1718..593fb419b9d8 100644 --- a/Tasks/Common/webdeployment-common/fileencoding.ts +++ b/Tasks/Common/webdeployment-common/fileencoding.ts @@ -27,9 +27,7 @@ function detectFileEncodingWithBOM(fileName: string, buffer: Buffer) { function detectFileEncodingWithoutBOM(fileName: string, buffer: Buffer) { tl.debug('Detecting file encoding without BOM'); - if(buffer.length < 4) { - throw Error('File buffer is too short to detect encoding type'); - } + var typeCode = 0; for(var index = 0; index < 4; index++) { typeCode = typeCode << 1; @@ -47,12 +45,12 @@ function detectFileEncodingWithoutBOM(fileName: string, buffer: Buffer) { case 15: return ['utf-8', false]; default: - throw Error(tl.loc('UnknownFileEncodeError', typeCode)); + throw Error(tl.loc('UnknownFileEncodeError', fileName, typeCode)); } } export function detectFileEncoding(fileName: string, buffer: Buffer) { if(buffer.length < 4) { - throw Error('ShortFileBufferError'); + throw Error(tl.loc('ShortFileBufferError', fileName)); } var fileEncoding = detectFileEncodingWithBOM(fileName, buffer) || detectFileEncodingWithoutBOM(fileName, buffer); return fileEncoding; diff --git a/Tasks/Common/webdeployment-common/ltxdomutility.ts b/Tasks/Common/webdeployment-common/ltxdomutility.ts index 275e40c206f4..44ccdf72ac62 100644 --- a/Tasks/Common/webdeployment-common/ltxdomutility.ts +++ b/Tasks/Common/webdeployment-common/ltxdomutility.ts @@ -9,6 +9,7 @@ export function initializeDOM(xmlContent) { xmlDomLookUpTable = {}; headerContent = null; var xmlDom = ltx.parse(xmlContent); + readHeader(xmlContent); buildLookUpTable(xmlDom); return xmlDom; } @@ -25,7 +26,7 @@ function readHeader(xmlContent) { } export function getContentWithHeader(xmlDom) { - return xmlDom ? (headerContent ? headerContent+"\n" : "") + xmlDom.root().toString() : ""; + return xmlDom ? (headerContent ? headerContent + "\n" : "") + xmlDom.root().toString() : ""; } /** diff --git a/Tasks/Common/webdeployment-common/package.json b/Tasks/Common/webdeployment-common/package.json index 4fb87b3ee02b..4cafddefe774 100644 --- a/Tasks/Common/webdeployment-common/package.json +++ b/Tasks/Common/webdeployment-common/package.json @@ -13,16 +13,15 @@ }, "homepage": "https://github.com/Microsoft/vsts-tasks#readme", "dependencies": { - "vsts-task-lib": "^0.9.20", - "q": "^1.4.1", - "adal-node": "^0.1.15", - "xml2js": "^0.4.13", - "decompress-zip": "^0.3.0", - "gulp": "^3.9.1", - "gulp-zip": "^3.2.0", - "vso-node-api": "^5.0.5", - "winreg" : "^1.2.2", - "ltx": "^2.5.0" + "archiver": "1.2.0", + "adal-node": "0.1.15", + "decompress-zip": "0.3.0", + "ltx": "2.5.0", + "q": "1.4.1", + "vso-node-api": "5.1.1", + "vsts-task-lib": "0.9.20", + "winreg": "1.2.2", + "xml2js": "0.4.13" }, "devDependencies": { "mocha": "^3.1.2" diff --git a/Tasks/Common/webdeployment-common/ziputility.ts b/Tasks/Common/webdeployment-common/ziputility.ts index 6202e2106dab..4c2722e80437 100644 --- a/Tasks/Common/webdeployment-common/ziputility.ts +++ b/Tasks/Common/webdeployment-common/ziputility.ts @@ -1,12 +1,12 @@ import tl = require('vsts-task-lib/task'); import path = require('path'); import Q = require('q'); +import fs = require('fs'); -var gulp = require('gulp'); -var zip = require('gulp-zip'); var DecompressZip = require('decompress-zip'); +var archiver = require('archiver'); -export function unzip(zipLocation, unzipLocation) { +export async function unzip(zipLocation, unzipLocation) { var defer = Q.defer(); if(tl.exist(unzipLocation)) { tl.rmRF(unzipLocation, false); @@ -25,21 +25,26 @@ export function unzip(zipLocation, unzipLocation) { return defer.promise; } -export function archiveFolder(folderPath, targetPath, zipName) { +export async function archiveFolder(folderPath, targetPath, zipName) { var defer = Q.defer(); tl.debug('Archiving ' + folderPath + ' to ' + zipName); - gulp.src(path.join(folderPath, '**', '*'), - { - dot: true - }) - .pipe(zip(zipName)) - .pipe(gulp.dest(targetPath)).on('end', function(error){ - if(error) { - defer.reject(error); - } - defer.resolve(path.join(targetPath, zipName)); - }); - return defer.promise; + var outputZipPath = path.join(targetPath, zipName); + var output = fs.createWriteStream(outputZipPath); + var archive = archiver('zip'); + output.on('close', function () { + tl.debug('Successfully created archive ' + zipName); + defer.resolve(outputZipPath); + }); + + output.on('error', function(error) { + defer.reject(error); + }); + + archive.pipe(output); + archive.directory(folderPath, '/'); + archive.finalize(); + + return defer.promise; } /** diff --git a/Tasks/CopyFiles/Strings/resources.resjson/en-US/resources.resjson b/Tasks/CopyFiles/Strings/resources.resjson/en-US/resources.resjson index ccc44b5a5786..9d2ad633b54d 100644 --- a/Tasks/CopyFiles/Strings/resources.resjson/en-US/resources.resjson +++ b/Tasks/CopyFiles/Strings/resources.resjson/en-US/resources.resjson @@ -14,6 +14,8 @@ "loc.input.help.CleanTargetFolder": "Delete all existing files in target folder before copy", "loc.input.label.OverWrite": "Overwrite", "loc.input.help.OverWrite": "Replace existing file in target folder", + "loc.input.label.flattenFolders": "Flatten Folders", + "loc.input.help.flattenFolders": "Flatten the folder structure and copy all files into the specified target folder.", "loc.messages.FoundNFiles": "found %d files", "loc.messages.CleaningTargetFolder": "Cleaning target folder: %s", "loc.messages.FileAlreadyExistAt": "File %s already exist at %s", diff --git a/Tasks/CopyFiles/copyfiles.ts b/Tasks/CopyFiles/copyfiles.ts index d1b5a799df81..f6bdbfed5097 100644 --- a/Tasks/CopyFiles/copyfiles.ts +++ b/Tasks/CopyFiles/copyfiles.ts @@ -85,6 +85,7 @@ var targetFolder: string = tl.getPathInput('TargetFolder', true); var cleanTargetFolder: boolean = tl.getBoolInput('CleanTargetFolder', false); var overWrite: boolean = tl.getBoolInput('OverWrite', false); +var flattenFolders: boolean = tl.getBoolInput('flattenFolders', false); // not use common root for now. //var useCommonRoot: boolean = tl.getBoolInput('UseCommonRoot', false); @@ -215,9 +216,14 @@ if (files.length > 0) { try { var createdFolders = {}; files.forEach((file: string) => { - var relativePath = file.substring(sourceFolder.length) + var relativePath; + if(flattenFolders) { + relativePath = path.basename(file); + } else { + relativePath = file.substring(sourceFolder.length) .replace(/^\\/g, "") .replace(/^\//g, ""); + } if (useCommonRoot) { relativePath = file.substring(commonRoot.length) diff --git a/Tasks/CopyFiles/task.json b/Tasks/CopyFiles/task.json index 7ca3ba368e47..8cb49a34e02f 100644 --- a/Tasks/CopyFiles/task.json +++ b/Tasks/CopyFiles/task.json @@ -16,7 +16,7 @@ "version": { "Major": 1, "Minor": 1, - "Patch": 3 + "Patch": 4 }, "demands": [], "minimumAgentVersion": "1.91.0", @@ -69,6 +69,15 @@ "required": false, "helpMarkDown": "Replace existing file in target folder", "groupName": "advanced" + }, + { + "name": "flattenFolders", + "type": "boolean", + "label": "Flatten Folders", + "defaultValue": "false", + "required": false, + "helpMarkDown": "Flatten the folder structure and copy all files into the specified target folder.", + "groupName": "advanced" } ], "instanceNameFormat": "Copy Files to: $(TargetFolder)", diff --git a/Tasks/CopyFiles/task.loc.json b/Tasks/CopyFiles/task.loc.json index 55cdc68d2031..ef70759ef05c 100644 --- a/Tasks/CopyFiles/task.loc.json +++ b/Tasks/CopyFiles/task.loc.json @@ -16,7 +16,7 @@ "version": { "Major": 1, "Minor": 1, - "Patch": 3 + "Patch": 4 }, "demands": [], "minimumAgentVersion": "1.91.0", @@ -69,6 +69,15 @@ "required": false, "helpMarkDown": "ms-resource:loc.input.help.OverWrite", "groupName": "advanced" + }, + { + "name": "flattenFolders", + "type": "boolean", + "label": "ms-resource:loc.input.label.flattenFolders", + "defaultValue": "false", + "required": false, + "helpMarkDown": "ms-resource:loc.input.help.flattenFolders", + "groupName": "advanced" } ], "instanceNameFormat": "ms-resource:loc.instanceNameFormat", diff --git a/Tasks/CopyFilesOverSSH/task.json b/Tasks/CopyFilesOverSSH/task.json index f69e16954814..be9370e131a3 100644 --- a/Tasks/CopyFilesOverSSH/task.json +++ b/Tasks/CopyFilesOverSSH/task.json @@ -8,12 +8,16 @@ "visibility": [ "Build", "Release" + ], + "runsOn": [ + "Agent", + "MachineGroup" ], "author": "Microsoft Corporation", "version": { "Major": 0, "Minor": 1, - "Patch": 1 + "Patch": 2 }, "demands": [], "instanceNameFormat": "Securely copy files to the remote machine", diff --git a/Tasks/CopyFilesOverSSH/task.loc.json b/Tasks/CopyFilesOverSSH/task.loc.json index 9004b68fa237..e1e1a06343bc 100644 --- a/Tasks/CopyFilesOverSSH/task.loc.json +++ b/Tasks/CopyFilesOverSSH/task.loc.json @@ -9,11 +9,15 @@ "Build", "Release" ], + "runsOn": [ + "Agent", + "MachineGroup" + ], "author": "Microsoft Corporation", "version": { "Major": 0, "Minor": 1, - "Patch": 1 + "Patch": 2 }, "demands": [], "instanceNameFormat": "ms-resource:loc.instanceNameFormat", diff --git a/Tasks/DecryptFile/task.json b/Tasks/DecryptFile/task.json index 00feb7b68905..1f0b399a3e4f 100644 --- a/Tasks/DecryptFile/task.json +++ b/Tasks/DecryptFile/task.json @@ -7,12 +7,16 @@ "visibility": [ "Build", "Release" + ], + "runsOn": [ + "Agent", + "MachineGroup" ], "author": "Microsoft Corporation", "version": { "Major": 1, "Minor": 0, - "Patch": 16 + "Patch": 17 }, "groups": [ { diff --git a/Tasks/DecryptFile/task.loc.json b/Tasks/DecryptFile/task.loc.json index 0229322ef149..82436f27db24 100644 --- a/Tasks/DecryptFile/task.loc.json +++ b/Tasks/DecryptFile/task.loc.json @@ -8,11 +8,15 @@ "Build", "Release" ], + "runsOn": [ + "Agent", + "MachineGroup" + ], "author": "Microsoft Corporation", "version": { "Major": 1, "Minor": 0, - "Patch": 16 + "Patch": 17 }, "groups": [ { diff --git a/Tasks/DeployAzureResourceGroup/task.loc.json b/Tasks/DeployAzureResourceGroup/task.loc.json index 40c272693d51..bb5ea6330c38 100644 --- a/Tasks/DeployAzureResourceGroup/task.loc.json +++ b/Tasks/DeployAzureResourceGroup/task.loc.json @@ -272,4 +272,4 @@ "ARG_SetExtensionFailedForVm": "ms-resource:loc.messages.ARG_SetExtensionFailedForVm", "ARG_DeploymentPrereqFailed": "ms-resource:loc.messages.ARG_DeploymentPrereqFailed" } -} +} \ No newline at end of file diff --git a/Tasks/DotNetCoreCLI/dotnetcore.ts b/Tasks/DotNetCoreCLI/dotnetcore.ts index 65518d441fe6..1761e6599df8 100644 --- a/Tasks/DotNetCoreCLI/dotnetcore.ts +++ b/Tasks/DotNetCoreCLI/dotnetcore.ts @@ -44,6 +44,8 @@ export class dotNetExe { var result = dotnet.execSync(); if (result.code != 0) { + var error = result.stderr.replace("\r", "%0D"); + tl.error(error.replace("\n", "%0A")); tl.setResult(result.code, tl.loc("dotnetCommandFailed", result.code)); } diff --git a/Tasks/DotNetCoreCLI/task.json b/Tasks/DotNetCoreCLI/task.json index 72181d26cd85..10a644f68271 100644 --- a/Tasks/DotNetCoreCLI/task.json +++ b/Tasks/DotNetCoreCLI/task.json @@ -16,7 +16,7 @@ "demands": [], "version": { "Major": 0, - "Minor": 1, + "Minor": 2, "Patch": 0 }, "minimumAgentVersion": "1.95.0", diff --git a/Tasks/DotNetCoreCLI/task.loc.json b/Tasks/DotNetCoreCLI/task.loc.json index d9b64072a1da..77ec045d7fad 100644 --- a/Tasks/DotNetCoreCLI/task.loc.json +++ b/Tasks/DotNetCoreCLI/task.loc.json @@ -16,7 +16,7 @@ "demands": [], "version": { "Major": 0, - "Minor": 1, + "Minor": 2, "Patch": 0 }, "minimumAgentVersion": "1.95.0", diff --git a/Tasks/ExtractFiles/task.json b/Tasks/ExtractFiles/task.json index 711bd14a01de..745bfdccdf7c 100644 --- a/Tasks/ExtractFiles/task.json +++ b/Tasks/ExtractFiles/task.json @@ -9,12 +9,16 @@ "visibility": [ "Build", "Release" + ], + "runsOn": [ + "Agent", + "MachineGroup" ], "demands": [], "version": { "Major": 1, "Minor": 0, - "Patch": 7 + "Patch": 8 }, "instanceNameFormat": "Extract files $(message)", "inputs": [ diff --git a/Tasks/ExtractFiles/task.loc.json b/Tasks/ExtractFiles/task.loc.json index 70b140d26780..a56851a671b2 100644 --- a/Tasks/ExtractFiles/task.loc.json +++ b/Tasks/ExtractFiles/task.loc.json @@ -10,11 +10,15 @@ "Build", "Release" ], + "runsOn": [ + "Agent", + "MachineGroup" + ], "demands": [], "version": { "Major": 1, "Minor": 0, - "Patch": 7 + "Patch": 8 }, "instanceNameFormat": "ms-resource:loc.instanceNameFormat", "inputs": [ diff --git a/Tasks/FtpUpload/task.json b/Tasks/FtpUpload/task.json index f78fe6f51ec9..686d3f98ad83 100644 --- a/Tasks/FtpUpload/task.json +++ b/Tasks/FtpUpload/task.json @@ -9,12 +9,16 @@ "visibility": [ "Build", "Release" + ], + "runsOn": [ + "Agent", + "MachineGroup" ], "demands": [], "version": { "Major": 1, "Minor": 0, - "Patch": 4 + "Patch": 5 }, "instanceNameFormat": "FTP Upload: $(rootFolder)", "groups": [ diff --git a/Tasks/FtpUpload/task.loc.json b/Tasks/FtpUpload/task.loc.json index 0a5cf43ec634..138b69a33944 100644 --- a/Tasks/FtpUpload/task.loc.json +++ b/Tasks/FtpUpload/task.loc.json @@ -10,11 +10,15 @@ "Build", "Release" ], + "runsOn": [ + "Agent", + "MachineGroup" + ], "demands": [], "version": { "Major": 1, "Minor": 0, - "Patch": 4 + "Patch": 5 }, "instanceNameFormat": "ms-resource:loc.instanceNameFormat", "groups": [ diff --git a/Tasks/Gradle/README.md b/Tasks/Gradle/README.md index d62c87c9af39..a912766e6783 100644 --- a/Tasks/Gradle/README.md +++ b/Tasks/Gradle/README.md @@ -36,6 +36,16 @@ Use the next options to manage your `JAVA_HOME` attribute by JDK Version and Pat - **JDK Architecture :** Select the approriate JDK Architecture. By default it is set to `x86` +####Code Analysis + +- **Run SonarQube Analysis :** You can choose to run SonarQube analysis after executing the current goals. 'install' or 'package' goals should be executed first. To know more about this option [click here](https://blogs.msdn.com/b/visualstudioalm/archive/2015/10/08/the-maven-build-task-now-simplifies-sonarqube-analysis.aspx) + +- **Run Checkstyle :** You can choose to run the Checkstyle static code analysis tool, which checks the compliance of your source code with coding rules. You will receive a code analysis report with the number of violations detected, as well as the original report files if there were any violations. + +- **Run PMD :** You can choose to run the PMD static code analysis tool, which examines your source code for possible bugs. You will receive a code analysis report with the number of violations detected, as well as the original report files if there were any violations. + +- **Run FindBugs :** You can choose to run the FindBugs static code analysis tool, which examines the bytecode of your program for possible bugs. You will receive a code analysis report with the number of violations detected, as well as the original report files if there were any violations. + ###Q&A ####How do I generate a wrapper from my Gradle project? diff --git a/Tasks/Gradle/make.json b/Tasks/Gradle/make.json index 833ddb0645c3..56ef268725c6 100644 --- a/Tasks/Gradle/make.json +++ b/Tasks/Gradle/make.json @@ -17,7 +17,8 @@ "CodeAnalysis/checkstyle.gradle", "CodeAnalysis/checkstyle.xml", "CodeAnalysis/pmd.gradle", - "CodeAnalysis/sonar.gradle" + "CodeAnalysis/sonar.gradle", + "CodeAnalysis/findbugs.gradle" ], "dest": "CodeAnalysis/" } diff --git a/Tasks/Gradle/task.json b/Tasks/Gradle/task.json index 4ab12ecd78b2..d83a95da0b21 100644 --- a/Tasks/Gradle/task.json +++ b/Tasks/Gradle/task.json @@ -7,12 +7,16 @@ "category": "Build", "visibility": [ "Build" + ], + "runsOn": [ + "Agent", + "MachineGroup" ], "author": "Microsoft Corporation", "version": { "Major": 1, "Minor": 0, - "Patch": 70 + "Patch": 72 }, "demands": [ "java" diff --git a/Tasks/Gradle/task.loc.json b/Tasks/Gradle/task.loc.json index 24abe59272b1..c4c46c555d39 100644 --- a/Tasks/Gradle/task.loc.json +++ b/Tasks/Gradle/task.loc.json @@ -8,11 +8,15 @@ "visibility": [ "Build" ], + "runsOn": [ + "Agent", + "MachineGroup" + ], "author": "Microsoft Corporation", "version": { "Major": 1, "Minor": 0, - "Patch": 70 + "Patch": 72 }, "demands": [ "java" diff --git a/Tasks/Grunt/task.json b/Tasks/Grunt/task.json index a6afc659323a..9e6c34f10cdc 100644 --- a/Tasks/Grunt/task.json +++ b/Tasks/Grunt/task.json @@ -7,12 +7,16 @@ "category": "Build", "visibility": [ "Build" + ], + "runsOn": [ + "Agent", + "MachineGroup" ], "author": "Microsoft Corporation", "version": { "Major": 0, "Minor": 5, - "Patch": 24 + "Patch": 25 }, "demands": [ "node.js" diff --git a/Tasks/Grunt/task.loc.json b/Tasks/Grunt/task.loc.json index e80233132aae..21a6eb0b7da4 100644 --- a/Tasks/Grunt/task.loc.json +++ b/Tasks/Grunt/task.loc.json @@ -8,11 +8,15 @@ "visibility": [ "Build" ], + "runsOn": [ + "Agent", + "MachineGroup" + ], "author": "Microsoft Corporation", "version": { "Major": 0, "Minor": 5, - "Patch": 24 + "Patch": 25 }, "demands": [ "node.js" diff --git a/Tasks/Gulp/task.json b/Tasks/Gulp/task.json index 2360e7611f96..3775e9327802 100644 --- a/Tasks/Gulp/task.json +++ b/Tasks/Gulp/task.json @@ -7,12 +7,16 @@ "category": "Build", "visibility": [ "Build" + ], + "runsOn": [ + "Agent", + "MachineGroup" ], "author": "Microsoft Corporation", "version": { "Major": 0, "Minor": 5, - "Patch": 28 + "Patch": 29 }, "demands": [ "node.js" diff --git a/Tasks/Gulp/task.loc.json b/Tasks/Gulp/task.loc.json index ddf0d73fd055..cca2e1b333c3 100644 --- a/Tasks/Gulp/task.loc.json +++ b/Tasks/Gulp/task.loc.json @@ -8,11 +8,15 @@ "visibility": [ "Build" ], + "runsOn": [ + "Agent", + "MachineGroup" + ], "author": "Microsoft Corporation", "version": { "Major": 0, "Minor": 5, - "Patch": 28 + "Patch": 29 }, "demands": [ "node.js" diff --git a/Tasks/IISWebAppDeployment/DeployIISWebApp.ps1 b/Tasks/IISWebAppDeployment/DeployIISWebApp.ps1 deleted file mode 100644 index 71e788c73b5a..000000000000 --- a/Tasks/IISWebAppDeployment/DeployIISWebApp.ps1 +++ /dev/null @@ -1,157 +0,0 @@ -param ( - [string]$environmentName, - [string]$adminUserName, - [string]$adminPassword, - [string]$winrmProtocol, - [string]$testCertificate, - [string]$resourceFilteringMethod, - [string]$machineFilter, - [string]$webDeployPackage, - [string]$webDeployParamFile, - [string]$overRideParams, - [string]$createWebSite, - [string]$webSiteName, - [string]$webSitePhysicalPath, - [string]$webSitePhysicalPathAuth, - [string]$webSiteAuthUserName, - [string]$webSiteAuthUserPassword, - [string]$addBinding, - [string]$assignDuplicateBinding, - [string]$protocol, - [string]$ipAddress, - [string]$port, - [string]$hostNameWithHttp, - [string]$hostNameWithOutSNI, - [string]$hostNameWithSNI, - [string]$serverNameIndication, - [string]$sslCertThumbPrint, - [string]$createAppPool, - [string]$appPoolName, - [string]$dotNetVersion, - [string]$pipeLineMode, - [string]$appPoolIdentity, - [string]$appPoolUsername, - [string]$appPoolPassword, - [string]$appCmdCommands, - [string]$deployInParallel - ) - -Write-Warning "The preview IIS Web App Deployment task has been deprecated and will be removed soon. An IIS Web App Deployment extension has been released in the Visual Studio Team Services marketplace at https://aka.ms/iisextn. Install the extension, and use its tasks in the Build/Release definitions, and delete the preview task from the definition." -Write-Verbose "Entering script DeployIISWebApp.ps1" -Verbose - -$hostName = [string]::Empty - -if($protocol -eq "http") -{ - $hostName = $hostNameWithHttp -} -elseif($serverNameIndication -eq "true") -{ - $hostName = $hostNameWithSNI -} -else -{ - $hostName = $hostNameWithOutSNI -} - -Write-Verbose "environmentName = $environmentName" -Verbose -Write-Verbose "adminUserName = $adminUserName" -Verbose -Write-Verbose "winrm protocol to connect to machine = $winrmProtocol" -Verbose -Write-Verbose "testCertificate = $testCertificate" -Verbose -Write-Verbose "resourceFilteringMethod = $resourceFilteringMethod" -Verbose -Write-Verbose "machineFilter = $machineFilter" -Verbose -Write-Verbose "webDeployPackage = $webDeployPackage" -Verbose -Write-Verbose "webDeployParamFile = $webDeployParamFile" -Verbose -Write-Verbose "overRideParams = $overRideParams" -Verbose -Write-Verbose "deployInParallel = $deployInParallel" -Verbose - -Write-Verbose "createWebSite = $createWebSite" -Verbose -Write-Verbose "webSiteName = $webSiteName" -Verbose -Write-Verbose "webSitePhysicalPath = $webSitePhysicalPath" -Verbose -Write-Verbose "webSitePhysicalPathAuth = $webSitePhysicalPathAuth" -Verbose -Write-Verbose "webSiteAuthUserName = $webSiteAuthUserName" -Verbose -Write-Verbose "addBinding = $addBinding" -Verbose -Write-Verbose "assignDuplicateBinding = $assignDuplicateBinding" -Verbose -Write-Verbose "protocol = $protocol" -Verbose -Write-Verbose "ipAddress = $ipAddress" -Verbose -Write-Verbose "port = $port" -Verbose -Write-Verbose "hostName = $hostName" -Verbose -Write-Verbose "serverNameIndication = $serverNameIndication" -Verbose - -Write-Verbose "createAppPool = $createAppPool" -Verbose -Write-Verbose "appPoolName = $appPoolName" -Verbose -Write-Verbose "dotNetVersion = $dotNetVersion" -Verbose -Write-Verbose "pipeLineMode = $pipeLineMode" -Verbose -Write-Verbose "appPoolIdentity = $appPoolIdentity" -Verbose -Write-Verbose "appPoolUsername = $appPoolUsername" -Verbose - -Write-Verbose "appCmdCommands = $appCmdCommands" -Verbose -Write-Verbose "deployInParallel = $deployInParallel" -Verbose - -import-module "Microsoft.TeamFoundation.DistributedTask.Task.Internal" -import-module "Microsoft.TeamFoundation.DistributedTask.Task.Common" -import-module "Microsoft.TeamFoundation.DistributedTask.Task.DevTestLabs" -Import-Module "Microsoft.TeamFoundation.DistributedTask.Task.Deployment.Internal" -Import-Module "Microsoft.TeamFoundation.DistributedTask.Task.Deployment.RemoteDeployment" - -$webDeployPackage = $webDeployPackage.Trim('"', ' ') -$webDeployParamFile = $webDeployParamFile.Trim('"', ' ') -$webSiteName = $webSiteName.Trim('"', ' ') -$webSitePhysicalPath = $webSitePhysicalPath.Trim('"', ' ') -$webSiteAuthUserName = $webSiteAuthUserName.Trim() - -$appPoolName = $appPoolName.Trim('"', ' ') -$appPoolUsername = $appPoolUsername.Trim() - -$appCmdCommands = $appCmdCommands.Replace('"', '`"') - -if($createWebSite -ieq "true" -and [string]::IsNullOrWhiteSpace($webSiteName)) -{ - throw "Website Name cannot be empty if you want to create or update the target website." -} - -if($createAppPool -ieq "true" -and [string]::IsNullOrWhiteSpace($appPoolName)) -{ - throw "Application pool name cannot be empty if you want to create or update the target app pool." -} - - -if(![string]::IsNullOrWhiteSpace($webSiteName)) -{ - if([string]::IsNullOrWhiteSpace($overRideParams)) - { - Write-Verbose "Adding override params to ensure deployment happens on $webSiteName" -Verbose - $overRideParams = [string]::Format('name="IIS Web Application Name",value="{0}"', $webSiteName) - } - elseif(!$overRideParams.Contains("IIS Web Application Name")) - { - $overRideParams = $overRideParams + [string]::Format('{0}name="IIS Web Application Name",value="{1}"', [System.Environment]::NewLine, $webSiteName) - } -} -$overRideParams = $overRideParams.Replace('"', '`"') -$msDeployScript = Get-Content ./MsDeployOnTargetMachines.ps1 | Out-String -$invokeMain = "Execute-Main -WebDeployPackage `"$webDeployPackage`" -WebDeployParamFile `"$webDeployParamFile`" -OverRideParams `"$overRideParams`" -WebSiteName `"$webSiteName`" -WebSitePhysicalPath `"$webSitePhysicalPath`" -WebSitePhysicalPathAuth `"$webSitePhysicalPathAuth`" -WebSiteAuthUserName `"$webSiteAuthUserName`" -WebSiteAuthUserPassword `"$webSiteAuthUserPassword`" -AddBinding $addBinding -AssignDuplicateBinding $assignDuplicateBinding -Protocol $protocol -IpAddress `"$ipAddress`" -Port $port -HostName `"$hostName`" -ServerNameIndication $serverNameIndication -SslCertThumbPrint `"$sslCertThumbPrint`" -AppPoolName `"$appPoolName`" -DotNetVersion `"$dotNetVersion`" -PipeLineMode $pipeLineMode -AppPoolIdentity $appPoolIdentity -AppPoolUsername `"$appPoolUsername`" -AppPoolPassword `"$appPoolPassword`" -AppCmdCommands `"$appCmdCommands`" -CreateWebSite $createWebSite -CreateAppPool $createAppPool" - -Write-Verbose "Executing main funnction in MsDeployOnTargetMachines : $invokeMain" -$msDeployOnTargetMachinesScript = [string]::Format("{0} {1} ( {2} )", $msDeployScript, [Environment]::NewLine, $invokeMain) -Write-Output ( Get-LocalizedString -Key "Starting deployment of IIS Web Deploy Package : {0}" -ArgumentList $webDeployPackage) - -$errorMessage = [string]::Empty - -if($resourceFilteringMethod -eq "tags") -{ - $errorMessage = Invoke-RemoteDeployment -environmentName $environmentName -tags $machineFilter -scriptBlockContent $msDeployOnTargetMachinesScript -runPowershellInParallel $deployInParallel -adminUserName $adminUserName -adminPassword $adminPassword -protocol $winrmProtocol -testCertificate $testCertificate -} -else -{ - $errorMessage = Invoke-RemoteDeployment -environmentName $environmentName -machineNames $machineFilter -scriptBlockContent $msDeployOnTargetMachinesScript -runPowershellInParallel $deployInParallel -adminUserName $adminUserName -adminPassword $adminPassword -protocol $winrmProtocol -testCertificate $testCertificate -} - -if(-not [string]::IsNullOrEmpty($errorMessage)) -{ - $readmelink = "https://aka.ms/iiswebappdeployreadme" - $helpMessage = (Get-LocalizedString -Key "For more info please refer to {0}" -ArgumentList $readmelink) - throw "$errorMessage $helpMessage" -} - -Write-Output ( Get-LocalizedString -Key "Successfully deployed IIS Web Deploy Package : {0}" -ArgumentList $webDeployPackage) \ No newline at end of file diff --git a/Tasks/IISWebAppDeployment/MsDeployOnTargetMachines.ps1 b/Tasks/IISWebAppDeployment/MsDeployOnTargetMachines.ps1 deleted file mode 100644 index 0f19c02774f2..000000000000 --- a/Tasks/IISWebAppDeployment/MsDeployOnTargetMachines.ps1 +++ /dev/null @@ -1,617 +0,0 @@ -Write-Verbose "Entering script MsDeployOnTargetMachines.ps1" -$AppCmdRegKey = "HKLM:\SOFTWARE\Microsoft\InetStp" -$MsDeployInstallPathRegKey = "HKLM:\SOFTWARE\Microsoft\IIS Extensions\MSDeploy" - -function Run-Command -{ - param( - [string]$command, - [bool] $failOnErr = $true - ) - - $ErrorActionPreference = 'Continue' - - if( $psversiontable.PSVersion.Major -le 4) - { - $result = cmd.exe /c "`"$command`"" - } - else - { - $result = cmd.exe /c "$command" - } - - $ErrorActionPreference = 'Stop' - - if($failOnErr -and $LASTEXITCODE -ne 0) - { - throw $result - } - - return $result -} - -function Get-MsDeployLocation -{ - param( - [Parameter(Mandatory=$true)] - [string]$regKeyPath - ) - - $msDeployNotFoundError = "Cannot find MsDeploy.exe location. Verify MsDeploy.exe is installed on $env:ComputeName and try operation again." - - if( -not (Test-Path -Path $regKeyPath)) - { - throw $msDeployNotFoundError - } - - $path = (Get-ChildItem -Path $regKeyPath | Select -Last 1).GetValue("InstallPath") - - if( -not (Test-Path -Path $path)) - { - throw $msDeployNotFoundError - } - - return (Join-Path $path msDeploy.exe) -} - -function Get-AppCmdLocation -{ - param( - [Parameter(Mandatory=$true)] - [string]$regKeyPath - ) - - $appCmdNotFoundError = "Cannot find appcmd.exe location. Verify IIS is configured on $env:ComputerName and try operation again." - $appCmdMinVersionError = "Version of IIS is less than 7.0 on machine $env:ComputerName. Minimum version of IIS required is 7.0" - - - if(-not (Test-Path -Path $regKeyPath)) - { - throw $appCmdNotFoundError - } - - $regKey = Get-ItemProperty -Path $regKeyPath - $path = $regKey.InstallPath - $version = $regKey.MajorVersion - - if($version -le 6.0) - { - throw $appCmdMinVersionError - } - - if( -not (Test-Path $path)) - { - throw $appCmdNotFoundError - } - - return (Join-Path $path appcmd.exe), $version -} - -function Get-MsDeployCmdArgs -{ - param( - [Parameter(Mandatory=$true)] - [string]$webDeployPackage, - [string]$webDeployParamFile, - [string]$overRideParams - ) - - if(-not ( Test-Path -Path $webDeployPackage)) - { - throw "Package does not exist : `"$webDeployPackage`"" - } - - $msDeployCmdArgs = [string]::Empty - if(-not [string]::IsNullOrWhiteSpace($webDeployParamFile)) - { - - if(-not ( Test-Path -Path $webDeployParamFile)) - { - throw "Param file does not exist : `"$webDeployParamFile`"" - } - - $msDeployCmdArgs = [string]::Format(' -setParamFile="{0}"', $webDeployParamFile) - } - - $setParams = $overRideParams.Split([System.Environment]::NewLine, [System.StringSplitOptions]::RemoveEmptyEntries) - foreach($setParam in $setParams) - { - $setParam = $setParam.Trim() - if(-not [string]::IsNullOrWhiteSpace($setParam)) - { - $msDeployCmdArgs = [string]::Format('{0} -setParam:{1}', $msDeployCmdArgs, $setParam) - } - } - - $msDeployCmdArgs = [string]::Format(' -verb:sync -source:package="{0}" {1} -dest:auto -verbose -retryAttempts:3 -retryInterval:3000', $webDeployPackage, $msDeployCmdArgs) - return $msDeployCmdArgs -} - -function Does-WebSiteExists -{ - param([string] $siteName) - - $appCmdPath, $iisVersion = Get-AppCmdLocation -regKeyPath $AppCmdRegKey - $appCmdArgs = [string]::Format(' list site /name:"{0}"',$siteName) - $command = "`"$appCmdPath`" $appCmdArgs" - Write-Verbose "Checking website exists. Running command : $command" - - $website = Run-Command -command $command -failOnErr $false - - if($website -ne $null) - { - Write-Verbose "Website (`"$siteName`") already exists" - return $true - } - - Write-Verbose "Website (`"$siteName`") does not exist" - return $false -} - -function Does-BindingExists -{ - param( - [string]$siteName, - [string]$protocol, - [string]$ipAddress, - [string]$port, - [string]$hostname, - [string]$assignDupBindings - ) - - $appCmdPath, $iisVersion = Get-AppCmdLocation -regKeyPath $AppCmdRegKey - $appCmdArgs = [string]::Format(' list sites') - $command = "`"$appCmdPath`" $appCmdArgs" - - Write-Verbose "Checking binding exists for website (`"$siteName`"). Running command : $command" - - $sites = Run-Command -command $command -failOnErr $false - $binding = [string]::Format("{0}/{1}:{2}:{3}", $protocol, $ipAddress, $port, $hostname) - - $isBindingExists = $false - - foreach($site in $sites) - { - switch($assignDupBindings) - { - $true - { - if($site.Contains($siteName) -and $site.Contains($binding)) - { - $isBindingExists = $true - } - } - default - { - if($site.Contains($siteName) -and $site.Contains($binding)) - { - $isBindingExists = $true - } - elseif($site.Contains($binding)) - { - throw "Binding already exists for website (`"$site`")" - } - } - } - } - - Write-Verbose "Does bindings exist for website (`"$siteName`") is : $isBindingExists" - return $isBindingExists -} - -function Does-AppPoolExists -{ - param( - [string]$appPoolName - ) - - $appCmdPath, $iisVersion = Get-AppCmdLocation -regKeyPath $AppCmdRegKey - $appCmdArgs = [string]::Format(' list apppool /name:"{0}"',$appPoolName) - $command = "`"$appCmdPath`" $appCmdArgs" - - Write-Verbose "Checking application exists. Running command : $command" - - $appPool = Run-Command -command $command -failOnErr $false - - if($appPool -ne $null) - { - Write-Verbose "Application Pool (`"$appPoolName`") already exists" - return $true - } - - Write-Verbose "Application Pool (`"$appPoolName`") does not exists" - return $false -} - -function Enable-SNI -{ - param( - [string]$siteName, - [string]$sni, - [string]$ipAddress, - [string]$port, - [string]$hostname - ) - - $appCmdPath, $iisVersion = Get-AppCmdLocation -regKeyPath $AppCmdRegKey - - if( -not ($sni -eq "true" -and $iisVersion -ge 8 -and -not [string]::IsNullOrWhiteSpace($hostname))) - { - Write-Verbose "Not enabling SNI : sni : $sni, iisVersion : $iisVersion, hostname : $hostname. Possible Reasons: `n 1. IIS Version is less than 8 `n 2. HostName input is not provided `n 3. SNI input is set to false" - return - } - - if($ipAddress -eq "All Unassigned") - { - $ipAddress = "*" - } - - $appCmdArgs = [string]::Format(' set site /site.name:{0} /bindings.[protocol=''https'',bindingInformation=''{1}:{2}:{3}''].sslFlags:"1"',$siteName, $ipAddress, $port, $hostname) - $command = "`"$appCmdPath`" $appCmdArgs" - - Write-Verbose "Enabling SNI by setting SslFlags=1 for binding. Running command : $command" - Run-Command -command $command -} - -function Add-SslCert -{ - param( - [string]$port, - [string]$certhash, - [string]$hostname, - [string]$sni, - [string]$iisVersion - ) - - if([string]::IsNullOrWhiteSpace($certhash)) - { - Write-Verbose "CertHash is empty .. returning" - return - } - - $result = $null - $isItSameBinding = $false - $addCertCmd = [string]::Empty - - #SNI is supported IIS 8 and above. To enable SNI hostnameport option should be used - if($sni -eq "true" -and $iisVersion -ge 8 -and -not [string]::IsNullOrWhiteSpace($hostname)) - { - $showCertCmd = [string]::Format("netsh http show sslcert hostnameport={0}:{1}", $hostname, $port) - Write-Verbose "Checking SslCert binding already Present. Running command : $showCertCmd" - - $result = Run-Command -command $showCertCmd -failOnErr $false - $isItSameBinding = $result.Get(4).Contains([string]::Format("{0}:{1}", $hostname, $port)) - - $addCertCmd = [string]::Format("netsh http add sslcert hostnameport={0}:{1} certhash={2} appid={{{3}}} certstorename=MY", $hostname, $port, $certhash, [System.Guid]::NewGuid().toString()) - } - else - { - $showCertCmd = [string]::Format("netsh http show sslcert ipport=0.0.0.0:{0}", $port) - Write-Verbose "Checking SslCert binding already Present. Running command : $showCertCmd" - - $result = Run-Command -command $showCertCmd -failOnErr $false - $isItSameBinding = $result.Get(4).Contains([string]::Format("0.0.0.0:{0}", $port)) - - $addCertCmd = [string]::Format("netsh http add sslcert ipport=0.0.0.0:{0} certhash={1} appid={{{2}}}", $port, $certhash, [System.Guid]::NewGuid().toString()) - } - - $isItSameCert = $result.Get(5).ToLower().Contains([string]::Format("{0}", $certhash.ToLower())) - - if($isItSameBinding -and $isItSameCert) - { - Write-Verbose "SSL cert binding already present.. returning" - return - } - - Write-Verbose "Setting SslCert for website." - Run-Command -command $addCertCmd -} - -function Deploy-WebSite -{ - param( - [string]$webDeployPkg, - [string]$webDeployParamFile, - [string]$overRiderParams - ) - - $msDeployExePath = Get-MsDeployLocation -regKeyPath $MsDeployInstallPathRegKey - $msDeployCmdArgs = Get-MsDeployCmdArgs -webDeployPackage $webDeployPkg -webDeployParamFile $webDeployParamFile -overRideParams $overRiderParams - - $msDeployCmd = "`"$msDeployExePath`" $msDeployCmdArgs" - Write-Verbose "Deploying website. Running command: $msDeployCmd" - Run-Command -command $msDeployCmd -} - -function Create-WebSite -{ - param( - [string]$siteName, - [string]$physicalPath - ) - - $appCmdPath, $iisVersion = Get-AppCmdLocation -regKeyPath $AppCmdRegKey - $appCmdArgs = [string]::Format(' add site /name:"{0}" /physicalPath:"{1}"',$siteName, $physicalPath) - $command = "`"$appCmdPath`" $appCmdArgs" - - Write-Verbose "Creating website. Running command : $command" - Run-Command -command $command -} - -function Create-AppPool -{ - param( - [string]$appPoolName - ) - - $appCmdPath, $iisVersion = Get-AppCmdLocation -regKeyPath $AppCmdRegKey - $appCmdArgs = [string]::Format(' add apppool /name:"{0}"', $appPoolName) - $command = "`"$appCmdPath`" $appCmdArgs" - - Write-Verbose "Creating application Pool. Running command : $command" - Run-Command -command $command -} - -function Run-AdditionalCommands -{ - param( - [string]$additionalCommands - ) - - $appCmdCommands = $additionalCommands.Trim('"').Split([System.Environment]::NewLine, [System.StringSplitOptions]::RemoveEmptyEntries) - $appCmdPath, $iisVersion = Get-AppCmdLocation -regKeyPath $AppCmdRegKey - - foreach($appCmdCommand in $appCmdCommands) - { - if(-not [string]::IsNullOrWhiteSpace($appCmdCommand.Trim(' '))) - { - $command = "`"$appCmdPath`" $appCmdCommand" - - Write-Verbose "Running additional command. $command" - Run-Command -command $command - } - } -} - -function Update-WebSite -{ - param( - [string]$siteName, - [string]$appPoolName, - [string]$physicalPath, - [string]$authType, - [string]$userName, - [string]$password, - [string]$addBinding, - [string]$protocol, - [string]$ipAddress, - [string]$port, - [string]$hostname, - [string]$assignDupBindings - ) - - $appCmdArgs = [string]::Format(' set site /site.name:"{0}"', $siteName) - - if(-not [string]::IsNullOrWhiteSpace($appPoolName)) - { - $appCmdArgs = [string]::Format('{0} -applicationDefaults.applicationPool:"{1}"', $appCmdArgs, $appPoolName) - } - - if(-not [string]::IsNullOrWhiteSpace($physicalPath)) - { - $appCmdArgs = [string]::Format("{0} -[path='/'].[path='/'].physicalPath:`"{1}`"", $appCmdArgs, $physicalPath) - } - - if(-not [string]::IsNullOrWhiteSpace($userName) -and $authType -eq "WebsiteWindowsAuth") - { - $appCmdArgs = [string]::Format("{0} -[path='/'].[path='/'].userName:{1}", $appCmdArgs, $userName) - } - - if(-not [string]::IsNullOrWhiteSpace($password) -and $authType -eq "WebsiteWindowsAuth") - { - $appCmdArgs = [string]::Format("{0} -[path='/'].[path='/'].password:{1}", $appCmdArgs, $password) - } - - if($ipAddress -eq "All Unassigned") - { - $ipAddress = "*" - } - - $isBindingExists = Does-BindingExists -siteName $siteName -protocol $protocol -ipAddress $ipAddress -port $port -hostname $hostname -assignDupBindings $assignDupBindings - - if($addBinding -eq "true" -and $isBindingExists -eq $false) - { - $appCmdArgs = [string]::Format("{0} /+bindings.[protocol='{1}',bindingInformation='{2}:{3}:{4}']", $appCmdArgs, $protocol, $ipAddress, $port, $hostname) - } - - $appCmdPath, $iisVersion = Get-AppCmdLocation -regKeyPath $AppCmdRegKey - $command = "`"$appCmdPath`" $appCmdArgs" - - Write-Verbose "Updating website properties. Running command : $command" - Run-Command -command $command -} - -function Update-AppPool -{ - param( - [string]$appPoolName, - [string]$clrVersion, - [string]$pipeLineMode, - [string]$identity, - [string]$userName, - [string]$password - ) - - $appCmdArgs = ' set config -section:system.applicationHost/applicationPools' - - if(-not [string]::IsNullOrWhiteSpace($clrVersion)) - { - $appCmdArgs = [string]::Format('{0} /[name=''"{1}"''].managedRuntimeVersion:{2}', $appCmdArgs, $appPoolName, $clrVersion) - } - - if(-not [string]::IsNullOrWhiteSpace($pipeLineMode)) - { - $appCmdArgs = [string]::Format('{0} /[name=''"{1}"''].managedPipelineMode:{2}', $appCmdArgs, $appPoolName, $pipeLineMode) - } - - if($identity -eq "SpecificUser" -and -not [string]::IsNullOrWhiteSpace($userName) -and -not [string]::IsNullOrWhiteSpace($password)) - { - $appCmdArgs = [string]::Format('{0} /[name=''"{1}"''].processModel.identityType:SpecificUser /[name=''"{1}"''].processModel.userName:"{2}" /[name=''"{1}"''].processModel.password:"{3}"',` - $appCmdArgs, $appPoolName, $userName, $password) - } - elseif ($identity -eq "SpecificUser" -and -not [string]::IsNullOrWhiteSpace($userName)) - { - $appCmdArgs = [string]::Format('{0} /[name=''"{1}"''].processModel.identityType:SpecificUser /[name=''"{1}"''].processModel.userName:"{2}"',` - $appCmdArgs, $appPoolName, $userName) - } - else - { - $appCmdArgs = [string]::Format('{0} /[name=''"{1}"''].processModel.identityType:{2}', $appCmdArgs, $appPoolName, $identity) - } - - $appCmdPath, $iisVersion = Get-AppCmdLocation -regKeyPath $AppCmdRegKey - $command = "`"$appCmdPath`" $appCmdArgs" - - Write-Verbose "Updating application pool properties. Running command : $command" - Run-Command -command $command -} - -function Create-And-Update-WebSite -{ - param( - [string]$siteName, - [string]$appPoolName, - [string]$physicalPath, - [string]$authType, - [string]$userName, - [string]$password, - [string]$addBinding, - [string]$protocol, - [string]$ipAddress, - [string]$port, - [string]$hostname, - [string]$assignDupBindings - ) - - $doesWebSiteExists = Does-WebSiteExists -siteName $siteName - - if( -not $doesWebSiteExists) - { - Create-WebSite -siteName $siteName -physicalPath $physicalPath - } - - Update-WebSite -siteName $siteName -appPoolName $appPoolName -physicalPath $physicalPath -authType $authType -userName $userName -password $password ` - -addBinding $addBinding -protocol $protocol -ipAddress $ipAddress -port $port -hostname $hostname -assignDupBindings $assignDupBindings -} - -function Create-And-Update-AppPool -{ - param( - [string]$appPoolName, - [string]$clrVersion, - [string]$pipeLineMode, - [string]$identity, - [string]$userName, - [string]$password - ) - - $doesAppPoolExists = Does-AppPoolExists -appPoolName $appPoolName - - if(-not $doesAppPoolExists) - { - Create-AppPool -appPoolName $appPoolName - } - - Update-AppPool -appPoolName $appPoolName -clrVersion $clrVersion -pipeLineMode $pipeLineMode -identity $identity -userName $userName -password $password -} - -function Execute-Main -{ - param ( - [string]$WebDeployPackage, - [string]$WebDeployParamFile, - [string]$OverRideParams, - [string]$CreateWebSite, - [string]$WebSiteName, - [string]$WebSitePhysicalPath, - [string]$WebSitePhysicalPathAuth, - [string]$WebSiteAuthUserName, - [string]$WebSiteAuthUserPassword, - [string]$AddBinding, - [string]$AssignDuplicateBinding, - [string]$Protocol, - [string]$IpAddress, - [string]$Port, - [string]$HostName, - [string]$ServerNameIndication, - [string]$SslCertThumbPrint, - [string]$CreateAppPool, - [string]$AppPoolName, - [string]$DotNetVersion, - [string]$PipeLineMode, - [string]$AppPoolIdentity, - [string]$AppPoolUsername, - [string]$AppPoolPassword, - [string]$AppCmdCommands - ) - - Write-Verbose "Entering Execute-Main function" - Write-Verbose "WebDeployPackage = $WebDeployPackage" - Write-Verbose "WebDeployParamFile = $WebDeployParamFile" - Write-Verbose "OverRideParams = $OverRideParams" - - Write-Verbose "CreateWebSite= $CreateWebSite" - Write-Verbose "WebSiteName = $WebSiteName" - Write-Verbose "WebSitePhysicalPath = $WebSitePhysicalPath" - Write-Verbose "WebSitePhysicalPathAuth = $WebSitePhysicalPathAuth" - Write-Verbose "WebSiteAuthUserName = $WebSiteAuthUserName" - Write-Verbose "WebSiteAuthUserPassword = $WebSiteAuthUserPassword" - Write-Verbose "AddBinding = $AddBinding" - Write-Verbose "AssignDuplicateBinding = $AssignDuplicateBinding" - Write-Verbose "Protocol = $Protocol" - Write-Verbose "IpAddress = $IpAddress" - Write-Verbose "Port = $Port" - Write-Verbose "HostName = $HostName" - Write-Verbose "ServerNameIndication = $ServerNameIndication" - - Write-Verbose "CreateAppPool = $CreateAppPool" - Write-Verbose "AppPoolName = $AppPoolName" - Write-Verbose "DotNetVersion = $DotNetVersion" - Write-Verbose "PipeLineMode = $PipeLineMode" - Write-Verbose "AppPoolIdentity = $AppPoolIdentity" - Write-Verbose "AppPoolUsername = $AppPoolUsername" - Write-Verbose "AppPoolPassword = $AppPoolPassword" - Write-Verbose "AppCmdCommands = $AppCmdCommands" - - if($CreateAppPool -ieq "true") - { - Create-And-Update-AppPool -appPoolName $AppPoolName -clrVersion $DotNetVersion -pipeLineMode $PipeLineMode -identity $AppPoolIdentity -userName $AppPoolUsername -password $AppPoolPassword - } - - if($CreateWebSite -ieq "true") - { - Create-And-Update-WebSite -siteName $WebSiteName -appPoolName $AppPoolName -physicalPath $WebSitePhysicalPath -authType $WebSitePhysicalPathAuth -userName $WebSiteAuthUserName ` - -password $WebSiteAuthUserPassword -addBinding $AddBinding -protocol $Protocol -ipAddress $IpAddress -port $Port -hostname $HostName -assignDupBindings $AssignDuplicateBinding - - if($Protocol -eq "https") - { - $appCmdPath, $iisVersion = Get-AppCmdLocation -regKeyPath $AppCmdRegKey - Add-SslCert -port $Port -certhash $SslCertThumbPrint -hostname $HostName -sni $ServerNameIndication -iisVersion $iisVersion - Enable-SNI -siteName $WebSiteName -sni $ServerNameIndication -ipAddress $IpAddress -port $Port -hostname $HostName - } - } - else - { - $doesWebSiteExists = Does-WebSiteExists -siteName $WebSiteName - if (-not $doesWebSiteExists) - { - Write-Verbose "Website does not exist and you did not request to create it - deployment might fail." - } - } - - Run-AdditionalCommands -additionalCommands $AppCmdCommands - - Deploy-WebSite -webDeployPkg $WebDeployPackage -webDeployParamFile $WebDeployParamFile -overRiderParams $OverRideParams - - Write-Verbose "Exiting Execute-Main function" -} diff --git a/Tasks/IISWebAppDeployment/README.md b/Tasks/IISWebAppDeployment/README.md deleted file mode 100644 index b474b448c437..000000000000 --- a/Tasks/IISWebAppDeployment/README.md +++ /dev/null @@ -1,110 +0,0 @@ -# IIS Web Application Deployment - -## **Important Notice** -The preview IIS Web Application Deployment task has been **deprecated and will be removed soon**. The task has been **shipped as an extension for Visual Studio Team Services**, and is available in the marketplace - https://marketplace.visualstudio.com/items?itemName=ms-vscs-rm.iiswebapp. - -**Install the extension, and add the tasks from the extension in Build or Release Definitions, and remove this IIS Web Application Deployment task from the definition.** - - -## Overview - -The task is used to deploy a web application or a website to IIS web server and to create or update websites and application pools, and the underlying technologies used by the task is [Web Deploy](https://www.iis.net/downloads/microsoft/web-deploy) and [AppCmd.exe](https://www.iis.net/learn/get-started/getting-started-with-iis/getting-started-with-appcmdexe). Web Deploy packages the web application content, configuration and any other artifacts like registry, GAC assemblies etc. that can be used deployment. If the package needs to be redeployed to a different environment, configuration values within the package can be parameterized during deployment without requiring modifications to the packages themselves. Web deploy works with IIS 7, IIS 7.5, IIS 8, and IIS 8.5. AppCmd.exe is the single command line tool for managing IIS 7 and above. It exposes all key server management functionality through a set of intuitive management objects that can be manipulated from the command line or from scripts. - -The task runs on the target machine(s) and it is important to have the pre-requisites, as described below, installed on the machine(s). The flow is that the automation agent when executing the task, connects to the target machine using the Windows Remote Management (WinRM), and then launches a bootstrap service, which in turn invokes the PowerShell scripts to locate the msdeploy.exe on the machine, and deploys the web application using the msdeploy.exe. - -## Contact Information - -Please contact the alias RM\_Customer\_Queries at microsoft dot com, if you are facing problems in making this task work. Also, if you would like to share feedback about the task and the new features that you would like to see in it, then do send an email to the alias. - -## Pre-requisites for the task - -The following pre-requisites need to be setup for the task to work properly. - -### Web Deploy - -Web Deploy (msdeploy.exe) is used to deploy the web application on the IIS server, and needs to be installed on the target machines, and can be easily done so using [Microsoft Web Platform Installer](https://www.microsoft.com/web/gallery/install.aspx?appid=wdeploynosmo). Note that the link will open Web PI with the Web Deploy showing-up ready to install. The WebDeploy 3.5 needs to be installed without the bundled SQL support and using the default settings. There is no need to choose any custom settings while installing web deploy. After installation the Web Deploy is available at C:\Program Files (x86)\IIS\Microsoft Web Deploy V3. The task [PowerShell on Target Machines](https://github.com/Microsoft/vsts-tasks/tree/master/Tasks/PowerShellOnTargetMachines) can be used to deploy Web Deploy to Azure virtual machines or domain-joined/workgroup machines. - -AppCmd.exe is an in-built command line tool of IIS and does not need to be separately installed. It is used to create or update websites and application pools. - -### IIS Web Server - -There should be a IIS web server already installed and configured on the pre-existing machines or virtual machines. The task creates or updates websites and application pools, and deploys IIS web applications but does not install or configure IIS web server on the machines. - -### Pre-existing Machine Groups - -If the web application is being deployed on pre-existing machines (physical or virtual machines) then a machine group has to be created in the Machines Hub. There is a manage link next to the Machine Group parameter of the task. Click on the link to navigate to the Machines Hub and create a machine group. Note that the IP Address or the FDQN of Azure virtual machines can be also added in the machine group. The difference between using the domain-joined/workgroup machines and the Azure virtual machines is that copying files to them uses separate tasks wiz. [Windows Machine File Copy](https://github.com/Microsoft/vsts-tasks/tree/master/Tasks/WindowsMachineFileCopy) for the domain-joined/workgroup machines and [Azure File Copy](https://github.com/Microsoft/vsts-tasks/tree/master/Tasks/AzureFileCopy) for the Azure virtual machines. Note that the IIS Web Application Deployment task expects the web application's package zip files to be available on the machines or on a UNC path that is accessible by the machine administrator's login. Prior to using the IIS Web Application Deployment task ensure that the zip files are available for the deployment by copying them to the machines using the Windows Machine File Copy or the Azure File Copy tasks. - -### WinRM setup -This task uses the [Windows Remote Management](https://msdn.microsoft.com/en-us/library/aa384426.aspx) (WinRM) to access domain-joined or workgroup, on-premises physical or virtual machines. - -#### Windows Remote Management (WinRM) Setup for On-premises Physical or Virtual Machines -To easily **setup WinRM** on the **host machines** follow the directions for [domain-joined machines](https://www.visualstudio.com/en-us/docs/release/examples/other-servers/net-to-vm) or the [workgroup machines](https://www.visualstudio.com/en-us/docs/release/examples/other-servers/net-to-workgroup-vm). - -#### Windows Remote Management (WinRM) Setup for Azure Virtual Machines -Azure virtual machines only work with the WinRM HTTPS protocol. With the WinRM protocol selected as HTTPS, you have an option to use the Test Certificate. Selecting the Test Certificate option means that the certificate is a self-signed certificate, and the automation agent will skip validating the authenticity of the machine's certificate from a trusted certification authority. - -- **Classic Virtual machines:** When creating [classic virtual machine](https://azure.microsoft.com/en-us/documentation/articles/virtual-machines-windows-tutorial-classic-portal/) from the [new Azure portal](https://portal.azure.com/) or the [classic Azure portal](https://manage.windowsazure.com/), the virtual machine is already setup for WinRM HTTPS, with the default port 5986 already open in Firewall, and a self-signed certificate installed on the machine. These virtual machines can be directly added to the WinRM. The existing [classic virtual machine](https://azure.microsoft.com/en-us/documentation/articles/virtual-machines-windows-tutorial-classic-portal/) can be also selected by using the [Azure Resource Group Deployment task](https://github.com/Microsoft/vso-agent-tasks/tree/master/Tasks/DeployAzureResourceGroup). - -- **• Azure Resource Group:** If an [Azure resource group](https://azure.microsoft.com/en-us/documentation/articles/virtual-machines-windows-hero-tutorial/) has been created in the [new Azure portal](https://portal.azure.com/), then it needs to be setup for the WinRM HTTPS protocol (WinRM HTTPS, with the default port 5986 already open in Firewall, and a self-signed certificate installed on the machine). To dynamically deploy Azure resource groups with virtual machines in them use the [Azure Resource Group Deployment task](https://github.com/Microsoft/vso-agent-tasks/tree/master/Tasks/DeployAzureResourceGroup). The task has a checkbox titled - **Enable Deployment Pre-requisites**. Select this option to setup the WinRM HTTPS protocol on the virtual machines, and to open the 5986 port in the Firewall, and to install the test certificate. After this the virtual machines are ready for use in the deployment task. - -## Parameters of the task - -The task can be used to deploy a web application to an existing website in the IIS web server using web deploy, and it can be also used for creating new IIS website and application pools, or to update existing ones. The task has three sections and the parameters of the different sections are described in detail below. The parameters listed with a \* are required parameters for the task. - -The task first creates/updates the application pool, then creates/updates the websites, then applies the additional App.Cmd.exe commands, and then deploys the web application to the website using the web deploy. The application pool, website, and the additional AppCmd.exe sections are optional and if none of them are provided, then the task directly deploys the web application to the IIS website. - -### Deploy IIS Web Application -This section of the task is used to deploy the web application to an existing IIS website and uses Web Deploy to do so. - - - **Machines**: Specify comma separated list of machine FQDNs/ip addresses along with port(optional). For example dbserver.fabrikam.com, dbserver_int.fabrikam.com:5986,192.168.34:5986. Port when not specified will be defaulted to WinRM defaults based on the specified protocol. i.e., (For *WinRM 2.0*): The default HTTP port is 5985, and the default HTTPS port is 5986. Machines field also accepts 'Machine Groups' defined under 'Test' hub, 'Machines' tab. - - **Admin Login**: Domain/Local administrator of the target host. Format: <Domain or hostname>\ < Admin User>. Mandatory when used with list of machines, optional for Test Machine Group (will override test machine group value when specified). - - **Password**: Password for the admin login. It can accept variable defined in Build/Release definitions as '$(passwordVariable)'. You may mark variable type as 'secret' to secure it. Mandatory when used with list of machines, optional for Test Machine Group (will override test machine group value when specified). - - **Protocol**: Specify the protocol that will be used to connect to target host, either HTTP or HTTPS. - - **Test Certificate**: Select the option to skip validating the authenticity of the machine's certificate by a trusted certification authority. The parameter is required for the WinRM HTTPS protocol. - - **Web Deploy Package\*:** Location of the web deploy zip package file on the target machine or on a UNC path that is accessible to the administrator credentials of the machine like, \\\\BudgetIT\Web\Deploy\FabrikamWeb.zip. Environment variables are also supported like $env:windir, $env:systemroot etc. For example, $env:windir\FabrikamFibre\Web. - - **Web Deploy Parameters File:** The parameter file is used to override the default settings in the web deploy zip package file like, the IIS Web application name or the database connection string. This helps in having a single package that can be deployed across dev, test, staging, and production, with a specific parameter file for each environment. The parameter takes in the location of the parameter file on the target machines or on a UNC path. - - **Override Parameters:** Parameters specified here will override the parameters in the MSDeploy zip file and the Parameter file. The format followed here is same as that for [setParam](https://technet.microsoft.com/en-us/library/dd569084(v=ws.10).aspx) option of MsDeploy.exe. For example, name="IIS Web Application Name",value="Fabrikam/MyApplication" - -### Website -The section of the task is used to create a new IIS website or to update an existing one by using the IIS Server's AppCmd.exe command line tool. For more information about the parameters see the [websites](https://technet.microsoft.com/library/hh831681.aspx#Add_Site) page on MSDN. - - - **Create or Update Website:** Select this option to create a new website or to update an existing one. - - **Website Name\*:** The name of the IIS website that will be created if it does not exist, or it will be updated if it is already present on the IIS server. The name of the website should be same as that specified in the web deploy zip package file. If a Parameter file and override Parameters setting is also specified, then the name of the website should be same as that in the override Parameters setting. - - **Physical Path\*:** Physical path where the website content is stored. The content can reside on the local computer or on a remote directory or share like, C:\Fabrikam or \\ContentShare\Fabrikam - - **Physical Path Authentication\*:** Specify credentials to connect to the physical path. If credentials are not provided, the web server uses pass-through authentication. This means that content is accessed by using the application user's identity, and configuration files are accessed by using the application pool's identity. By default, Application user (pass-through authentication) is selected. - - **Username:** If Windows authentication is selected in the physical path authentication, then provide the username for accessing the physical path. - - **Password:** Password of the user to access the physical path. - - **Add Binding:** Select the option to add bindings for the website. - - **Assign Duplicate Binding:** Selecting this option will add the bindings specified here, even if there is another website with the same bindings. If there are binding conflicts, then only one of the website will start. - - **Protocol:** Select HTTP for the website to have an HTTP binding, or select HTTPS for the website to have a Secure Sockets Layer (SSL) binding. - - **IP Address:** Type an IP address that users can use to access this website. If All Unassigned is selected, the site will respond to requests for all IP addresses on the port and the optional host name that is specified for this site, unless there is another site on the server that has a binding on the same port but with a specific IP address. For example, the default website binding specifies All Unassigned for IP address, and 80 for Port, and no host name. If the server has a second site named Fabrikam with a binding that specifies 172.30.189.132 for IP address on port 80 and no host name, Contoso receives all HTTP requests to port 80 on IP address 172.30.189.132, and the default website continues to receive HTTP requests to port 80 on any IP address other than 172.30.189.132. - - **Port:** Type the port on which Hypertext Transfer Protocol Stack (HTTP.sys) must listen for requests made to this website. The default port for HTTP is 80 and for HTTPS it is 443. If any other port is specified, apart from the default ports, clients must specify the port number in requests to the server or they will not be able to connect to the website. - - **Host Name:** To assign one or more host names (aka domain names) to a computer that uses a single IP address, type a host name here. If a host name is specified, then the clients must use the host name instead of the IP address to access the website. - - **Server Name Indication Required:** Determines whether the website requires Server Name Indication (SNI). SNI extends the SSL and TLS protocols to indicate what host name the client is attempting to connect to. It allows multiple secure websites with different certificates to use the same IP address. The checkbox is displayed when the binding type is HTTPS. This parameter only works with IIS 8 and later versions of IIS. If SNI is selected, then host name should be also specified - - **SSL Certificate Thumbprint:** Thumbprint of the Secure Socket Layer certificate that the website is going to use. The certificate should be already installed on the machine and present under the Local Computer, Personal store. - -### Application Pool -The section is used to create a new IIS application pool or to update an existing one by using the IIS Server's AppCmd.exe command line tool. For more information about the parameters see the [application pools](https://technet.microsoft.com/library/hh831797.aspx) page on MSDN. - - - **Create or Update Application Pool:** Select this option to create a new application pool or to update an existing one. - - **Name\*:** The name of the IIS application pool that will be created if it does not exist, or it will be updated if it is already present on the IIS server. The name of the application pool should be same as that specified in the web deploy zip package file. If a Parameter file and override Parameters setting is also specified, then the name of the application pool should be same as that in the override Parameters setting. - - **.NET Version\*:** Version of the .NET Framework that is loaded by this application pool. If the applications assigned to this application pool do not contain managed code, select the No Managed Code option from the list. - - **Managed Pipeline Mode\*:** Managed pipeline mode specifies how IIS processes requests for managed content. Use classic mode only when the applications in the application pool cannot run in the Integrated mode. - - **Identity\*:** Configure the account under which an application pool's worker process runs. Select one of the predefined security accounts or configure a custom account. - -### Advanced -The section provides for advanced options. - - - **Additional AppCmd.exe Commands:** Additional [AppCmd.exe](https://technet.microsoft.com/en-us/library/cc732107(v=ws.10).aspx) commands to set website or application pool properties. For more than one command use line separator. For example: - - ```c - set config /section:applicationPools /[name='Fabrikam'].autoStart:false - add site /name:fabrikam /bindings:http/\*:85: fabrikam.com. - ``` - - - **Deploy in Parallel:** Setting it to true will run the database deployment task in-parallel on the target machines. - -## Known Issues - - - The IIS Web Application Deployment task does not provide support for Web Deploy manifest files and has not been tested and verified for ASP.NET 5 and MVC 6 web application. Please send us feedback for the task and for the support for manifest files, ASP.NET 5/MVC 6 we applications at RM\_Customer\_Queries at microsoft dot com. - - The Override Parameters can take only one parameter based on the [setParam](https://technet.microsoft.com/en-us/library/dd569084(v=ws.10).aspx) option of MsDeploy.exe diff --git a/Tasks/IISWebAppDeployment/Strings/resources.resjson/de-de/resources.resjson b/Tasks/IISWebAppDeployment/Strings/resources.resjson/de-de/resources.resjson deleted file mode 100644 index 6981ecc078e5..000000000000 --- a/Tasks/IISWebAppDeployment/Strings/resources.resjson/de-de/resources.resjson +++ /dev/null @@ -1,79 +0,0 @@ -{ - "loc.friendlyName": "[Veraltet] IIS-Web-App-Bereitstellung", - "loc.helpMarkDown": "[More Information](https://aka.ms/iiswebappdeployreadme)", - "loc.description": "Bereitstellen durch MSDeploy, Erstellen/Aktualisieren der Website und App-Pools.", - "loc.instanceNameFormat": "[Veraltet] IIS-App bereitstellen: $(WebDeployPackage)", - "loc.group.displayName.deployment": "Bereitstellung", - "loc.group.displayName.website": "Website", - "loc.group.displayName.applicationPool": "Anwendungspool", - "loc.group.displayName.advanced": "Erweitert", - "loc.input.label.EnvironmentName": "Computer", - "loc.input.help.EnvironmentName": "Stellen Sie eine durch Kommas getrennte Liste der IP-Computeradressen oder FQDNs zusammen mit den Ports bereit. Die Standardeinstellung für den Port basiert auf dem ausgewählten Protokoll.
Beispiel: \"dbserver.fabrikam.com,dbserver_int.fabrikam.com:5986,192.168.12.34:5986\"
Sie können auch die Ausgabevariable anderer Tasks angeben. Beispiel: \"$(variableName)\".", - "loc.input.label.AdminUserName": "Administratoranmeldung", - "loc.input.help.AdminUserName": "Die Administratoranmeldung für die Zielcomputer.", - "loc.input.label.AdminPassword": "Kennwort", - "loc.input.help.AdminPassword": "Das Administratorkennwort für die Zielcomputer.
Es kann die Variable annehmen, die in Build-/Releasedefinitionen als\"$(passwordVariable)\" definiert wird.
Sie können den Variablentyp als \"secret\" markieren, um die Variable zu sichern. ", - "loc.input.label.WinRMProtocol": "Protokoll", - "loc.input.help.WinRMProtocol": "Wählen Sie das Protokoll aus, das für die WinRM-Verbindung mit dem Computer bzw. den Computern verwendet werden soll. Der Standardwert ist HTTPS.", - "loc.input.label.TestCertificate": "Testzertifikat", - "loc.input.help.TestCertificate": "Wählen Sie die Option aus, um die Überprüfung der Authentizität des Zertifikats des Computers durch eine vertrauenswürdige Zertifizierungsstelle zu überspringen. Der Parameter ist für das WinRM HTTPS-Protokoll erforderlich.", - "loc.input.label.WebDeployPackage": "Web Deploy-Paket", - "loc.input.help.WebDeployPackage": "Der Speicherort der Web Deploy-ZIP-Datei (MSDeploy) auf den Zielcomputern oder in einem UNC-Pfad (z. B. \"\\\\\\\\BudgetIT\\WebDeploy\\WebDeployPackage.zip\"). Auf den UNC-Pfad sollte über das Administratorkonto des Computers zugegriffen werden können. Umgebungsvariablen werden ebenfalls unterstützt. Beispiel: \"$env:windir\", \"$env:systemroot – \"$env:windir\\FabrikamFibre\\Web\".", - "loc.input.label.WebDeployParamFile": "Web Deploy-Parameterdatei", - "loc.input.help.WebDeployParamFile": "Der Speicherort der Parameterdatei auf dem Zielcomputer oder in einem UNC-Pfad. Die Parameterdatei wird zum Außerkraftsetzen der Konfigurationseinstellungen der Webanwendung (z. B. des Namens der IIS-Webanwendung oder der Datenbankverbindungszeichenfolge) verwendet.", - "loc.input.label.OverRideParams": "Parameter außer Kraft setzen", - "loc.input.help.OverRideParams": "Hier angegebenen Parameter überschreiben die Parameter in der MSDeploy-ZIP-Datei und in der Parameterdatei. Wenn mehrere Parameter überschrieben werden sollen, verwenden Sie Zeilentrennzeichen, z. B.
\"IIS Web Application Name\"=\"Fabrikam\"
\"ConnectionString\"=\"Server=localhost;Database=Fabrikam;\"", - "loc.input.label.CreateWebSite": "Website erstellen oder aktualisieren", - "loc.input.help.CreateWebSite": "Wählen Sie diese Option aus, um eine Website zu erstellen oder eine vorhandene Website zu aktualisieren.", - "loc.input.label.WebSiteName": "Websitename", - "loc.input.help.WebSiteName": "Der Name der IIS-Website, die erstellt werden soll, wenn sie nicht vorhanden ist, oder die aktualisiert wird, wenn sie auf dem IIS-Server bereits vorhanden ist. Der Name der Website sollte mit dem in der Web Deploy-ZIP-Paketdatei angegebenen Namen identisch sein. Wenn eine Parameterdatei und eine Einstellung zum Überschreiben von Parametern ebenfalls angegeben werden, sollte der Name der Website identisch mit der Einstellung zum Überschreiben von Parametern sein.", - "loc.input.label.WebSitePhysicalPath": "Physischer Pfad", - "loc.input.help.WebSitePhysicalPath": "Der physische Pfad, unter dem der Websiteinhalt gespeichert ist. Der Inhalt kann sich auf dem lokalen Computer, in einem Remoteverzeichnis oder auf einer Freigabe befinden. Beispiel: \"C:\\Fabrikam\" oder \"\\\\\\\\ContentShare\\Fabrikam\".", - "loc.input.label.WebSitePhysicalPathAuth": "Authentifizierung des physischen Pfads", - "loc.input.help.WebSitePhysicalPathAuth": "Der Authentifizierungsmechanismus für den Zugriff auf den physischen Pfad der Website.", - "loc.input.label.WebSiteAuthUserName": "Benutzername", - "loc.input.help.WebSiteAuthUserName": "Der Benutzername für den Zugriff auf den physischen Pfad der Website.", - "loc.input.label.WebSiteAuthUserPassword": "Kennwort", - "loc.input.help.WebSiteAuthUserPassword": "Das Kennwort für den Zugriff auf den physischen Pfad der Website. Wenn Sie gMSA verwenden, ist dieses nicht erforderlich.", - "loc.input.label.AddBinding": "Bindung hinzufügen", - "loc.input.help.AddBinding": "Wählen Sie diese Option aus, um eine Portbindung für die Website hinzuzufügen.", - "loc.input.label.AssignDuplicateBinding": "Doppelte Bindung zuweisen", - "loc.input.help.AssignDuplicateBinding": "Wählen Sie die Option aus, um die hier angegebenen Bindungen selbst dann hinzuzufügen, wenn eine andere Website mit den gleichen Bindungen vorhanden ist. Wenn Bindungskonflikte auftreten, wird nur eine der Websites gestartet.", - "loc.input.label.Protocol": "Protokoll", - "loc.input.help.Protocol": "Wählen Sie HTTP für die Website aus, um eine HTTP-Bindung zu verwenden, oder HTTPS, um eine HTTPS-Bindung (Secure Sockets Layer) zu verwenden.", - "loc.input.label.IPAddress": "IP-Adresse", - "loc.input.help.IPAddress": "Geben Sie eine IP-Adresse ein, die Benutzer für den Zugriff auf diese Website verwenden können. Wenn \"Alle nicht zugewiesen\" ausgewählt ist, antwortet die Website auf Anforderungen für alle IP-Adressen für den Port und den optionalen Hostnamen, der für diese Website angegeben wurde. Dies ist nur dann nicht der Fall, wenn eine andere Website auf dem Server eine Bindung am gleichen Port mit einer bestimmten IP-Adresse besitzt.", - "loc.input.label.Port": "Port", - "loc.input.help.Port": "Geben Sie den Port ein, an dem \"HTTP.sys\" (Hypertext Transfer Protocol Stack) auf Anforderungen dieser Website lauschen muss.", - "loc.input.label.ServerNameIndication": "Die Angabe des Servernamens ist erforderlich.", - "loc.input.help.ServerNameIndication": "Ermittelt, ob für die Website SNI (Server Name Indication, Servernamensanzeige) erforderlich ist. SNI erweitert die SSL- und TLS-Protokolle so, dass der Hostname angegeben wird, mit dem der Client versucht, eine Verbindung herzustellen. Mehrere sichere Websites mit verschiedenen Zertifikaten können die gleiche IP-Adresse verwenden.", - "loc.input.label.HostNameWithOutSNI": "Hostname", - "loc.input.help.HostNameWithOutSNI": "Wenn Sie einem Computer, der eine einzelne IP-Adresse verwendet, mindestens einen Hostnamen (oder Domänennamen) zuweisen möchten, geben Sie hier einen Hostnamen ein. Wenn ein Hostname angegeben wird, müssen Clients den Hostnamen anstelle der IP-Adresse für den Zugriff auf die Website verwenden.", - "loc.input.label.HostNameWithHttp": "Hostname", - "loc.input.help.HostNameWithHttp": "Wenn Sie einem Computer, der eine einzelne IP-Adresse verwendet, mindestens einen Hostnamen (oder Domänennamen) zuweisen möchten, geben Sie hier einen Hostnamen ein. Wenn ein Hostname angegeben wird, müssen Clients den Hostnamen anstelle der IP-Adresse für den Zugriff auf die Website verwenden.", - "loc.input.label.HostNameWithSNI": "Hostname", - "loc.input.help.HostNameWithSNI": "Wenn Sie einem Computer, der eine einzelne IP-Adresse verwendet, mindestens einen Hostnamen (oder Domänennamen) zuweisen möchten, geben Sie hier einen Hostnamen ein. Wenn ein Hostname angegeben wird, müssen Clients den Hostnamen anstelle der IP-Adresse für den Zugriff auf die Website verwenden.", - "loc.input.label.SSLCertThumbPrint": "Fingerabdruck des SSL-Zertifikats", - "loc.input.help.SSLCertThumbPrint": "Der Fingerabdruck des SSL-Zertifikats, das die Website verwenden wird. Das Zertifikat sollte bereits auf dem Computer installiert und im lokalen persönlichen Speicher des Computers vorhanden sein.", - "loc.input.label.CreateAppPool": "Anwendungspool erstellen oder aktualisieren", - "loc.input.help.CreateAppPool": "Wählen Sie die Option aus, um einen Anwendungspool zu erstellen oder einen vorhandenen Anwendungspool zu aktualisieren.", - "loc.input.label.AppPoolName": "Name", - "loc.input.help.AppPoolName": "Der Name des IIS-Anwendungspools, der erstellt oder aktualisiert werden soll. Ein vorhandener Anwendungspool wird mit den hier angegebenen Einstellungen aktualisiert.", - "loc.input.label.DotNetVersion": ".NET-Version", - "loc.input.help.DotNetVersion": "Die Version von .NET Framework, die von diesem Anwendungspool geladen wird. Wenn die Anwendung, die diesem Anwendungspool zugewiesen ist, keinen verwalteten Code enthält, wählen Sie die Option \"Kein verwalteter Code\" aus der Liste aus.", - "loc.input.label.PipeLineMode": "Verwalteter Pipelinemodus", - "loc.input.help.PipeLineMode": "Der verwaltete Pipelinemodus gibt an, wie IIS Anforderungen für verwalteten Inhalt verarbeitet. Verwenden Sie den klassischen Modus nur, wenn die Anwendung im Anwendungspool nicht im integrierten Modus ausgeführt werden kann.", - "loc.input.label.AppPoolIdentity": "Identität", - "loc.input.help.AppPoolIdentity": "Konfigurieren Sie das Konto, unter dem der Arbeitsprozess eines Anwendungspools ausgeführt wird. Wählen Sie eines der vordefinierten Sicherheitskonten aus, oder konfigurieren Sie ein benutzerdefiniertes Konto.", - "loc.input.label.AppPoolUsername": "Benutzername", - "loc.input.label.AppPoolPassword": "Kennwort", - "loc.input.help.AppPoolPassword": "Wenn Sie gMSA verwenden, ist dies nicht erforderlich.", - "loc.input.label.AppCmdCommands": "Weitere AppCmd.exe-Befehle", - "loc.input.help.AppCmdCommands": "Zusätzliche AppCmd.exe-Befehle zum Festlegen von Website- oder Anwendungspooleigenschaften. Verwenden Sie für mehrere Befehle Zeilentrennzeichen. Beispiel:
\"list apppools\"
\"list sites\"", - "loc.input.label.DeployInParallel": "Parallel bereitstellen", - "loc.input.help.DeployInParallel": "Wenn diese Option auf \"true\" festgelegt wird, wird die Webanwendung parallel auf den Zielcomputern bereitgestellt.", - "loc.input.label.ResourceFilteringMethod": "Computer auswählen nach", - "loc.input.help.ResourceFilteringMethod": "Wählen Sie optional eine Teilmenge der Computer durch Angeben von Computernamen oder Tags aus.", - "loc.input.label.MachineFilter": "Auf Computern bereitstellen", - "loc.input.help.MachineFilter": "Diese Eingabe ist nur gültig für Computergruppen und wird noch nicht für flache Listen von Computern oder Ausgabevariablen unterstützt. Geben Sie eine Liste von Computern (z. B. \"dbserver.fabrikam.com\", \"webserver.fabrikam.com\", \"192.168.12.34\") oder Tags (z. B. \"Role:DB\", \"OS:Win8.1\") an. Wenn mehrere Tags angegeben werden, wird der Task auf allen Computern mit den angegebenen Tags ausgeführt. Geben Sie für Azure-Ressourcengruppen den Namen der virtuellen Maschine an, z. B. \"ffweb\" oder \"ffdb\". Standardmäßig wird der Task auf allen Computern ausgeführt." -} \ No newline at end of file diff --git a/Tasks/IISWebAppDeployment/Strings/resources.resjson/en-US/resources.resjson b/Tasks/IISWebAppDeployment/Strings/resources.resjson/en-US/resources.resjson deleted file mode 100644 index 886500a88b87..000000000000 --- a/Tasks/IISWebAppDeployment/Strings/resources.resjson/en-US/resources.resjson +++ /dev/null @@ -1,79 +0,0 @@ -{ - "loc.friendlyName": "[Deprecated] IIS Web App Deployment", - "loc.helpMarkDown": "[More Information](https://aka.ms/iiswebappdeployreadme)", - "loc.description": "Deploy by MSDeploy, create/update website & app pools", - "loc.instanceNameFormat": "[Deprecated] Deploy IIS App: $(WebDeployPackage)", - "loc.group.displayName.deployment": "Deployment", - "loc.group.displayName.website": "Website", - "loc.group.displayName.applicationPool": "Application Pool", - "loc.group.displayName.advanced": "Advanced", - "loc.input.label.EnvironmentName": "Machines", - "loc.input.help.EnvironmentName": "Provide a comma separated list of machine IP addresses or FQDNs along with ports. Port is defaulted based on the selected protocol.
Eg: dbserver.fabrikam.com,dbserver_int.fabrikam.com:5986,192.168.12.34:5986
Or provide output variable of other tasks. Eg: $(variableName)", - "loc.input.label.AdminUserName": "Admin Login", - "loc.input.help.AdminUserName": "Administrator login for the target machines.", - "loc.input.label.AdminPassword": "Password", - "loc.input.help.AdminPassword": "Administrator password for the target machines.
It can accept variable defined in Build/Release definitions as '$(passwordVariable)'.
You may mark variable type as 'secret' to secure it. ", - "loc.input.label.WinRMProtocol": "Protocol", - "loc.input.help.WinRMProtocol": "Select the protocol to use for the WinRM connection with the machine(s). Default is HTTPS.", - "loc.input.label.TestCertificate": "Test Certificate", - "loc.input.help.TestCertificate": "Select the option to skip validating the authenticity of the machine's certificate by a trusted certification authority. The parameter is required for the WinRM HTTPS protocol.", - "loc.input.label.WebDeployPackage": "Web Deploy Package", - "loc.input.help.WebDeployPackage": "Location of the Web Deploy (MSDeploy) zip file on the target machines or on a UNC path like, \\\\\\\\BudgetIT\\WebDeploy\\WebDeployPackage.zip. The UNC path should be accessible to the machine's administrator account. Environment variables are also supported like, $env:windir, $env:systemroot, like, $env:windir\\FabrikamFibre\\Web.", - "loc.input.label.WebDeployParamFile": "Web Deploy Parameter File", - "loc.input.help.WebDeployParamFile": "Location of the Parameter file on the target machines or on a UNC path. Parameter file is used to override Web application configuration settings like, IIS Web application name or database connection string.", - "loc.input.label.OverRideParams": "Override Parameters", - "loc.input.help.OverRideParams": "Parameters specified here will override the parameters in the MSDeploy zip file and the Parameter file. To override more than one parameter use line separator, e.g.,
\"IIS Web Application Name\"=\"Fabrikam\"
\"ConnectionString\"=\"Server=localhost;Database=Fabrikam;\"", - "loc.input.label.CreateWebSite": "Create or Update Website", - "loc.input.help.CreateWebSite": "Select the option to create a website or to update an existing website.", - "loc.input.label.WebSiteName": "Website Name", - "loc.input.help.WebSiteName": "Name of the IIS website that will be created if it does not exist, or it will be updated if it is already present on the IIS server. The name of the website should be same as that specified in the web deploy zip package file. If a Parameter file and override Parameters setting is also specified, then the name of the website should be same as that in the override Parameters setting.", - "loc.input.label.WebSitePhysicalPath": "Physical Path", - "loc.input.help.WebSitePhysicalPath": "Physical path where the website content is stored. The content can reside on the local computer or on a remote directory or share like, C:\\Fabrikam or \\\\\\\\ContentShare\\Fabrikam.", - "loc.input.label.WebSitePhysicalPathAuth": "Physical Path Authentication", - "loc.input.help.WebSitePhysicalPathAuth": "Authentication mechanism for accessing the physical path of the website.", - "loc.input.label.WebSiteAuthUserName": "User Name", - "loc.input.help.WebSiteAuthUserName": "User name for accessing the website's physical path.", - "loc.input.label.WebSiteAuthUserPassword": "Password", - "loc.input.help.WebSiteAuthUserPassword": "Password for accessing the website's physical path. If you are using a gMSA, this is not required.", - "loc.input.label.AddBinding": "Add Binding", - "loc.input.help.AddBinding": "Select the option to add port binding for the website.", - "loc.input.label.AssignDuplicateBinding": "Assign Duplicate Binding", - "loc.input.help.AssignDuplicateBinding": "Select the option to add the bindings specified here, even if there is another website with the same bindings. If there are binding conflicts, then only one of the website will start.", - "loc.input.label.Protocol": "Protocol", - "loc.input.help.Protocol": "Select HTTP for the website to have an HTTP binding, or select HTTPS for the website to have a Secure Sockets Layer (SSL) binding.", - "loc.input.label.IPAddress": "IP Address", - "loc.input.help.IPAddress": "Type an IP address that users can use to access this website. If All Unassigned is selected, the site will respond to requests for all IP addresses on the port and the optional host name that is specified for this site, unless another site on the server has a binding on the same port but with a specific IP address.", - "loc.input.label.Port": "Port", - "loc.input.help.Port": "Type the port on which Hypertext Transfer Protocol Stack (HTTP.sys) must listen for requests made to this website.", - "loc.input.label.ServerNameIndication": "Server Name Indication Required", - "loc.input.help.ServerNameIndication": "Determines whether the website requires Server Name Indication (SNI). SNI extends the SSL and TLS protocols to indicate what host name the client is attempting to connect to. It allows multiple secure websites with different certificates to use the same IP address.", - "loc.input.label.HostNameWithOutSNI": "Host Name", - "loc.input.help.HostNameWithOutSNI": "To assign one or more host names (or domain names) to a computer that uses a single IP address, type a host name here. If a host name is specified then the clients must use the host name instead of the IP address to access the website.", - "loc.input.label.HostNameWithHttp": "Host Name", - "loc.input.help.HostNameWithHttp": "To assign one or more host names (or domain names) to a computer that uses a single IP address, type a host name here. If a host name is specified then the clients must use the host name instead of the IP address to access the website.", - "loc.input.label.HostNameWithSNI": "Host Name", - "loc.input.help.HostNameWithSNI": "To assign one or more host names (or domain names) to a computer that uses a single IP address, type a host name here. If a host name is specified then the clients must use the host name instead of the IP address to access the website.", - "loc.input.label.SSLCertThumbPrint": "SSL Certificate Thumb Print", - "loc.input.help.SSLCertThumbPrint": "Thumb-print of the Secure Socket Layer certificate that the website is going to use. The certificate should be already installed on the machine and present under the Local Computer, Personal store.", - "loc.input.label.CreateAppPool": "Create or Update Application Pool", - "loc.input.help.CreateAppPool": "Select the option to create an application pool or to update an existing application pool.", - "loc.input.label.AppPoolName": "Name", - "loc.input.help.AppPoolName": "Name of the IIS application pool to create or update. Existing application pool will be updated with the settings specified here.", - "loc.input.label.DotNetVersion": ".NET Version", - "loc.input.help.DotNetVersion": "Version of the .NET Framework that is loaded by this application pool. If the applications assigned to this application pool do not contain managed code, select the No Managed Code option from the list.", - "loc.input.label.PipeLineMode": "Managed Pipeline Mode", - "loc.input.help.PipeLineMode": "Managed pipeline mode specifies how IIS processes requests for managed content. Use classic mode only when the applications in the application pool cannot run in the Integrated mode.", - "loc.input.label.AppPoolIdentity": "Identity", - "loc.input.help.AppPoolIdentity": "Configure the account under which an application pool's worker process runs. Select one of the predefined security accounts or configure a custom account.", - "loc.input.label.AppPoolUsername": "Username", - "loc.input.label.AppPoolPassword": "Password", - "loc.input.help.AppPoolPassword": "If you are using a gMSA, this is not required.", - "loc.input.label.AppCmdCommands": "Additional AppCmd.exe Commands", - "loc.input.help.AppCmdCommands": "Additional AppCmd.exe commands to set website or application pool properties. For more than one command use line separator, e.g.,
list apppools
list sites", - "loc.input.label.DeployInParallel": "Deploy in Parallel", - "loc.input.help.DeployInParallel": "Setting it to true will deploy the Web application in-parallel on the target machines.", - "loc.input.label.ResourceFilteringMethod": "Select Machines By", - "loc.input.help.ResourceFilteringMethod": "Optionally, select a subset of machines either by providing machine names or tags.", - "loc.input.label.MachineFilter": "Deploy to Machines", - "loc.input.help.MachineFilter": "This input is valid only for machine groups and is not supported for flat list of machines or output variables yet. Provide a list of machines like, dbserver.fabrikam.com, webserver.fabrikam.com, 192.168.12.34, or tags like, Role:DB; OS:Win8.1. If multiple tags are provided, then the task will run in all the machines with the specified tags. For Azure Resource Groups, provide the virtual machine's name like, ffweb, ffdb. The default is to run the task in all machines." -} \ No newline at end of file diff --git a/Tasks/IISWebAppDeployment/Strings/resources.resjson/es-es/resources.resjson b/Tasks/IISWebAppDeployment/Strings/resources.resjson/es-es/resources.resjson deleted file mode 100644 index 0ef82c67b924..000000000000 --- a/Tasks/IISWebAppDeployment/Strings/resources.resjson/es-es/resources.resjson +++ /dev/null @@ -1,79 +0,0 @@ -{ - "loc.friendlyName": "[En desuso] Implementación de la aplicación web de IIS", - "loc.helpMarkDown": "[More Information](https://aka.ms/iiswebappdeployreadme)", - "loc.description": "Implementar con MSDeploy, crear o actualizar el sitio web y los grupos de aplicaciones", - "loc.instanceNameFormat": "[En desuso] Implementar aplicación de IIS: $(WebDeployPackage)", - "loc.group.displayName.deployment": "Implementación", - "loc.group.displayName.website": "Sitio web", - "loc.group.displayName.applicationPool": "Grupo de aplicaciones", - "loc.group.displayName.advanced": "Avanzado", - "loc.input.label.EnvironmentName": "Equipos", - "loc.input.help.EnvironmentName": "Proporcione una lista separada por comas de direcciones IP de equipos o nombres de dominio completos junto con puertos. El puerto se establece de manera predeterminada en función del protocolo seleccionado.
Ejemplo: dbserver.fabrikam.com,dbserver_int.fabrikam.com:5986,192.168.12.34:5986
O bien proporcione la variable de salida de otras tareas. Ejemplo: $(nombreDeVariable)", - "loc.input.label.AdminUserName": "Inicio de sesión del administrador", - "loc.input.help.AdminUserName": "Inicio de sesión del administrador para los equipos de destino.", - "loc.input.label.AdminPassword": "Contraseña", - "loc.input.help.AdminPassword": "Contraseña del administrador para las máquinas de destino.
Admite la variable declarada en las definiciones de compilación o versión como \"$(passwordVariable)\".
Para proteger la variable, puede marcar el tipo como \"secret\". ", - "loc.input.label.WinRMProtocol": "Protocolo", - "loc.input.help.WinRMProtocol": "Seleccione el protocolo que se usará para la conexión WinRM con los equipos. El valor predeterminado es HTTPS.", - "loc.input.label.TestCertificate": "Certificado de prueba", - "loc.input.help.TestCertificate": "Seleccione la opción para omitir la validación de la autenticidad del certificado del equipo por parte de una entidad de certificación de confianza. El parámetro es obligatorio para el protocolo HTTPS de WinRM.", - "loc.input.label.WebDeployPackage": "Paquete de Web Deploy", - "loc.input.help.WebDeployPackage": "Ubicación del archivo zip de Web Deploy (MSDeploy) en las máquinas de destino o en una ruta de acceso UNC, como \\\\\\\\BudgetIT\\WebDeploy\\WebDeployPackage.zip. La ruta de acceso UNC debe ser accesible para la cuenta del administrador de la máquina. También se admiten variables de entorno, como $env:windir o $env:systemroot, por ejemplo, en $env:windir\\FabrikamFibre\\Web.", - "loc.input.label.WebDeployParamFile": "Archivo de parámetros de Web Deploy", - "loc.input.help.WebDeployParamFile": "Ubicación del archivo de parámetros en las máquinas de destino o en una ruta de acceso UNC. El archivo de parámetros se usa para reemplazar opciones de configuración de aplicaciones web tales como el nombre de aplicación web IIS o la cadena de conexión de base de datos.", - "loc.input.label.OverRideParams": "Parámetros de reemplazo", - "loc.input.help.OverRideParams": "Los parámetros que se especifiquen aquí reemplazarán a los parámetros del archivo zip de MSDeploy y del archivo de parámetros. Para reemplazar más de un parámetro, utilice el separador de líneas, por ejemplo,
\"Nombre de aplicación web de IIS\"=\"Fabrikam\"
\"ConnectionString\"=\"Server=localhost;Database=Fabrikam;\"", - "loc.input.label.CreateWebSite": "Crear o actualizar sitio web", - "loc.input.help.CreateWebSite": "Seleccione la opción para crear un sitio web o actualizar un sitio web existente.", - "loc.input.label.WebSiteName": "Nombre del sitio web", - "loc.input.help.WebSiteName": "Nombre del sitio web que se va a crear si no existe, o que se actualizará si ya está presente en el servidor IIS. El nombre del sitio web debe ser el mismo que el que se especificó en el archivo del paquete zip de implementación web. Si también se especifica un archivo de parámetros y la configuración de los parámetros de reemplazo, el nombre del sitio web debe ser igual que en la configuración de parámetros de reemplazo.", - "loc.input.label.WebSitePhysicalPath": "Ruta de acceso física", - "loc.input.help.WebSitePhysicalPath": "Ruta de acceso física donde se almacena el contenido del sitio web. El contenido puede residir en el equipo local o en un directorio o recurso compartido remoto, como C:\\Fabrikam o \\\\\\\\ContentShare\\Fabrikam.", - "loc.input.label.WebSitePhysicalPathAuth": "Autenticación de ruta de acceso física", - "loc.input.help.WebSitePhysicalPathAuth": "Mecanismo de autenticación para acceder a la ruta de acceso física del sitio web.", - "loc.input.label.WebSiteAuthUserName": "Nombre de usuario", - "loc.input.help.WebSiteAuthUserName": "Nombre de usuario para acceder a la ruta de acceso física del sitio web.", - "loc.input.label.WebSiteAuthUserPassword": "Contraseña", - "loc.input.help.WebSiteAuthUserPassword": "Contraseña para acceder a la ruta de acceso física del sitio web. Si usa gMSA, esto no es necesario.", - "loc.input.label.AddBinding": "Agregar enlace", - "loc.input.help.AddBinding": "Seleccione la opción para agregar enlace de puerto al sitio web.", - "loc.input.label.AssignDuplicateBinding": "Asignar enlace duplicado", - "loc.input.help.AssignDuplicateBinding": "Seleccione la opción para agregar los enlaces especificados aquí, incluso si hay otro sitio web con los mismos enlaces. Si hay conflictos de enlace, solo se iniciará uno de los sitios web.", - "loc.input.label.Protocol": "Protocolo", - "loc.input.help.Protocol": "Seleccione HTTP para que el sitio web tenga un enlace HTTP o seleccione HTTPS para que el sitio web tenga un enlace SSL (Capa de sockets seguros).", - "loc.input.label.IPAddress": "Dirección IP", - "loc.input.help.IPAddress": "Escriba una dirección IP que los usuarios puedan usar para acceder al sitio web. Si se selecciona Todas las no asignadas, el sitio responderá a las solicitudes de todas las direcciones IP del puerto y el nombre de host opcional que se especifique para este sitio, a menos que otro sitio del servidor tenga un enlace al mismo puerto pero con una dirección IP específica.", - "loc.input.label.Port": "Puerto", - "loc.input.help.Port": "Escriba el puerto en el que la pila del Protocolo de transferencia de hipertexto (HTTP.sys) debe escuchar las solicitudes efectuadas a este sitio web.", - "loc.input.label.ServerNameIndication": "Se requiere indicación de nombre de servidor", - "loc.input.help.ServerNameIndication": "Determina si el sitio web requiere Indicación de nombre de servidor (SNI). SNI extiende los protocolos SSL y TLS para indicar el nombre de host al que el cliente intenta conectarse. Permite que sitios web seguros con certificados diferentes usen la misma dirección IP.", - "loc.input.label.HostNameWithOutSNI": "Nombre de host", - "loc.input.help.HostNameWithOutSNI": "Para asignar uno o más nombres de host (o nombres de dominio) a un equipo que usa una sola dirección IP, escriba aquí un nombre de host. Si se especifica un nombre de host, los clientes deben usar este nombre y no la dirección IP para acceder al sitio web.", - "loc.input.label.HostNameWithHttp": "Nombre de host", - "loc.input.help.HostNameWithHttp": "Para asignar uno o más nombres de host (o nombres de dominio) a un equipo que usa una sola dirección IP, escriba aquí un nombre de host. Si se especifica un nombre de host, los clientes deben usar este nombre y no la dirección IP para acceder al sitio web.", - "loc.input.label.HostNameWithSNI": "Nombre de host", - "loc.input.help.HostNameWithSNI": "Para asignar uno o más nombres de host (o nombres de dominio) a un equipo que usa una sola dirección IP, escriba aquí un nombre de host. Si se especifica un nombre de host, los clientes deben usar este nombre y no la dirección IP para acceder al sitio web.", - "loc.input.label.SSLCertThumbPrint": "Huella digital del certificado SSL", - "loc.input.help.SSLCertThumbPrint": "Huella digital del certificado de Capa de sockets seguros que el sitio web va a usar. El certificado debe estar ya instalado en la máquina y presente en el almacén personal del equipo local.", - "loc.input.label.CreateAppPool": "Crear o actualizar grupo de aplicaciones", - "loc.input.help.CreateAppPool": "Seleccione la opción para crear un grupo de aplicaciones o actualizar un grupo de aplicaciones existente.", - "loc.input.label.AppPoolName": "Nombre", - "loc.input.help.AppPoolName": "Nombre del grupo de aplicaciones de IIS que se quiere crear o actualizar. El grupo de aplicaciones existente se actualizará con la configuración que se establezca aquí.", - "loc.input.label.DotNetVersion": "Versión de .NET", - "loc.input.help.DotNetVersion": "Versión de .NET Framework que se carga con este grupo de aplicaciones. Si las aplicaciones asignadas al grupo no contienen código administrado, seleccione en la lista la opción Sin código administrado.", - "loc.input.label.PipeLineMode": "Modo de canalización administrada", - "loc.input.help.PipeLineMode": "El modo de canalización administrada especifica cómo procesa IIS las solicitudes de contenido administrado. Use el modo clásico solo cuando las aplicaciones del grupo de aplicaciones no se puedan ejecutar en el modo integrado.", - "loc.input.label.AppPoolIdentity": "Identidad", - "loc.input.help.AppPoolIdentity": "Configure la cuenta en la que se ejecuta el proceso de trabajo de un grupo de aplicaciones. Seleccione una de las cuentas de seguridad predefinidas o configure una cuenta personalizada.", - "loc.input.label.AppPoolUsername": "Nombre de usuario", - "loc.input.label.AppPoolPassword": "Contraseña", - "loc.input.help.AppPoolPassword": "Si usa gMSA, esto no es necesario.", - "loc.input.label.AppCmdCommands": "Comandos adicionales de AppCmd.exe", - "loc.input.help.AppCmdCommands": "Comandos adicionales de AppCmd.exe para establecer propiedades de sitios web o grupos de aplicaciones. Para más de un comando, use separadores de líneas, p. ej.,
list apppools
list sites", - "loc.input.label.DeployInParallel": "Implementar en paralelo", - "loc.input.help.DeployInParallel": "Si se establece en true, la aplicación web se implementará en paralelo en las máquinas de destino.", - "loc.input.label.ResourceFilteringMethod": "Seleccionar máquinas por", - "loc.input.help.ResourceFilteringMethod": "También puede seleccionar un subconjunto de máquinas especificando nombres de máquina o etiquetas.", - "loc.input.label.MachineFilter": "Implementar en las máquinas", - "loc.input.help.MachineFilter": "Esta entrada solo es válida para los grupos de máquinas y no se admite para una lista plana de máquinas o de variables de salida. Proporcione una lista de máquinas (como dbserver.fabrikam.com, webserver.fabrikam.com o 192.168.12.34) o etiquetas (como Role:DB; OS:Win8.1). Si se proporcionan varias etiquetas, la tarea se ejecutará en todas las máquinas que tengan las etiquetas especificadas. Para los grupos de recursos de Azure, proporcione el nombre de la máquina virtual, como ffweb o ffdb. La opción predeterminada es ejecutar la tarea en todas las máquinas." -} \ No newline at end of file diff --git a/Tasks/IISWebAppDeployment/Strings/resources.resjson/fr-fr/resources.resjson b/Tasks/IISWebAppDeployment/Strings/resources.resjson/fr-fr/resources.resjson deleted file mode 100644 index ef9ee6cc6700..000000000000 --- a/Tasks/IISWebAppDeployment/Strings/resources.resjson/fr-fr/resources.resjson +++ /dev/null @@ -1,79 +0,0 @@ -{ - "loc.friendlyName": "[Déconseillé] Déploiement d'applications web IIS", - "loc.helpMarkDown": "[More Information](https://aka.ms/iiswebappdeployreadme)", - "loc.description": "Effectuer le déploiement avec MSDeploy, créer/mettre à jour un site web et un pool d'applications", - "loc.instanceNameFormat": "[Déconseillé] Déployer une application IIS : $(WebDeployPackage)", - "loc.group.displayName.deployment": "Déploiement", - "loc.group.displayName.website": "Site web", - "loc.group.displayName.applicationPool": "Pool d'applications", - "loc.group.displayName.advanced": "Avancé", - "loc.input.label.EnvironmentName": "Ordinateurs", - "loc.input.help.EnvironmentName": "Indiquez une liste séparée par des virgules d'adresses IP ou de noms de domaine complets d'ordinateurs ainsi que les ports. Le port par défaut dépend du protocole sélectionné.
Exemple : dbserver.fabrikam.com,dbserver_int.fabrikam.com:5986,192.168.12.34:5986
Ou indiquez une variable de sortie d'autres tâches. Exemple : $(variableName)", - "loc.input.label.AdminUserName": "Informations de connexion d'administrateur", - "loc.input.help.AdminUserName": "Informations de connexion d'administrateur pour les machines cibles.", - "loc.input.label.AdminPassword": "Mot de passe", - "loc.input.help.AdminPassword": "Mot de passe d'administrateur pour les machines cibles.
Il peut accepter une variable définie dans les définitions Build/Release sous la forme '$(passwordVariable)'.
Vous pouvez marquer le type de variable en tant que 'secret' pour renforcer sa sécurité. ", - "loc.input.label.WinRMProtocol": "Protocole", - "loc.input.help.WinRMProtocol": "Sélectionnez le protocole à utiliser pour la connexion WinRM avec les machines. La valeur par défaut est HTTPS.", - "loc.input.label.TestCertificate": "Certificat de test", - "loc.input.help.TestCertificate": "Sélectionnez l'option pour ignorer l'étape de validation de l'authenticité du certificat de l'ordinateur par une autorité de certification approuvée. Le paramètre est requis pour le protocole HTTPS WinRM.", - "loc.input.label.WebDeployPackage": "Package Web Deploy", - "loc.input.help.WebDeployPackage": "Emplacement du fichier zip Web Deploy (MSDeploy) sur les ordinateurs cibles ou dans un chemin d'accès UNC tel que \\\\\\\\BudgetIT\\WebDeploy\\WebDeployPackage.zip. Le chemin d'accès UNC doit être accessible au compte Administrateur de l'ordinateur. Les variables d'environnement sont également prises en charge, par exemple, $env:windir, $env:systemroot ou $env:windir\\FabrikamFibre\\Web.", - "loc.input.label.WebDeployParamFile": "Fichier de paramètres Web Deploy", - "loc.input.help.WebDeployParamFile": "Emplacement du fichier de paramètres sur les ordinateurs cibles ou dans un chemin d'accès UNC. Utilisez le fichier de paramètres pour remplacer les paramètres de configuration d'une application web, tels que le nom de l'application web IIS ou la chaîne de connexion de base de données.", - "loc.input.label.OverRideParams": "Remplacer les paramètres", - "loc.input.help.OverRideParams": "Les paramètres spécifiés ici remplacent les paramètres définis dans le fichier zip MSDeploy et le fichier Parameter. Pour remplacer plusieurs paramètres, utilisez le séparateur de ligne. Exemple :
\"IIS Web Application Name\"=\"Fabrikam\"
\"ConnectionString\"=\"Server=localhost;Database=Fabrikam;\"", - "loc.input.label.CreateWebSite": "Créer ou mettre à jour un site web", - "loc.input.help.CreateWebSite": "Sélectionnez l'option pour créer un site web ou mettre à jour un site web existant.", - "loc.input.label.WebSiteName": "Nom du site web", - "loc.input.help.WebSiteName": "Nom du site web IIS qui sera créé s'il n'existe pas ou qui sera mis à jour s'il est déjà présent sur le serveur IIS. Le nom du site web doit être identique à celui spécifié dans le fichier de package zip de déploiement web. Si un fichier de paramètres et des valeurs de remplacement des paramètres sont également spécifiés, le nom du site web doit être identique à celui spécifié dans les valeurs de remplacement des paramètres.", - "loc.input.label.WebSitePhysicalPath": "Chemin d'accès physique", - "loc.input.help.WebSitePhysicalPath": "Chemin d'accès physique où est stocké le contenu du site web. Le contenu peut résider sur l'ordinateur local ou dans un répertoire ou partage distant, tel que C:\\Fabrikam ou \\\\\\\\ContentShare\\Fabrikam.", - "loc.input.label.WebSitePhysicalPathAuth": "Authentification du chemin d'accès physique", - "loc.input.help.WebSitePhysicalPathAuth": "Mécanisme d'authentification pour accéder au chemin d'accès physique du site web.", - "loc.input.label.WebSiteAuthUserName": "Nom d'utilisateur", - "loc.input.help.WebSiteAuthUserName": "Nom d'utilisateur permettant d'accéder au chemin d'accès physique du site web.", - "loc.input.label.WebSiteAuthUserPassword": "Mot de passe", - "loc.input.help.WebSiteAuthUserPassword": "Mot de passe permettant d'accéder au chemin physique du site web. Si vous utilisez un gMSA, ce n'est pas obligatoire.", - "loc.input.label.AddBinding": "Ajouter une liaison", - "loc.input.help.AddBinding": "Sélectionnez l'option permettant d'ajouter une liaison de port pour le site web.", - "loc.input.label.AssignDuplicateBinding": "Assigner une liaison dupliquée", - "loc.input.help.AssignDuplicateBinding": "Sélectionnez l'option pour ajouter les liaisons spécifiées ici, même si un autre site web contient les mêmes liaisons. En cas de conflit entre les liaisons, un seul site web démarre.", - "loc.input.label.Protocol": "Protocole", - "loc.input.help.Protocol": "Sélectionnez HTTP pour assigner une liaison HTTP au site web, ou HTTPS pour lui assigner une liaison SSL (Secure Sockets Layer).", - "loc.input.label.IPAddress": "Adresse IP", - "loc.input.help.IPAddress": "Tapez une adresse IP avec laquelle les utilisateurs peuvent accéder à ce site web. Si l'option \"Non assignée\" est sélectionnée, le site répond aux demandes pour toutes les adresses IP sur le port et pour le nom d'hôte facultatif spécifié pour ce site, sauf si un autre site sur le serveur a une liaison sur le même port, mais avec une adresse IP spécifique.", - "loc.input.label.Port": "Port", - "loc.input.help.Port": "Tapez le numéro du port sur lequel la pile HTTP (HTTP.sys) doit écouter les demandes effectuées à ce site web.", - "loc.input.label.ServerNameIndication": "Indication du nom du serveur (SNI) requise", - "loc.input.help.ServerNameIndication": "Détermine si le site web nécessite l'indication du nom du serveur (SNI). SNI étend les protocoles SSL et TLS pour indiquer le nom d'hôte auquel le client tente de se connecter. Cette fonctionnalité permet à plusieurs sites web sécurisés ayant des certificats différents d'utiliser la même adresse IP.", - "loc.input.label.HostNameWithOutSNI": "Nom de l'hôte", - "loc.input.help.HostNameWithOutSNI": "Pour assigner un ou plusieurs noms d'hôte (ou noms de domaine) à un ordinateur utilisant une seule adresse IP, tapez un nom d'hôte ici. Si un nom d'hôte est spécifié, les clients doivent utiliser ce nom à la place de l'adresse IP pour accéder au site web.", - "loc.input.label.HostNameWithHttp": "Nom de l'hôte", - "loc.input.help.HostNameWithHttp": "Pour assigner un ou plusieurs noms d'hôte (ou noms de domaine) à un ordinateur utilisant une seule adresse IP, tapez un nom d'hôte ici. Si un nom d'hôte est spécifié, les clients doivent utiliser ce nom à la place de l'adresse IP pour accéder au site web.", - "loc.input.label.HostNameWithSNI": "Nom de l'hôte", - "loc.input.help.HostNameWithSNI": "Pour assigner un ou plusieurs noms d'hôte (ou noms de domaine) à un ordinateur utilisant une seule adresse IP, tapez un nom d'hôte ici. Si un nom d'hôte est spécifié, les clients doivent utiliser ce nom à la place de l'adresse IP pour accéder au site web.", - "loc.input.label.SSLCertThumbPrint": "Empreinte numérique du certificat SSL", - "loc.input.help.SSLCertThumbPrint": "Empreinte numérique du certificat SSL (Secure Socket Layer) utilisé par le site web. Le certificat doit être déjà installé sur l'ordinateur et disponible dans le magasin personnel de l'ordinateur local.", - "loc.input.label.CreateAppPool": "Créer ou mettre à jour un pool d'applications", - "loc.input.help.CreateAppPool": "Sélectionnez l'option pour créer un pool d'applications ou mettre à jour un pool d'applications existant.", - "loc.input.label.AppPoolName": "Nom", - "loc.input.help.AppPoolName": "Nom du pool d'applications IIS à créer ou à mettre à jour. Le pool d'applications existant sera mis à jour avec les paramètres spécifiés ici.", - "loc.input.label.DotNetVersion": "Version de .NET", - "loc.input.help.DotNetVersion": "Version du .NET Framework qui est chargé par ce pool d'applications. Si les applications assignées à ce pool d'applications ne contiennent pas de code managé, sélectionnez l'option \"Aucun code managé\" dans la liste.", - "loc.input.label.PipeLineMode": "Mode pipeline géré", - "loc.input.help.PipeLineMode": "Le mode pipeline géré spécifie de quelle manière les processus IIS demandent le contenu géré. Utilisez le mode Classique uniquement quand les applications du pool d'applications ne peuvent pas s'exécuter en mode Intégré.", - "loc.input.label.AppPoolIdentity": "Identité", - "loc.input.help.AppPoolIdentity": "Configurez le compte sous lequel est exécuté le processus de travail d'un pool d'applications. Sélectionnez l'un des comptes de sécurité prédéfinis ou configurez un compte personnalisé.", - "loc.input.label.AppPoolUsername": "Nom d'utilisateur", - "loc.input.label.AppPoolPassword": "Mot de passe", - "loc.input.help.AppPoolPassword": "Si vous utilisez un gMSA, ceci n'est pas obligatoire.", - "loc.input.label.AppCmdCommands": "Commandes AppCmd.exe supplémentaires", - "loc.input.help.AppCmdCommands": "Commandes AppCmd.exe supplémentaires pour définir les propriétés d'un site web ou d'un pool d'applications. Pour spécifier plusieurs commandes, utilisez un séparateur de ligne, par exemple,
liste poolsapplications
liste sites", - "loc.input.label.DeployInParallel": "Déployer en parallèle", - "loc.input.help.DeployInParallel": "Si la valeur est true, l'application web est déployée en parallèle sur les machines cibles.", - "loc.input.label.ResourceFilteringMethod": "Sélectionner les machines par", - "loc.input.help.ResourceFilteringMethod": "Vous pouvez également sélectionner un sous-ensemble de machines en spécifiant les noms des machines ou les balises associées.", - "loc.input.label.MachineFilter": "Déployer sur les ordinateurs", - "loc.input.help.MachineFilter": "Cette entrée est valide uniquement pour les groupes de machines. Elle n'est pas encore prise en charge pour une liste plate de machines ou de variables de sortie. Indiquez une liste de machines, par exemple dbserver.fabrikam.com, webserver.fabrikam.com, 192.168.12.34, ou utilisez des balises telles que Role:DB; OS:Win8.1. Si plusieurs balises sont indiquées, la tâche s'exécute sur toutes les machines correspondant aux balises spécifiées. Pour les groupes de ressources Azure, indiquez le nom de la machine virtuelle, par exemple ffweb, ffdb. Par défaut, la tâche s'exécute sur toutes les machines." -} \ No newline at end of file diff --git a/Tasks/IISWebAppDeployment/Strings/resources.resjson/it-IT/resources.resjson b/Tasks/IISWebAppDeployment/Strings/resources.resjson/it-IT/resources.resjson deleted file mode 100644 index 3eadc1737b8d..000000000000 --- a/Tasks/IISWebAppDeployment/Strings/resources.resjson/it-IT/resources.resjson +++ /dev/null @@ -1,79 +0,0 @@ -{ - "loc.friendlyName": "[Deprecata] Distribuzione app Web IIS", - "loc.helpMarkDown": "[More Information](https://aka.ms/iiswebappdeployreadme)", - "loc.description": "Consente di distribuire con MSDeploy e di creare/aggiornare il sito Web e i pool di applicazioni", - "loc.instanceNameFormat": "[Deprecata] Distribuisci app IIS: $(WebDeployPackage)", - "loc.group.displayName.deployment": "Distribuzione", - "loc.group.displayName.website": "Sito Web", - "loc.group.displayName.applicationPool": "Pool di applicazioni", - "loc.group.displayName.advanced": "Avanzate", - "loc.input.label.EnvironmentName": "Computer", - "loc.input.help.EnvironmentName": "Consente di specificare un elenco di indirizzi IP o FQDN separati da virgola unitamente alle porte. Per impostazione predefinita, la porta è basata sul protocollo selezionato.
Esempio: dbserver.fabrikam.com,dbserver_int.fabrikam.com:5986,192.168.12.34:5986
In alternativa, consente di specificare la variabile di output di altre attività. Esempio: $(variableName)", - "loc.input.label.AdminUserName": "Account di accesso amministratore", - "loc.input.help.AdminUserName": "Account di accesso dell'amministratore per i computer di destinazione.", - "loc.input.label.AdminPassword": "Password", - "loc.input.help.AdminPassword": "Password dell'amministratore per i computer di destinazione.
Accetta la variabile definita nelle definizioni di compilazione/versione come '$(passwordVariable)'.
Per proteggerla, è possibile contrassegnare il tipo di variabile come 'secret'. ", - "loc.input.label.WinRMProtocol": "Protocollo", - "loc.input.help.WinRMProtocol": "Consente di selezionare il protocollo da usare per la connessione WinRM con i computer. Il valore predefinito è HTTPS.", - "loc.input.label.TestCertificate": "Certificato di test", - "loc.input.help.TestCertificate": "Consente di selezionare l'opzione per ignorare la convalida dell'autenticità del certificato del computer da parte di un'Autorità di certificazione attendibile. Il parametro è obbligatorio per il protocollo HTTPS di WinRM.", - "loc.input.label.WebDeployPackage": "Pacchetto Distribuzione Web", - "loc.input.help.WebDeployPackage": "Percorso del file ZIP di Distribuzione Web (MSDeploy) nei computer di destinazione o in un percorso UNC, ad esempio \\\\\\\\BudgetIT\\WebDeploy\\WebDeployPackage.zip. Il percorso UNC deve essere accessibile all'account Administrator del computer. Sono supportate anche variabili di ambiente come $env:windir, $env:systemroot, $env:windir\\FabrikamFibre\\Web.", - "loc.input.label.WebDeployParamFile": "File di parametri Distribuzione Web", - "loc.input.help.WebDeployParamFile": "Percorso del file dei parametri nei computer di destinazione o in un percorso UNC. Il file dei parametri viene usato per sostituire le impostazioni di configurazione dell'applicazione Web, ad esempio il nome dell'applicazione Web IIS o la stringa della connessione di database.", - "loc.input.label.OverRideParams": "Parametri di sostituzione", - "loc.input.help.OverRideParams": "I parametri specificati qui sostituiscono quelli nel file ZIP di MSDeploy e nel file dei parametri. Per eseguire l'override di più parametri, usare il separatore di riga, ad esempio
\"IIS Web Application Name\"=\"Fabrikam\"
\"ConnectionString\"=\"Server=localhost;Database=Fabrikam;\"", - "loc.input.label.CreateWebSite": "Crea o aggiorna sito Web", - "loc.input.help.CreateWebSite": "Consente di selezionare l'opzione per creare un sito Web o aggiornarne uno esistente.", - "loc.input.label.WebSiteName": "Nome del sito Web", - "loc.input.help.WebSiteName": "Nome del sito Web IIS che verrà creato se non esiste o verrà aggiornato se è già presente nel server IIS. Il nome del sito Web deve essere uguale a quello specificato nel file del pacchetto ZIP di Distribuzione Web. Se si specificano anche un file di parametri e un'impostazione per i parametri di sostituzione, il nome del sito Web deve essere uguale a quello dell'impostazione dei parametri di sostituzione.", - "loc.input.label.WebSitePhysicalPath": "Percorso fisico", - "loc.input.help.WebSitePhysicalPath": "Percorso fisico in cui è archiviato il contenuto del sito Web. Il contenuto può risiedere nel computer locale oppure in una directory o condivisione remota, ad esempio C:\\Fabrikam o \\\\\\\\ContentShare\\Fabrikam.", - "loc.input.label.WebSitePhysicalPathAuth": "Autenticazione del percorso fisico", - "loc.input.help.WebSitePhysicalPathAuth": "Meccanismo di autenticazione per accedere al percorso fisico del sito Web.", - "loc.input.label.WebSiteAuthUserName": "Nome utente", - "loc.input.help.WebSiteAuthUserName": "Nome utente per accedere al percorso fisico del sito Web.", - "loc.input.label.WebSiteAuthUserPassword": "Password", - "loc.input.help.WebSiteAuthUserPassword": "Password per accedere al percorso fisico del sito Web. Se si usa un account del servizio gestito del gruppo, non è necessario immettere questo valore.", - "loc.input.label.AddBinding": "Aggiungi binding", - "loc.input.help.AddBinding": "Selezionare l'opzione per aggiungere il binding delle porte per il sito Web.", - "loc.input.label.AssignDuplicateBinding": "Assegna binding duplicato", - "loc.input.help.AssignDuplicateBinding": "Consente di selezionare l'opzione per aggiungere i binding specificati qui, anche se è presente un altro sito Web con gli stessi binding. In presenza di conflitti di binding, verrà avviato solo quello del sito Web.", - "loc.input.label.Protocol": "Protocollo", - "loc.input.help.Protocol": "Selezionare HTTP o HTTPS per impostare rispettivamente un binding HTTP o SSL (Secure Sockets Layer) per il sito Web.", - "loc.input.label.IPAddress": "Indirizzo IP", - "loc.input.help.IPAddress": "Digitare un indirizzo IP che gli utenti possono usare per accedere a questo sito Web. Se è selezionato Tutti non assegnati, il sito risponderà alle richieste relative a tutti gli indirizzi IP sulla porta e al nome host facoltativo specificato per questo sito, a meno che nel server non sia presente un altro sito con un binding sulla stessa porta ma con un indirizzo IP specifico.", - "loc.input.label.Port": "Porta", - "loc.input.help.Port": "Digitare il numero della porta su cui Hypertext Transfer Protocol Stack (HTTP.sys) deve rimanere in ascolto delle richieste effettuate a questo sito Web.", - "loc.input.label.ServerNameIndication": "Indicazione nome server obbligatoria", - "loc.input.help.ServerNameIndication": "Determina se il sito Web richiede Indicazione nome server (SNI). Tale funzionalità estende i protocolli SSL e TLS per indicare il nome host a cui il client sta provando a connettersi. Consente di usare lo stesso indirizzo a più siti Web sicuri con certificati diversi.", - "loc.input.label.HostNameWithOutSNI": "Nome host", - "loc.input.help.HostNameWithOutSNI": "Per assegnare uno o più nomi host (o nomi di dominio) a un computer che usa un singolo indirizzo IP, digitare qui un nome host. Se si specifica un nome host, per accedere al sito Web, i client devono usare tale nome invece dell'indirizzo IP.", - "loc.input.label.HostNameWithHttp": "Nome host", - "loc.input.help.HostNameWithHttp": "Per assegnare uno o più nomi host (o nomi di dominio) a un computer che usa un singolo indirizzo IP, digitare qui un nome host. Se si specifica un nome host, per accedere al sito Web, i client devono usare tale nome invece dell'indirizzo IP.", - "loc.input.label.HostNameWithSNI": "Nome host", - "loc.input.help.HostNameWithSNI": "Per assegnare uno o più nomi host (o nomi di dominio) a un computer che usa un singolo indirizzo IP, digitare qui un nome host. Se si specifica un nome host, per accedere al sito Web, i client devono usare tale nome invece dell'indirizzo IP.", - "loc.input.label.SSLCertThumbPrint": "Identificazione personale certificato SSL", - "loc.input.help.SSLCertThumbPrint": "Identificazione personale del certificato SSL (Secure Socket Layer) che verrà usato dal sito Web. Il certificato deve essere già installato nel computer e presente nell'archivio personale del computer locale.", - "loc.input.label.CreateAppPool": "Crea o aggiorna pool di applicazioni", - "loc.input.help.CreateAppPool": "Consente di selezionare l'opzione per creare un pool di applicazioni o aggiornarne uno esistente.", - "loc.input.label.AppPoolName": "Nome", - "loc.input.help.AppPoolName": "Nome del pool di applicazioni IIS da creare o aggiornare. Il pool di applicazioni IIS verrà aggiornato con le impostazioni specificate qui.", - "loc.input.label.DotNetVersion": "Versione di .NET", - "loc.input.help.DotNetVersion": "Versione di .NET Framework caricata da questo pool di applicazioni. Se le applicazioni assegnate a questo pool di applicazioni non contengono codice gestito, selezionare l'opzione Nessun codice gestito nell'elenco.", - "loc.input.label.PipeLineMode": "Modalità pipeline gestita", - "loc.input.help.PipeLineMode": "La modalità pipeline gestita consente di specificare in che modo IIS elabora le richieste relative al contenuto gestito. Usare la modalità classica solo quando non è possibile eseguire le applicazioni del pool di applicazioni nella modalità integrata.", - "loc.input.label.AppPoolIdentity": "Identità", - "loc.input.help.AppPoolIdentity": "Consente di configurare l'account con cui verrà eseguito il processo di lavoro del pool di applicazioni. Selezionare uno degli account di sicurezza predefiniti o configurare un account personalizzato.", - "loc.input.label.AppPoolUsername": "Nome utente", - "loc.input.label.AppPoolPassword": "Password", - "loc.input.help.AppPoolPassword": "Se si usa un account del servizio gestito del gruppo, non è necessario immettere questo valore.", - "loc.input.label.AppCmdCommands": "Comandi aggiuntivi di AppCmd.exe", - "loc.input.help.AppCmdCommands": "Comandi aggiuntivi di AppCmd.exe per impostare le proprietà del sito Web o del pool di applicazioni. Per più comandi, usare il separatore di riga, ad esempio
list apppools
list sites", - "loc.input.label.DeployInParallel": "Distribuisci in parallelo", - "loc.input.help.DeployInParallel": "Se è impostato su true, l'applicazione Web verrà distribuita in parallelo nei computer di destinazione.", - "loc.input.label.ResourceFilteringMethod": "Seleziona computer per", - "loc.input.help.ResourceFilteringMethod": "Selezionare, facoltativamente, un sottoinsieme di computer specificando nomi o tag dei computer.", - "loc.input.label.MachineFilter": "Distribuisci in computer", - "loc.input.help.MachineFilter": "Questo input è valido solo per gruppi di computer e non è ancora supportato per elenchi semplici di computer o variabili di output. Consente di specificare un elenco di computer come dbserver.fabrikam.com, webserver.fabrikam.com, 192.168.12.34 o tag come Role:DB; OS:Win8.1. Se vengono specificati più tag, l'attività verrà eseguita in tutti i computer con i tag specificati. Per Gruppo di risorse di Azure specificare il nome della macchina virtuale, ad esempio ffweb o ffdb. Per impostazione predefinita, l'attività viene eseguita in tutti i computer." -} \ No newline at end of file diff --git a/Tasks/IISWebAppDeployment/Strings/resources.resjson/ja-jp/resources.resjson b/Tasks/IISWebAppDeployment/Strings/resources.resjson/ja-jp/resources.resjson deleted file mode 100644 index caa4ac6ed619..000000000000 --- a/Tasks/IISWebAppDeployment/Strings/resources.resjson/ja-jp/resources.resjson +++ /dev/null @@ -1,79 +0,0 @@ -{ - "loc.friendlyName": "[非推奨] IIS Web アプリの展開", - "loc.helpMarkDown": "[More Information](https://aka.ms/iiswebappdeployreadme)", - "loc.description": "MSDeploy で展開し、Web サイトとアプリ プールを作成またはアップデートします", - "loc.instanceNameFormat": "[非推奨] IIS アプリ: $(WebDeployPackage) の展開", - "loc.group.displayName.deployment": "配置", - "loc.group.displayName.website": "Web サイト", - "loc.group.displayName.applicationPool": "アプリケーション プール", - "loc.group.displayName.advanced": "詳細設定", - "loc.input.label.EnvironmentName": "コンピューター", - "loc.input.help.EnvironmentName": "コンピューターの IP アドレスまたは FQDN とポートのコンマ区切り一覧を指定します。ポートは選んだプロトコルに基づいて既定値に設定されます。
例: dbserver.fabrikam.com,dbserver_int.fabrikam.com:5986,192.168.12.34:5986
または他のタスクの出力変数を指定します。例: $(variableName)", - "loc.input.label.AdminUserName": "管理者ログイン", - "loc.input.help.AdminUserName": "ターゲット コンピューターの管理者ログイン。", - "loc.input.label.AdminPassword": "パスワード", - "loc.input.help.AdminPassword": "対象のコンピューターの管理者パスワード。
ビルド/リリース定義で '$(passwordVariable)' として定義された変数を受け入れることができます。
変数タイプを 'シークレット' とマークして保護することもできます。", - "loc.input.label.WinRMProtocol": "プロトコル", - "loc.input.help.WinRMProtocol": "コンピューターとの WinRM 接続に使用するプロトコルを選びます。既定は HTTPS です。", - "loc.input.label.TestCertificate": "証明書のテスト", - "loc.input.help.TestCertificate": "信頼された証明機関によるコンピューターの証明書の信頼性の検証をスキップするにはこのオプションを選びます。WinRM HTTPS プロトコルにはこのパラメーターが必要です。", - "loc.input.label.WebDeployPackage": "Web 展開パッケージ", - "loc.input.help.WebDeployPackage": "対象のコンピューターまたは UNC パス (\\\\\\\\BudgetIT\\WebDeploy\\WebDeployPackage.zip など) 上の Web 展開 (MSDeploy) zip ファイルの場所。UNC パスはコンピューターの管理者アカウントからアクセスできる必要があります。$env:windir、$env:systemroot などの環境変数を使って $env:windir\\FabrikamFibre\\Web のように指定することもサポートされます。", - "loc.input.label.WebDeployParamFile": "Web 展開パラメーター ファイル", - "loc.input.help.WebDeployParamFile": "対象のコンピューターまたは UNC パスにあるパラメーター ファイルの場所。パラメーター ファイルは IIS Web アプリケーション名やデータベース接続文字列などの Web アプリケーション構成設定を上書きするために用いられます。", - "loc.input.label.OverRideParams": "パラメーターの上書き", - "loc.input.help.OverRideParams": "ここで指定されたパラメーターで MSDeploy zip ファイルおよびパラメーター ファイルのパラメーターが上書きされます。1 つ以上のパラメーターを上書きするには、行区切りを使用します。例:
\"IIS Web Application Name\"=\"Fabrikam\"
\"ConnectionString\"=\"Server=localhost;Database=Fabrikam;\"", - "loc.input.label.CreateWebSite": "Web サイトの作成または更新", - "loc.input.help.CreateWebSite": "Web サイトを作成する、または既存の Web サイトを更新するオプションを選択します。", - "loc.input.label.WebSiteName": "Web サイト名", - "loc.input.help.WebSiteName": "IIS Web サイトの名前。存在しない場合は作成され、IIS サーバーに既に存在する場合は更新されます。Web サイトの名前は Web 展開 zip パッケージ ファイルで指定されたものと同じである必要があります。パラメーター ファイルとパラメーターの上書き設定も指定される場合、Web サイトの名前はパラメーターの上書き設定のものと同じである必要があります。", - "loc.input.label.WebSitePhysicalPath": "物理パス", - "loc.input.help.WebSitePhysicalPath": "Web サイトのコンテンツが保存されている物理パス。コンテンツはローカル コンピューター、リモート ディレクトリ、共有に置くことができます (C:\\Fabrikam、\\\\\\\\ContentShare\\Fabrikam など)。", - "loc.input.label.WebSitePhysicalPathAuth": "物理パス認証", - "loc.input.help.WebSitePhysicalPathAuth": "Web サイトの物理パスにアクセスする認証機構。", - "loc.input.label.WebSiteAuthUserName": "ユーザー名", - "loc.input.help.WebSiteAuthUserName": "Web サイトの物理パスにアクセスするユーザー名。", - "loc.input.label.WebSiteAuthUserPassword": "パスワード", - "loc.input.help.WebSiteAuthUserPassword": "Web サイトの物理パスにアクセスするためのパスワード。gMSA を使用している場合、これは必要ありません。", - "loc.input.label.AddBinding": "バインドの追加", - "loc.input.help.AddBinding": "このオプションを選択して Web サイトのポートのバインドを追加します。", - "loc.input.label.AssignDuplicateBinding": "重複するバインドの割り当て", - "loc.input.help.AssignDuplicateBinding": "同じバインドを持つ他の Web サイトがある場合でも、ここで指定されたバインドを追加するオプションを選択します。バインドの競合がある場合は、Web サイトのうちの 1 つのみが開始されます。", - "loc.input.label.Protocol": "プロトコル", - "loc.input.help.Protocol": "Web サイトに HTTP を選択して HTTP バインドとするか、Web サイトに HTTPS を選択して Secure Sockets Layer (SSL) バインドとします。", - "loc.input.label.IPAddress": "IP アドレス", - "loc.input.help.IPAddress": "ユーザーがこの Web サイトへのアクセスで用いることができる IP アドレスを入力します。[割り当てなし] が選択されると、同じサーバーの別サイトが同一ポートに特定の IP アドレスでバインドされていない限り、サイトはポート上すべての IP アドレスと、このサイトに指定されたオプションのホスト名に対する要求に応答します。", - "loc.input.label.Port": "ポート", - "loc.input.help.Port": "ハイパーテキスト転送プロトコル スタック (HTTP.sys) がこの Web サイトで作られた要求を待ち受けるポートを入力します。", - "loc.input.label.ServerNameIndication": "サーバー名の通知が必要です", - "loc.input.help.ServerNameIndication": "Web サイトで Server Name Indication (SNI) が要求されるかどうかを指定します。SNI は SSL と TLS プロトコルを拡張したもので、クライアントが接続を試みるホスト名を指定します。これによって異なる証明書を持つ複数の安全な Web サイトで同一 IP アドレスを使うことができるようになります。", - "loc.input.label.HostNameWithOutSNI": "ホスト名", - "loc.input.help.HostNameWithOutSNI": "1 つの IP アドレスを使用するコンピューターに 1 つか複数のホスト名 (ドメイン名) を割り当てるには、ここでホスト名を入力します。ホスト名が指定されると、クライアントが Web サイトにアクセスする際に IP アドレスではなくホスト名が使用されます。", - "loc.input.label.HostNameWithHttp": "ホスト名", - "loc.input.help.HostNameWithHttp": "1 つの IP アドレスを使用するコンピューターに 1 つか複数のホスト名 (ドメイン名) を割り当てるには、ここでホスト名を入力します。ホスト名が指定されると、クライアントが Web サイトにアクセスする際に IP アドレスではなくホスト名が使用されます。", - "loc.input.label.HostNameWithSNI": "ホスト名", - "loc.input.help.HostNameWithSNI": "1 つの IP アドレスを使用するコンピューターに 1 つか複数のホスト名 (ドメイン名) を割り当てるには、ここでホスト名を入力します。ホスト名が指定されると、クライアントが Web サイトにアクセスする際に IP アドレスではなくホスト名が使用されます。", - "loc.input.label.SSLCertThumbPrint": "SSL 証明書の拇印", - "loc.input.help.SSLCertThumbPrint": "Web サイトが使用する Secure Socket Layer 証明書の拇印。証明書はあらかじめインストールされ、コンピューターのローカル システムの個人用保存場所に置かれている必要があります。", - "loc.input.label.CreateAppPool": "アプリケーション プールの作成または更新", - "loc.input.help.CreateAppPool": "アプリケーション プールを作成するオプションか、既存のアプリケーション プールを更新するオプションを選択します。", - "loc.input.label.AppPoolName": "名前", - "loc.input.help.AppPoolName": "作成または更新する IIS アプリケーション プールの名前。既存のアプリケーション プールはここで指定した設定で更新されます。", - "loc.input.label.DotNetVersion": ".NET バージョン", - "loc.input.help.DotNetVersion": "このアプリケーション プールで読み込まれる .NET Framework のバージョン。このアプリケーション プールに割り当てられたアプリケーションにマネージ コードがない場合、リストから [マネージ コードなし] オプションを選択します。", - "loc.input.label.PipeLineMode": "マネージ パイプライン モード", - "loc.input.help.PipeLineMode": "マネージ パイプライン モードは、管理コンテンツの要求が IIS で処理される方法を指定します。アプリケーション プールのアプリケーションが統合モードで実行できない場合は、クラシック モードのみ使用します。", - "loc.input.label.AppPoolIdentity": "ID", - "loc.input.help.AppPoolIdentity": "アプリケーション プールのワーカー プロセスが実行されるアカウントを構成します。定義済みセキュリティ アカウントの 1 つを選択するか、カスタム アカウントを構成します。", - "loc.input.label.AppPoolUsername": "ユーザー名", - "loc.input.label.AppPoolPassword": "パスワード", - "loc.input.help.AppPoolPassword": "gMSA を使用している場合、これは必要ありません。", - "loc.input.label.AppCmdCommands": "Appcmd.exe 追加コマンド", - "loc.input.help.AppCmdCommands": "Web サイトまたはアプリケーション プールのプロパティを設定する Appcmd.exe 追加コマンド。複数のコマンドを指定する場合は行区切りを使用します。例:
list apppools
list sites", - "loc.input.label.DeployInParallel": "並列で展開", - "loc.input.help.DeployInParallel": "この値を [True] に設定すると、対象のコンピューターで平行して Web アプリケーションが展開されます。", - "loc.input.label.ResourceFilteringMethod": "以下の条件でコンピューターを選択", - "loc.input.help.ResourceFilteringMethod": "必要に応じて、コンピューター名またはタグを指定してコンピューターのサブセットを選択します。", - "loc.input.label.MachineFilter": "コンピューターに展開", - "loc.input.help.MachineFilter": "この入力はコンピューター グループでのみ使用でき、コンピューターまたは出力変数の単純なリストではまだサポートされていません。コンピューターのリスト (dbserver.fabrikam.com, webserver.fabrikam.com, 192.168.12.34 など)、またはタグのリスト (Role:DB; OS:Win8.1) をご指定ください。複数のタグを指定した場合、指定されたタグを持つすべてのコンピューターでタスクが実行されます。Azure リソース グループの場合は、ffweb または ffdb のような仮想マシン名をご指定ください。既定値ではタスクがすべてのコンピューターで実行されます。" -} \ No newline at end of file diff --git a/Tasks/IISWebAppDeployment/Strings/resources.resjson/ko-KR/resources.resjson b/Tasks/IISWebAppDeployment/Strings/resources.resjson/ko-KR/resources.resjson deleted file mode 100644 index e4a895e98fa4..000000000000 --- a/Tasks/IISWebAppDeployment/Strings/resources.resjson/ko-KR/resources.resjson +++ /dev/null @@ -1,79 +0,0 @@ -{ - "loc.friendlyName": "[사용되지 않음] IIS 웹앱 배포", - "loc.helpMarkDown": "[More Information](https://aka.ms/iiswebappdeployreadme)", - "loc.description": "MSDeploy에 의한 배포, 웹 사이트 및 앱 풀 만들기/업데이트", - "loc.instanceNameFormat": "[사용되지 않음] IIS 앱 배포: $(WebDeployPackage)", - "loc.group.displayName.deployment": "배포", - "loc.group.displayName.website": "웹 사이트", - "loc.group.displayName.applicationPool": "응용 프로그램 풀", - "loc.group.displayName.advanced": "고급", - "loc.input.label.EnvironmentName": "컴퓨터", - "loc.input.help.EnvironmentName": "포트와 함께 쉼표로 구분된 컴퓨터 IP 주소 또는 FQDN 목록을 제공하세요. 포트의 기본값이 선택된 프로토콜을 기준으로 설정되었습니다.
예: dbserver.fabrikam.com,dbserver_int.fabrikam.com:5986,192.168.12.34:5986
또는 다른 작업의 출력 변수를 제공하세요. 예: $(variableName)", - "loc.input.label.AdminUserName": "관리자 로그인", - "loc.input.help.AdminUserName": "대상 컴퓨터에 대한 관리자 로그인입니다.", - "loc.input.label.AdminPassword": "암호", - "loc.input.help.AdminPassword": "대상 컴퓨터에 대한 관리자 암호입니다.
빌드/릴리스 정의에 '$(passwordVariable)'(으)로 정의된 변수를 사용할 수 있습니다.
보호하기 위해 변수 형식을 'secret'으로 표시할 수 있습니다.", - "loc.input.label.WinRMProtocol": "프로토콜", - "loc.input.help.WinRMProtocol": "컴퓨터와의 WinRM 연결에 사용할 프로토콜을 선택하세요. 기본값은 HTTPS입니다.", - "loc.input.label.TestCertificate": "테스트 인증서", - "loc.input.help.TestCertificate": "신뢰할 수 있는 인증 기관의 컴퓨터 인증서 신뢰성 확인을 건너뛰려면 이 옵션을 선택하세요. WinRM HTTPS 프로토콜에는 매개 변수가 필요합니다.", - "loc.input.label.WebDeployPackage": "웹 배포 패키지", - "loc.input.help.WebDeployPackage": "대상 컴퓨터나 UNC 경로에 있는 웹 배포(MSDeploy) zip 파일의 위치입니다(예: \\\\\\\\BudgetIT\\WebDeploy\\WebDeployPackage.zip). UNC 경로는 컴퓨터의 관리자 계정이 액세스할 수 있어야 합니다. 환경 변수도 지원됩니다(예: $env:windir, $env:systemroot, $env:windir\\FabrikamFibre\\Web).", - "loc.input.label.WebDeployParamFile": "웹 배포 매개 변수 파일", - "loc.input.help.WebDeployParamFile": "대상 컴퓨터나 UNC 경로에 있는 매개 변수 파일의 위치입니다. 매개 변수 파일은 IIS 웹 응용 프로그램 이름 또는 데이터베이스 연결 문자열과 같은 웹 응용 프로그램 구성 설정을 재정의하는 데 사용됩니다.", - "loc.input.label.OverRideParams": "재정의 매개 변수", - "loc.input.help.OverRideParams": "여기에서 지정된 매개 변수는 MSDeploy zip 파일 및 매개 변수 파일의 매개 변수를 재정의합니다. 하나 이상의 매개 변수를 재정의하려면 줄 구분선을 사용하세요. 예:
\"IIS 웹 응용 프로그램 이름\"=\"Fabrikam\"
\"ConnectionString\"=\"Server=localhost;Database=Fabrikam;\"", - "loc.input.label.CreateWebSite": "웹 사이트 만들기 또는 업데이트", - "loc.input.help.CreateWebSite": "웹 사이트를 만들거나 기존 웹 사이트를 업데이트하는 옵션을 선택합니다.", - "loc.input.label.WebSiteName": "웹 사이트 이름", - "loc.input.help.WebSiteName": "없는 경우 만들어지고 IIS 서버에 이미 있는 경우 업데이트될 IIS 웹 사이트의 이름입니다. 웹 사이트의 이름은 웹 배포 zip 패키지 파일에서 지정된 웹 사이트 이름과 같아야 합니다. 매개 변수 파일과 재정의 매개 변수 설정도 지정된 경우에는 웹 사이트의 이름이 재정의 매개 변수 설정의 웹 사이트 이름과 같아야 합니다.", - "loc.input.label.WebSitePhysicalPath": "실제 경로", - "loc.input.help.WebSitePhysicalPath": "웹 사이트 콘텐츠가 저장되는 실제 경로입니다. 콘텐츠는 로컬 컴퓨터나 원격 디렉터리 또는 공유에 있을 수 있습니다(예: C:\\Fabrikam 또는 \\\\\\\\ContentShare\\Fabrikam).", - "loc.input.label.WebSitePhysicalPathAuth": "실제 경로 인증", - "loc.input.help.WebSitePhysicalPathAuth": "웹 사이트의 실제 경로에 액세스하기 위한 인증 메커니즘입니다.", - "loc.input.label.WebSiteAuthUserName": "사용자 이름", - "loc.input.help.WebSiteAuthUserName": "웹 사이트의 실제 경로에 액세스하기 위한 사용자 이름입니다.", - "loc.input.label.WebSiteAuthUserPassword": "암호", - "loc.input.help.WebSiteAuthUserPassword": "웹 사이트의 실제 경로에 액세스하기 위한 암호입니다. gMSA를 사용 중인 경우 이 항목은 필수 항목이 아닙니다.", - "loc.input.label.AddBinding": "바인딩 추가", - "loc.input.help.AddBinding": "웹 사이트에 대한 포트 바인딩을 추가하는 옵션을 선택합니다.", - "loc.input.label.AssignDuplicateBinding": "중복 바인딩 할당", - "loc.input.help.AssignDuplicateBinding": "바인딩이 동일한 다른 웹 사이트가 있는 경우에도 여기에서 지정된 바인딩을 추가하는 옵션을 선택합니다. 바인딩 충돌이 있는 경우 웹 사이트 중 하나만 시작됩니다.", - "loc.input.label.Protocol": "프로토콜", - "loc.input.help.Protocol": "HTTP 바인딩을 사용할 웹 사이트의 경우 HTTP를 선택하고, SSL(Secure Sockets Layer) 바인딩을 사용할 웹 사이트의 경우에는 HTTPS를 선택합니다.", - "loc.input.label.IPAddress": "IP 주소", - "loc.input.help.IPAddress": "사용자가 이 웹 사이트에 액세스하는 데 사용할 수 있는 IP 주소를 입력합니다. [지정하지 않은 모든 IP]를 선택하는 경우 동일한 포트에 있지만 특정 IP 주소를 가진 바인딩이 서버의 다른 사이트에 없으면 이 사이트에 대해 지정된 포트와 선택적 호스트 이름의 모든 IP 주소에 대한 요청에 이 사이트가 응답합니다.", - "loc.input.label.Port": "포트", - "loc.input.help.Port": "HTTP(Hypertext Transfer Protocol) 스택(HTTP.sys)에서 이 웹 사이트에 실행된 요청을 수신 대기해야 하는 포트를 입력합니다.", - "loc.input.label.ServerNameIndication": "서버 이름 표시 필요", - "loc.input.help.ServerNameIndication": "웹 사이트에 SNI(서버 이름 표시)가 필요한지 여부를 확인합니다. SNI는 SSL 및 TLS 프로토콜을 확장하여 클라이언트가 연결하려고 하는 호스트 이름을 나타냅니다. SNI를 통해 서로 다른 인증서를 사용하는 여러 보안 웹 사이트에서 동일한 IP 주소를 사용할 수 있습니다.", - "loc.input.label.HostNameWithOutSNI": "호스트 이름", - "loc.input.help.HostNameWithOutSNI": "단일 IP 주소를 사용하는 컴퓨터에 호스트 이름(또는 도메인 이름)을 하나 이상 할당하려면 여기에 호스트 이름을 입력합니다. 호스트 이름이 지정된 경우 클라이언트는 IP 주소 대신 호스트 이름을 사용하여 웹 사이트에 액세스해야 합니다.", - "loc.input.label.HostNameWithHttp": "호스트 이름", - "loc.input.help.HostNameWithHttp": "단일 IP 주소를 사용하는 컴퓨터에 호스트 이름(또는 도메인 이름)을 하나 이상 할당하려면 여기에 호스트 이름을 입력합니다. 호스트 이름이 지정된 경우 클라이언트는 IP 주소 대신 호스트 이름을 사용하여 웹 사이트에 액세스해야 합니다.", - "loc.input.label.HostNameWithSNI": "호스트 이름", - "loc.input.help.HostNameWithSNI": "단일 IP 주소를 사용하는 컴퓨터에 호스트 이름(또는 도메인 이름)을 하나 이상 할당하려면 여기에 호스트 이름을 입력합니다. 호스트 이름이 지정된 경우 클라이언트는 IP 주소 대신 호스트 이름을 사용하여 웹 사이트에 액세스해야 합니다.", - "loc.input.label.SSLCertThumbPrint": "SSL 인증서 지문", - "loc.input.help.SSLCertThumbPrint": "웹 사이트에서 사용할 SSL(Secure Socket Layer) 인증서의 지문입니다. 인증서가 컴퓨터에 이미 설치되어 있고 로컬 컴퓨터, 개인 저장소에 있어야 합니다.", - "loc.input.label.CreateAppPool": "응용 프로그램 풀 만들기 또는 업데이트", - "loc.input.help.CreateAppPool": "응용 프로그램 풀을 만들거나 기존 응용 프로그램 풀을 업데이트하는 옵션을 선택합니다.", - "loc.input.label.AppPoolName": "이름", - "loc.input.help.AppPoolName": "만들거나 업데이트할 IIS 응용 프로그램 풀의 이름입니다. 기존 응용 프로그램 풀은 여기에서 지정된 설정으로 업데이트됩니다.", - "loc.input.label.DotNetVersion": ".NET 버전", - "loc.input.help.DotNetVersion": "이 응용 프로그램 풀에 의해 로드되는 .NET Framework의 버전입니다. 이 응용 프로그램 풀에 할당된 응용 프로그램에 관리 코드가 포함되지 않은 경우 목록에서 [관리 코드 없음] 옵션을 선택합니다.", - "loc.input.label.PipeLineMode": "관리되는 파이프라인 모드", - "loc.input.help.PipeLineMode": "관리되는 파이프라인 모드는 IIS에서 관리되는 콘텐츠에 대한 요청을 처리하는 방식을 지정합니다. 응용 프로그램 풀의 응용 프로그램이 통합 모드에서 실행될 수 없는 경우에만 클래식 모드를 사용하세요.", - "loc.input.label.AppPoolIdentity": "ID", - "loc.input.help.AppPoolIdentity": "응용 프로그램 풀의 작업자 프로세스가 실행되는 계정을 구성합니다. 미리 정의된 보안 계정 중 하나를 선택하거나 사용자 지정 계정을 구성합니다.", - "loc.input.label.AppPoolUsername": "사용자 이름", - "loc.input.label.AppPoolPassword": "암호", - "loc.input.help.AppPoolPassword": "gMSA를 사용 중인 경우 이 항목은 필수 항목이 아닙니다.", - "loc.input.label.AppCmdCommands": "추가 AppCmd.exe 명령", - "loc.input.help.AppCmdCommands": "웹 사이트 또는 응용 프로그램 풀 속성을 설정할 추가 AppCmd.exe 명령입니다. 명령이 두 개 이상인 경우 줄 구분 기호를 사용하세요. 예:
list apppools
list sites", - "loc.input.label.DeployInParallel": "동시 배포", - "loc.input.help.DeployInParallel": "true로 설정하면 웹 응용 프로그램이 대상 컴퓨터에 동시에 배포됩니다.", - "loc.input.label.ResourceFilteringMethod": "컴퓨터 선택 기준", - "loc.input.help.ResourceFilteringMethod": "필요한 경우 컴퓨터 이름 또는 태그를 제공하여 컴퓨터의 하위 집합을 선택합니다.", - "loc.input.label.MachineFilter": "컴퓨터에 배포", - "loc.input.help.MachineFilter": "이 입력은 컴퓨터 그룹에만 유효하며 컴퓨터 또는 변수의 단순 목록에는 아직 지원되지 않습니다. dbserver.fabrikam.com, webserver.fabrikam.com, 192.168.12.34 등과 같은 컴퓨터나 Role:DB; OS:Win8.1 등과 같은 태그 목록을 지정하세요. 여러 태그를 지정하는 경우 지정된 태그가 포함된 모든 컴퓨터에서 작업이 실행됩니다. Azure 리소스 그룹의 경우 ffweb, ffdb 등과 같은 가상 컴퓨터 이름을 지정하세요. 기본값은 모든 컴퓨터에서 실행하는 것입니다." -} \ No newline at end of file diff --git a/Tasks/IISWebAppDeployment/Strings/resources.resjson/ru-RU/resources.resjson b/Tasks/IISWebAppDeployment/Strings/resources.resjson/ru-RU/resources.resjson deleted file mode 100644 index a3376cb2c694..000000000000 --- a/Tasks/IISWebAppDeployment/Strings/resources.resjson/ru-RU/resources.resjson +++ /dev/null @@ -1,79 +0,0 @@ -{ - "loc.friendlyName": "[Не рекомендуется] Развертывание веб-приложений IIS", - "loc.helpMarkDown": "[More Information](https://aka.ms/iiswebappdeployreadme)", - "loc.description": "Развертывание с помощью MSDeploy, создание и обновление пула веб-сайтов и приложений", - "loc.instanceNameFormat": "[Не рекомендуется] Развертывание приложения IIS: $(WebDeployPackage)", - "loc.group.displayName.deployment": "Развертывание", - "loc.group.displayName.website": "Веб-сайт", - "loc.group.displayName.applicationPool": "Пул приложений", - "loc.group.displayName.advanced": "Дополнительно", - "loc.input.label.EnvironmentName": "Компьютеры", - "loc.input.help.EnvironmentName": "Укажите разделенный запятыми список IP-адресов компьютеров или полных доменных имен вместе с портами. Порт по умолчанию выбирается исходя из используемого протокола.
Например: dbserver.fabrikam.com,dbserver_int.fabrikam.com:5986,192.168.12.34:5986
Или укажите выходную переменную из других задач. Например: $(variableName)", - "loc.input.label.AdminUserName": "Имя для входа администратора", - "loc.input.help.AdminUserName": "Имя для входа администратора для целевых компьютеров.", - "loc.input.label.AdminPassword": "Пароль", - "loc.input.help.AdminPassword": "Пароль администратора для целевых компьютеров.
Он может принять переменную, заданную в определениях сборки или выпуска в качестве \"$(passwordVariable)\".
Вы можете отметить тип переменной как \"secret\", чтобы защитить ее. ", - "loc.input.label.WinRMProtocol": "Протокол", - "loc.input.help.WinRMProtocol": "Выберите протокол, используемый в WinRM-подключениях к компьютерам. Значение по умолчанию — HTTPS.", - "loc.input.label.TestCertificate": "Тестовый сертификат", - "loc.input.help.TestCertificate": "Выберите этот параметр, чтобы пропустить проверку достоверности сертификата компьютера доверенным центром сертификации. Параметр обязателен для протокола WinRM HTTPS.", - "loc.input.label.WebDeployPackage": "Пакет веб-развертывания", - "loc.input.help.WebDeployPackage": "Расположение ZIP-файла веб-развертывания (MSDeploy) на целевых компьютерах или UNC-путь, например \\\\\\\\BudgetIT\\WebDeploy\\WebDeployPackage.zip. UNC-путь должен быть доступен для учетной записи администратора компьютера. Также поддерживаются переменные среды, такие как $env:windir, $env:systemroot, like, $env:windir\\FabrikamFibre\\Web.", - "loc.input.label.WebDeployParamFile": "Файл параметров веб-развертывания", - "loc.input.help.WebDeployParamFile": "Расположение файла параметров на целевых компьютерах или UNC-путь. С помощью файла параметров переопределяются параметры конфигурации веб-приложения, например имя веб-приложения IIS или строка подключения к базе данных.", - "loc.input.label.OverRideParams": "Переопределить параметры", - "loc.input.help.OverRideParams": "Указанные здесь параметры переопределяют параметры в ZIP-файле MSDeploy и файле параметров. Чтобы переопределить больше одного параметра, используйте разделитель строк, например
IIS Web Application Name = Fabrikam
ConnectionString = Server=localhost;Database=Fabrikam;", - "loc.input.label.CreateWebSite": "Создать или обновить веб-сайт", - "loc.input.help.CreateWebSite": "Параметр для создания нового веб-сайта или обновления существующего.", - "loc.input.label.WebSiteName": "Имя веб-сайта", - "loc.input.help.WebSiteName": "Имя веб-сайта IIS, который будет создан, если веб-сайт еще не существует, или который будет обновлен, если веб-сайт уже существует на сервере IIS. Имя веб-сайта должно совпадать с именем, указанным в ZIP-файле веб-развертывания. Если файл параметров и настройки параметров переопределения также указаны, то имя веб-сайта должно быть таким же, как в настройках параметров переопределения.", - "loc.input.label.WebSitePhysicalPath": "Физический путь", - "loc.input.help.WebSitePhysicalPath": "Физический путь к месту хранения содержимого веб-сайта. Содержимое может располагаться на локальном компьютере или в удаленном каталоге или общей папке, например C:\\Fabrikam или \\\\\\\\ContentShare\\Fabrikam.", - "loc.input.label.WebSitePhysicalPathAuth": "Проверка подлинности физического пути", - "loc.input.help.WebSitePhysicalPathAuth": "Механизм проверки подлинности для доступа к физическому пути веб-сайта.", - "loc.input.label.WebSiteAuthUserName": "Имя пользователя", - "loc.input.help.WebSiteAuthUserName": "Имя пользователя для доступа к физическому пути веб-сайта.", - "loc.input.label.WebSiteAuthUserPassword": "Пароль", - "loc.input.help.WebSiteAuthUserPassword": "Пароль для доступа к физическому пути веб-сайта. При использовании gMSA не требуется.", - "loc.input.label.AddBinding": "Добавить привязку", - "loc.input.help.AddBinding": "Выберите параметр для добавления привязки порта для веб-сайта.", - "loc.input.label.AssignDuplicateBinding": "Назначить повторяющуюся привязку", - "loc.input.help.AssignDuplicateBinding": "Выберите параметр для добавления привязок, указанных здесь, даже если существует другой веб-сайт с такими же привязками. Если возникнет конфликт привязок, то будет запущен только один веб-сайт.", - "loc.input.label.Protocol": "Протокол", - "loc.input.help.Protocol": "Выберите \"HTTP\", чтобы веб-сайт имел привязку HTTP, или выберите \"HTTPS\", чтобы веб-сайт имел привязку SSL.", - "loc.input.label.IPAddress": "IP-адрес", - "loc.input.help.IPAddress": "Введите IP-адрес для доступа пользователей к веб-сайту. Если выбрано \"Все неназначенные\", сайт будет отвечать на запросы со всех IP-адресов порта и необязательного имени узла, указанного для этого сайта, если только другой сайт на сервере не имеет привязки к тому же порту, но с указанным IP-адресом.", - "loc.input.label.Port": "Порт", - "loc.input.help.Port": "Введите порт, от которого стеку протокола HTTP (HTTP.sys) нужно ожидать передачи запросов, выполняемых к этому веб-сайту.", - "loc.input.label.ServerNameIndication": "Требуется указать имя сервера", - "loc.input.help.ServerNameIndication": "Определяет, требуется ли веб-сайту указание имени сервера (SNI). Указание имени сервера расширяет возможности протоколов SSL и TLS по указанию имени узла, к которому клиент пытается подключиться. Оно позволяет нескольким безопасным веб-сайтам с разными сертификатами использовать один IP-адрес.", - "loc.input.label.HostNameWithOutSNI": "Имя узла", - "loc.input.help.HostNameWithOutSNI": "Чтобы назначить одно или несколько имен узла (доменных имен) компьютеру, который использует один IP-адрес, введите имя узла здесь. Если указано имя узла, клиенты должны использовать его вместо IP-адреса для доступа к веб-сайту.", - "loc.input.label.HostNameWithHttp": "Имя узла", - "loc.input.help.HostNameWithHttp": "Чтобы назначить одно или несколько имен узла (доменных имен) компьютеру, который использует один IP-адрес, введите имя узла здесь. Если указано имя узла, клиенты должны использовать его вместо IP-адреса для доступа к веб-сайту.", - "loc.input.label.HostNameWithSNI": "Имя узла", - "loc.input.help.HostNameWithSNI": "Чтобы назначить одно или несколько имен узла (доменных имен) компьютеру, который использует один IP-адрес, введите имя узла здесь. Если указано имя узла, клиенты должны использовать его вместо IP-адреса для доступа к веб-сайту.", - "loc.input.label.SSLCertThumbPrint": "Отпечаток SSL-сертификата", - "loc.input.help.SSLCertThumbPrint": "Отпечаток SSL-сертификата, который будет использоваться веб-сайтом. Сертификат должен быть уже установлен на компьютере и присутствовать в личном хранилище сертификатов на локальном компьютере.", - "loc.input.label.CreateAppPool": "Создать или обновить пул приложений", - "loc.input.help.CreateAppPool": "Параметр для создания нового пула приложений или обновления существующего.", - "loc.input.label.AppPoolName": "Имя", - "loc.input.help.AppPoolName": "Имя пула приложений IIS для создания или обновления. Существующий пул приложений будет обновлен с использованием указанных здесь параметров.", - "loc.input.label.DotNetVersion": "Версия .NET", - "loc.input.help.DotNetVersion": "Версия платформы .NET Framework, загруженная этим пулом приложений. Если приложения, назначенные для этого пула приложений, не содержат управляемого кода, в списке выберите параметр \"Без управляемого кода\".", - "loc.input.label.PipeLineMode": "Режим управляемого конвейера", - "loc.input.help.PipeLineMode": "Режим управляемого конвейера указывает, как IIS обрабатывает запросы к управляемому содержимому. Используйте классический режим, только если приложение из пула приложений не может быть запущено в интегрированном режиме.", - "loc.input.label.AppPoolIdentity": "Идентификатор", - "loc.input.help.AppPoolIdentity": "Настройте учетную запись, с которой будет запущен рабочий процесс пула. Выберите одну из предопределенных учетных записей безопасности или настройте пользовательскую учетную запись.", - "loc.input.label.AppPoolUsername": "Имя пользователя", - "loc.input.label.AppPoolPassword": "Пароль", - "loc.input.help.AppPoolPassword": "При использовании gMSA не требуется.", - "loc.input.label.AppCmdCommands": "Дополнительные команды AppCmd.exe", - "loc.input.help.AppCmdCommands": "Дополнительные команды AppCmd.exe для задания свойств веб-сайта или пула приложений. Если команд несколько, используйте строку-разделитель, например \"
список пулов
список сайтов\".", - "loc.input.label.DeployInParallel": "Параллельное развертывание", - "loc.input.help.DeployInParallel": "Если задать значение \"True\", будет выполнено одновременное развертывание веб-приложения на целевых машинах.", - "loc.input.label.ResourceFilteringMethod": "Выбор компьютеров по", - "loc.input.help.ResourceFilteringMethod": "Как вариант, выберите подмножество компьютеров, указав их имена или теги.", - "loc.input.label.MachineFilter": "Развертывание на компьютерах", - "loc.input.help.MachineFilter": "Входные данные допустимы только для групп компьютеров и пока не поддерживаются для плоского списка компьютеров или выходных переменных. Укажите список компьютеров, например, dbserver.fabrikam.com, webserver.fabrikam.com, 192.168.12.34 или теги, такие как Role:DB; OS:Win8.1. Если указано несколько тегов, задача будет выполняться на всех компьютерах с указанными тегами. Для групп ресурсов Azure укажите имя виртуальной машины (например, ffweb, ffdb). Поведение по умолчанию — запуск задачи на всех компьютерах." -} \ No newline at end of file diff --git a/Tasks/IISWebAppDeployment/Strings/resources.resjson/zh-CN/resources.resjson b/Tasks/IISWebAppDeployment/Strings/resources.resjson/zh-CN/resources.resjson deleted file mode 100644 index ec7afe10786d..000000000000 --- a/Tasks/IISWebAppDeployment/Strings/resources.resjson/zh-CN/resources.resjson +++ /dev/null @@ -1,79 +0,0 @@ -{ - "loc.friendlyName": "[已弃用] IIS Web 应用部署", - "loc.helpMarkDown": "[More Information](https://aka.ms/iiswebappdeployreadme)", - "loc.description": "通过 MSDeploy 进行部署,创建/更新网站和应用池", - "loc.instanceNameFormat": "[已弃用]部署 IIS App: $(WebDeployPackage)", - "loc.group.displayName.deployment": "部署", - "loc.group.displayName.website": "网站", - "loc.group.displayName.applicationPool": "应用程序池", - "loc.group.displayName.advanced": "高级", - "loc.input.label.EnvironmentName": "计算机", - "loc.input.help.EnvironmentName": "提供以逗号分隔的计算机 IP 地址或 FQDN 以及端口列表。端口默认基于选定的协议。
例如: dbserver.fabrikam.com,dbserver_int.fabrikam.com:5986,192.168.12.34:5986
或者提供其他任务的输出变量。例如: $(variableName)", - "loc.input.label.AdminUserName": "管理员登录名", - "loc.input.help.AdminUserName": "目标计算机的管理员登录名。", - "loc.input.label.AdminPassword": "密码", - "loc.input.help.AdminPassword": "目标计算机的管理员密码。
可接受“生成/发布”定义中定义为 \"$(passwordVariable)\" 的变量。
你可将变量类型标记为“机密”来进行保护。", - "loc.input.label.WinRMProtocol": "协议", - "loc.input.help.WinRMProtocol": "选择与计算机进行 WinRM 连接时使用的协议。默认为 HTTPS.", - "loc.input.label.TestCertificate": "测试证书", - "loc.input.help.TestCertificate": "选择跳过验证计算机的证书是否真正由受信任的证书颁发机构签署的选项。WinRM HTTPS 协议需要该参数。", - "loc.input.label.WebDeployPackage": "Web 部署包", - "loc.input.help.WebDeployPackage": "目标计算机或 UNC 路径上 Web 部署(MSDeploy) zip 文件的位置,如,\\\\\\\\BudgetIT\\WebDeploy\\WebDeployPackage.zip。计算机的管理员帐户应可访问该 UNC 路径。也支持环境变量,如 $env:windir、$env:systemroot、 $env:windir\\FabrikamFibre\\Web。", - "loc.input.label.WebDeployParamFile": "Web 部署参数文件", - "loc.input.help.WebDeployParamFile": "目标计算机或 UNC 路径上参数文件的位置。参数文件用于替代 Web 应用程序配置设置,如 IIS Web 应用程序名称或数据库连接字符串。", - "loc.input.label.OverRideParams": "替代参数", - "loc.input.help.OverRideParams": "此处指定的参数将替代 MSDeploy zip 文件和参数文件中的参数。要替代多个参数,请使用行分隔符,例如,
\"IIS Web Application Name\"=\"Fabrikam\"
\"ConnectionString\"=\"Server=localhost;Database=Fabrikam;\"", - "loc.input.label.CreateWebSite": "创建或更新网站", - "loc.input.help.CreateWebSite": "选择创建网站或更新现有网站的选项。", - "loc.input.label.WebSiteName": "网站名", - "loc.input.help.WebSiteName": "将创建的 IIS 网站(如果不存在)的名称,如果 IIS 服务器上已存在 IIS 网站,则将进行更新。网站的名称应与 Web 部署 zip 包文件中指定的名称相同。如果还指定了参数文件和 override 参数设置,则网站名称还应与 override 参数设置中的名称相同。", - "loc.input.label.WebSitePhysicalPath": "物理路径", - "loc.input.help.WebSitePhysicalPath": "存储网站内容的物理路径。该内容可位于本地计算机、远程目录或共享上。如,C:\\Fabrikam or \\\\\\\\ContentShare\\Fabrikam。", - "loc.input.label.WebSitePhysicalPathAuth": "物理路径身份验证", - "loc.input.help.WebSitePhysicalPathAuth": "应用访问网站的物理路径的身份验证机制。", - "loc.input.label.WebSiteAuthUserName": "用户名", - "loc.input.help.WebSiteAuthUserName": "用于访问网站的物理路径的用户名。", - "loc.input.label.WebSiteAuthUserPassword": "密码", - "loc.input.help.WebSiteAuthUserPassword": "用于访问网站的物理路径的密码。如果使用的是 gMSA,则不需要。", - "loc.input.label.AddBinding": "添加绑定", - "loc.input.help.AddBinding": "选择为网站添加端口绑定的选项。", - "loc.input.label.AssignDuplicateBinding": "分配重复绑定", - "loc.input.help.AssignDuplicateBinding": "选择添加此处指定的绑定(即使另一个网站具有相同的绑定)的选项。如果存在绑定冲突,则仅将启动其中一个网站。", - "loc.input.label.Protocol": "协议", - "loc.input.help.Protocol": "为将具有 HTTP 绑定的网站选择 HTTP,或为将具有安全套接字层(SSL)绑定的网站选择 HTTPS。", - "loc.input.label.IPAddress": "IP 地址", - "loc.input.help.IPAddress": "键入用户可用于访问此网站的 IP 地址。如果选择“全部取消分配”,则站点将响应针对为此站点指定的端口和可选主机名上所有 IP 地址的请求,除非服务器上的另一个站点在具有特定 IP 地址的同一端口上具有绑定。", - "loc.input.label.Port": "端口", - "loc.input.help.Port": "键入必须在其上侦听超文本传输协议堆栈(HTTP.sys)的端口,以对此网站发出请求。", - "loc.input.label.ServerNameIndication": "需要服务器名称指示", - "loc.input.help.ServerNameIndication": "确定网站是否需要服务器名称指示(SNI)。SNI 扩展 SSL 和 TLS 协议以指示客户端尝试连接到的主机名。它允许使用不同证书的多个安全网站使用相同的 IP 地址。", - "loc.input.label.HostNameWithOutSNI": "主机名", - "loc.input.help.HostNameWithOutSNI": "若要向使用单个 IP 地址的计算机分配一个或多个主机名(或域名),请在此处键入主机名。如果已指定主机名,则客户端必须使用主机名而非 IP 地址来访问网站。", - "loc.input.label.HostNameWithHttp": "主机名", - "loc.input.help.HostNameWithHttp": "若要向使用单个 IP 地址的计算机分配一个或多个主机名(或域名),请在此处键入主机名。如果已指定主机名,则客户端必须使用主机名而非 IP 地址来访问网站。", - "loc.input.label.HostNameWithSNI": "主机名", - "loc.input.help.HostNameWithSNI": "若要向使用单个 IP 地址的计算机分配一个或多个主机名(或域名),请在此处键入主机名。如果已指定主机名,则客户端必须使用主机名而非 IP 地址来访问网站。", - "loc.input.label.SSLCertThumbPrint": "SSL 证书缩略图打印", - "loc.input.help.SSLCertThumbPrint": "网站将使用的安全套接字层证书的缩略图打印。证书应已安装在计算机上,并位于本地计算机下的个人存储中。", - "loc.input.label.CreateAppPool": "创建或更新应用程序池", - "loc.input.help.CreateAppPool": "选择创建应用程序池或更新现有应用程序池的选项。", - "loc.input.label.AppPoolName": "名称", - "loc.input.help.AppPoolName": "要创建或更新的 IIS 应用程序池的名称。将使用此处指定的设置更新现有应用程序池。", - "loc.input.label.DotNetVersion": ".NET 版本", - "loc.input.help.DotNetVersion": "此应用程序池加载的 .NET Framework 的版本。如果分配给此应用程序池的应用程序不包含托管代码,则从列表中选择“无托管代码”选项。", - "loc.input.label.PipeLineMode": "托管管道模式", - "loc.input.help.PipeLineMode": "托管管道模式指定 IIS 进程如何请求托管内容。仅当应用程序池中的应用程序无法在集成模式下运行时使用经典模式。", - "loc.input.label.AppPoolIdentity": "标识", - "loc.input.help.AppPoolIdentity": "配置运行应用程序池的工作进程的帐户。选择一个预定义安全帐户或配置一个自定义帐户。", - "loc.input.label.AppPoolUsername": "用户名", - "loc.input.label.AppPoolPassword": "密码", - "loc.input.help.AppPoolPassword": "如果你使用的是 gMSA,则不需要。", - "loc.input.label.AppCmdCommands": "其他 AppCmd.exe 命令", - "loc.input.help.AppCmdCommands": "用于设置网站或应用程序池属性的其他 AppCmd.exe 命令。对于多个命令,使用行分隔符,如
list apppools
list sites", - "loc.input.label.DeployInParallel": "并行部署", - "loc.input.help.DeployInParallel": "将它设置为 true 会在目标计算机上并行部署 Web 应用程序。", - "loc.input.label.ResourceFilteringMethod": "计算机选择依据", - "loc.input.help.ResourceFilteringMethod": "(可选)通过提供计算机名或标记来选择计算机的子集。", - "loc.input.label.MachineFilter": "部署到计算机", - "loc.input.help.MachineFilter": "此输入仅对计算机组有效,且尚不支持计算机或输出变量的简单列表。提供计算机列表(如 dbserver.fabrikam.com, webserver.fabrikam.com, 192.168.12.34)或标记列表(如 Role:DB; OS:Win8.1)。如果提供了多个标记,则任务将在具有指定标记的所有计算机中运行。对于 Azure 资源组,提供虚拟机的名称,如 ffweb、ffdb。默认为在所有计算机中运行任务。" -} \ No newline at end of file diff --git a/Tasks/IISWebAppDeployment/Strings/resources.resjson/zh-TW/resources.resjson b/Tasks/IISWebAppDeployment/Strings/resources.resjson/zh-TW/resources.resjson deleted file mode 100644 index a9324281ef35..000000000000 --- a/Tasks/IISWebAppDeployment/Strings/resources.resjson/zh-TW/resources.resjson +++ /dev/null @@ -1,79 +0,0 @@ -{ - "loc.friendlyName": "[已取代] IIS Web 應用程式部署", - "loc.helpMarkDown": "[More Information](https://aka.ms/iiswebappdeployreadme)", - "loc.description": "使用 MSDeploy 部署,建立/更新網站和 app 集區", - "loc.instanceNameFormat": "[已取代] 部署 IIS 應用程式: $(WebDeployPackage)", - "loc.group.displayName.deployment": "部署", - "loc.group.displayName.website": "網站", - "loc.group.displayName.applicationPool": "應用程式集區", - "loc.group.displayName.advanced": "進階", - "loc.input.label.EnvironmentName": "電腦", - "loc.input.help.EnvironmentName": "提供以逗號分隔,包含電腦 IP 位址或 FQDN 與連接埠的清單。連接埠的預設值隨所選的通訊協定而定。
例如: dbserver.fabrikam.com,dbserver_int.fabrikam.com:5986,192.168.12.34:5986
或提供其他作業的輸出變數。例如: $(variableName)", - "loc.input.label.AdminUserName": "系統管理員登入", - "loc.input.help.AdminUserName": "目標電腦的系統管理員登入。", - "loc.input.label.AdminPassword": "密碼", - "loc.input.help.AdminPassword": "目標電腦的系統管理員密碼。
其可接受組建/發行定義中 '$(passwordVariable)' 這類形式的變數。
您可以將變數類型標示為 'secret' 加以保護。", - "loc.input.label.WinRMProtocol": "通訊協定", - "loc.input.help.WinRMProtocol": "選取 WinRM 與電腦連線時所囡使用的通訊協定。預設值為 HTTPS。", - "loc.input.label.TestCertificate": "測試憑證", - "loc.input.help.TestCertificate": "選取此選項可略過驗證電腦憑證是否確實經由信任的憑證授權單位簽署。WinRM HTTPS 通訊協定需要此參數。", - "loc.input.label.WebDeployPackage": "Web Deploy 封裝", - "loc.input.help.WebDeployPackage": "目標電腦或 UNC 路徑上的 Web Deploy (MSDeploy) 壓縮檔位置,例如 \\\\\\\\BudgetIT\\WebDeploy\\WebDeployPackage.zip。電腦的系統管理員帳戶必須可以存取 UNC 路徑。同時也支援環境變數,例如 $env:windir、$env:systemroot 像是 $env:windir\\FabrikamFibre\\Web。", - "loc.input.label.WebDeployParamFile": "Web Deploy 參數檔", - "loc.input.help.WebDeployParamFile": "目標電腦或 UNC 路徑上的參數檔位置。參數檔可用來覆寫 Web 應用程式的組態設定,如 IIS Web 應用程式名稱或資料庫連接字串。", - "loc.input.label.OverRideParams": "覆寫參數", - "loc.input.help.OverRideParams": "此處指定的參數會覆寫 MSDeploy zip 檔案及參數檔案中的參數。若要覆寫一個以上的參數,請使用行分隔符號,例如
\"IIS Web Application Name\"=\"Fabrikam\"
\"ConnectionString\"=\"Server=localhost;Database=Fabrikam;\" ", - "loc.input.label.CreateWebSite": "建立或更新網站", - "loc.input.help.CreateWebSite": "選取選項以建立網站或更新現有網站。", - "loc.input.label.WebSiteName": "網站名稱", - "loc.input.help.WebSiteName": "若不存在則會加以建立,或是若已存在於 IIS 伺服器上則會加以更新的 IIS 網站名稱。網站名稱應與 Web Deploy ZIP 封裝檔中所指定的名稱相同。若同時指定了參數檔及覆寫參數設定,則網站名稱應與覆寫參數設定中的名稱相同。", - "loc.input.label.WebSitePhysicalPath": "實體路徑", - "loc.input.help.WebSitePhysicalPath": "儲存網站內容所在的實體路徑。內容可以存放在本機電腦上或遠端目錄或是共用上,如 C:\\Fabrikam 或 \\\\\\\\ContentShare\\Fabrikam。", - "loc.input.label.WebSitePhysicalPathAuth": "實體路徑驗證", - "loc.input.help.WebSitePhysicalPathAuth": "存取網站實體路徑時,所使用的驗證機制。", - "loc.input.label.WebSiteAuthUserName": "使用者名稱", - "loc.input.help.WebSiteAuthUserName": "用以存取網站實體路徑的使用者名稱。", - "loc.input.label.WebSiteAuthUserPassword": "密碼", - "loc.input.help.WebSiteAuthUserPassword": "用來存取網站實體路徑的密碼。如果您使用 gMSA,則不需要此項目。", - "loc.input.label.AddBinding": "新增繫結", - "loc.input.help.AddBinding": "選取選項以加入網站的連接埠繫結。", - "loc.input.label.AssignDuplicateBinding": "指派重複的繫結", - "loc.input.help.AssignDuplicateBinding": "選取選項,以加入在此處指定的繫結 (即使其他網站已具有相同繫結)。若有繫結衝突的情形,則只會啟動其中一個網站。", - "loc.input.label.Protocol": "通訊協定", - "loc.input.help.Protocol": "選取網站的 HTTP 以建立 HTTP 繫結,或者選取網站的 HTTPS 以建立 Secure Sockets Layer (SSL) 繫結。", - "loc.input.label.IPAddress": "IP 位址", - "loc.input.help.IPAddress": "輸入使用者可以用來存取這個網站的 IP 位址。如果選取 [全部未指派],則當任一 IP 位址位於連接埠上,或位於指定給此網站的選用主機名稱上,該網站便會為其回應所有要求,除非伺服器上的另一個網站在相同連接埠上具有繫結,卻使用特定的 IP 位址。", - "loc.input.label.Port": "連接埠", - "loc.input.help.Port": "輸入超文字傳輸通訊協定堆疊 (HTTP.sys) 務必接聽對此網站提出之要求時所使用的連接埠。", - "loc.input.label.ServerNameIndication": "需要有伺服器名稱指示", - "loc.input.help.ServerNameIndication": "判斷網站是否需要伺服器名稱指示 (SNI)。SNI 會擴充 SSL 和 TLS 通訊協定,以表示用戶端正在嘗試連接的主機名稱。其允許多個具有不同憑證的安全網站使用相同的 IP 位址。", - "loc.input.label.HostNameWithOutSNI": "主機名稱", - "loc.input.help.HostNameWithOutSNI": "若要將一或多個主機名稱 (或網域名稱) 指派給使用單一 IP 位址的電腦,請在這裡輸入主機名稱。如果指定了主機名稱,用戶端就必須使用主機名稱 (而非 IP 位址) 來存取網站。", - "loc.input.label.HostNameWithHttp": "主機名稱", - "loc.input.help.HostNameWithHttp": "若要將一或多個主機名稱 (或網域名稱) 指派給使用單一 IP 位址的電腦,請在這裡輸入主機名稱。如果指定了主機名稱,用戶端就必須使用主機名稱 (而非 IP 位址) 來存取網站。", - "loc.input.label.HostNameWithSNI": "主機名稱", - "loc.input.help.HostNameWithSNI": "若要將一或多個主機名稱 (或網域名稱) 指派給使用單一 IP 位址的電腦,請在這裡輸入主機名稱。如果指定了主機名稱,用戶端就必須使用主機名稱 (而非 IP 位址) 來存取網站。", - "loc.input.label.SSLCertThumbPrint": "SSL 憑證指紋", - "loc.input.help.SSLCertThumbPrint": "網站要使用的安全通訊端層憑證指紋。此憑證應該已安裝在電腦上,且存在於本機電腦的個人存放區之下。", - "loc.input.label.CreateAppPool": "建立或更新應用程式集區", - "loc.input.help.CreateAppPool": "選取選項以建立應用程式集區或更新現有應用程式集區。", - "loc.input.label.AppPoolName": "名稱", - "loc.input.help.AppPoolName": "要建立或更新之 IIS 應用程式集區的名稱。將以此處指定的設定來更新現有應用程式集區。", - "loc.input.label.DotNetVersion": ".NET 版本", - "loc.input.help.DotNetVersion": "此應用程式集區所載入的 .NET Framework 版本。如果指派至此應用程式集區的應用程式不包含 Managed 程式碼,請選取清單中的 [沒有 Managed 程式碼] 選項。", - "loc.input.label.PipeLineMode": "Managed 管線模式", - "loc.input.help.PipeLineMode": "Managed 管線模式會指定 IIS 如何處理受管理內容的要求。只有當應用程式集區中的應用程式無法在整合模式中執行時,才能使用傳統模式。", - "loc.input.label.AppPoolIdentity": "身分識別", - "loc.input.help.AppPoolIdentity": "設定應用程式集區執行所在的帳戶。選取其中一個預先定義的安全性帳戶或設定自訂帳戶。", - "loc.input.label.AppPoolUsername": "使用者名稱", - "loc.input.label.AppPoolPassword": "密碼", - "loc.input.help.AppPoolPassword": "如果您使用 gMSA,則不需要此項目。", - "loc.input.label.AppCmdCommands": "其他 AppCmd.exe 命令", - "loc.input.help.AppCmdCommands": "其他用來設定網站或應用程式集區屬性的 AppCmd.exe 命令。使用一個以上的命令時,請利用行分隔符號,例如
list apppools
list sites", - "loc.input.label.DeployInParallel": "平行部署", - "loc.input.help.DeployInParallel": "設定為 true 即會以平行方式在目標電腦上部署 Web 應用程式。", - "loc.input.label.ResourceFilteringMethod": "選取電腦依據", - "loc.input.help.ResourceFilteringMethod": "選擇性地提供電腦名稱或標記來選取電腦的子集。", - "loc.input.label.MachineFilter": "部署至電腦", - "loc.input.help.MachineFilter": "此輸入只對電腦群組有效,電腦的簡單列表或輸出變數目前尚無法支援。請以 dbserver.fabrikam.com、webserver.fabrikam.com、192.168.12.34 等形式提供電腦清單,或以 Role:DB; OS:Win8.1 等提供標記清單。若提供多個標記,工作會在所有具有指定標記的電腦上執行。若為 Azure 資源群組,請提供虛擬機器的名稱 (例如 ffweb、ffdb)。預設會在所有電腦上執行此工作。" -} \ No newline at end of file diff --git a/Tasks/IISWebAppDeployment/icon.png b/Tasks/IISWebAppDeployment/icon.png deleted file mode 100644 index 8e866e9503ac..000000000000 Binary files a/Tasks/IISWebAppDeployment/icon.png and /dev/null differ diff --git a/Tasks/IISWebAppDeployment/task.json b/Tasks/IISWebAppDeployment/task.json deleted file mode 100644 index fcaae655e5df..000000000000 --- a/Tasks/IISWebAppDeployment/task.json +++ /dev/null @@ -1,416 +0,0 @@ -{ - "id": "89A3A82D-4B3E-4A09-8D40-A793849DC94F", - "name": "IISWebAppDeployment", - "friendlyName": "[Deprecated] IIS Web App Deployment", - "description": "Deploy by MSDeploy, create/update website & app pools", - "helpMarkDown": "[More Information](https://aka.ms/iiswebappdeployreadme)", - "category": "Deploy", - "visibility": [ - "Preview", - "Build", - "Release" - ], - "author": "Microsoft Corporation", - "version": { - "Major": 1, - "Minor": 0, - "Patch": 20 - }, - "demands": [], - "minimumAgentVersion": "1.91.0", - "groups": [ - { - "name": "deployment", - "displayName": "Deployment", - "isExpanded": true - }, - { - "name": "website", - "displayName": "Website", - "isExpanded": true - }, - { - "name": "applicationPool", - "displayName": "Application Pool", - "isExpanded": true - }, - { - "name": "advanced", - "displayName": "Advanced", - "isExpanded": false - } - ], - "inputs": [ - { - "name": "EnvironmentName", - "type": "multiLine", - "label": "Machines", - "defaultValue": "", - "required": true, - "helpMarkDown": "Provide a comma separated list of machine IP addresses or FQDNs along with ports. Port is defaulted based on the selected protocol.
Eg: dbserver.fabrikam.com,dbserver_int.fabrikam.com:5986,192.168.12.34:5986
Or provide output variable of other tasks. Eg: $(variableName)" - }, - { - "name": "AdminUserName", - "type": "string", - "label": "Admin Login", - "defaultValue": "", - "required": false, - "helpMarkDown": "Administrator login for the target machines." - }, - { - "name": "AdminPassword", - "type": "string", - "label": "Password", - "defaultValue": "", - "required": false, - "helpMarkDown": "Administrator password for the target machines.
It can accept variable defined in Build/Release definitions as '$(passwordVariable)'.
You may mark variable type as 'secret' to secure it. " - }, - { - "name": "WinRMProtocol", - "type": "radio", - "label": "Protocol", - "required": false, - "defaultValue": "", - "options": { - "Http": "HTTP", - "Https": "HTTPS" - }, - "helpMarkDown": "Select the protocol to use for the WinRM connection with the machine(s). Default is HTTPS." - }, - { - "name": "TestCertificate", - "type": "boolean", - "label": "Test Certificate", - "defaultValue": "true", - "visibleRule": "WinRMProtocol = Https", - "required": false, - "helpMarkDown": "Select the option to skip validating the authenticity of the machine's certificate by a trusted certification authority. The parameter is required for the WinRM HTTPS protocol." - }, - { - "name": "WebDeployPackage", - "type": "string", - "label": "Web Deploy Package", - "required": true, - "groupName": "deployment", - "defaultValue": "", - "helpMarkDown": "Location of the Web Deploy (MSDeploy) zip file on the target machines or on a UNC path like, \\\\\\\\BudgetIT\\WebDeploy\\WebDeployPackage.zip. The UNC path should be accessible to the machine's administrator account. Environment variables are also supported like, $env:windir, $env:systemroot, like, $env:windir\\FabrikamFibre\\Web." - }, - { - "name": "WebDeployParamFile", - "type": "string", - "label": "Web Deploy Parameter File", - "required": false, - "groupName": "deployment", - "defaultValue": "", - "helpMarkDown": "Location of the Parameter file on the target machines or on a UNC path. Parameter file is used to override Web application configuration settings like, IIS Web application name or database connection string." - }, - { - "name": "OverRideParams", - "type": "multiLine", - "label": "Override Parameters", - "required": false, - "groupName": "deployment", - "defaultValue": "", - "helpMarkDown": "Parameters specified here will override the parameters in the MSDeploy zip file and the Parameter file. To override more than one parameter use line separator, e.g.,
\"IIS Web Application Name\"=\"Fabrikam\"
\"ConnectionString\"=\"Server=localhost;Database=Fabrikam;\"" - }, - { - "name": "CreateWebSite", - "type": "boolean", - "label": "Create or Update Website", - "required": false, - "groupName": "website", - "defaultValue": "false", - "helpMarkDown": "Select the option to create a website or to update an existing website." - }, - { - "name": "WebSiteName", - "type": "string", - "label": "Website Name", - "required": true, - "groupName": "website", - "defaultValue": "", - "visibleRule": "CreateWebSite = true", - "helpMarkDown": "Name of the IIS website that will be created if it does not exist, or it will be updated if it is already present on the IIS server. The name of the website should be same as that specified in the web deploy zip package file. If a Parameter file and override Parameters setting is also specified, then the name of the website should be same as that in the override Parameters setting." - }, - { - "name": "WebSitePhysicalPath", - "type": "string", - "label": "Physical Path", - "required": true, - "groupName": "website", - "defaultValue": "%SystemDrive%\\inetpub\\wwwroot", - "visibleRule": "CreateWebSite = true", - "helpMarkDown": "Physical path where the website content is stored. The content can reside on the local computer or on a remote directory or share like, C:\\Fabrikam or \\\\\\\\ContentShare\\Fabrikam." - }, - { - "name": "WebSitePhysicalPathAuth", - "type": "pickList", - "label": "Physical Path Authentication", - "required": true, - "groupName": "website", - "defaultValue": "Application User (Pass-through)", - "visibleRule": "CreateWebSite = true", - "options": { - "WebSiteUserPassThrough": "Application User (Pass-through)", - "WebSiteWindowsAuth": "Windows Authentication" - }, - "helpMarkDown": "Authentication mechanism for accessing the physical path of the website." - }, - { - "name": "WebSiteAuthUserName", - "type": "string", - "label": "User Name", - "required": true, - "groupName": "website", - "defaultValue": "", - "visibleRule": "WebSitePhysicalPathAuth = WebSiteWindowsAuth", - "helpMarkDown": "User name for accessing the website's physical path." - }, - { - "name": "WebSiteAuthUserPassword", - "type": "string", - "label": "Password", - "required": false, - "groupName": "website", - "defaultValue": "", - "visibleRule": "WebSitePhysicalPathAuth = WebSiteWindowsAuth", - "helpMarkDown": "Password for accessing the website's physical path. If you are using a gMSA, this is not required." - }, - { - "name": "AddBinding", - "type": "boolean", - "label": "Add Binding", - "required": false, - "groupName": "website", - "defaultValue": "true", - "visibleRule": "CreateWebSite = true", - "helpMarkDown": "Select the option to add port binding for the website." - }, - { - "name": "AssignDuplicateBinding", - "type": "boolean", - "label": "Assign Duplicate Binding", - "required": false, - "groupName": "website", - "defaultValue": "false", - "visibleRule": "AddBinding = true", - "helpMarkDown": "Select the option to add the bindings specified here, even if there is another website with the same bindings. If there are binding conflicts, then only one of the website will start." - }, - { - "name": "Protocol", - "type": "pickList", - "label": "Protocol", - "required": true, - "groupName": "website", - "defaultValue": "http", - "options": { - "https": "https", - "http": "http" - }, - "visibleRule": "AddBinding = true", - "helpMarkDown": "Select HTTP for the website to have an HTTP binding, or select HTTPS for the website to have a Secure Sockets Layer (SSL) binding." - }, - { - "name": "IPAddress", - "type": "string", - "label": "IP Address", - "required": true, - "groupName": "website", - "defaultValue": "All Unassigned", - "visibleRule": "AddBinding = true", - "helpMarkDown": "Type an IP address that users can use to access this website. If All Unassigned is selected, the site will respond to requests for all IP addresses on the port and the optional host name that is specified for this site, unless another site on the server has a binding on the same port but with a specific IP address." - }, - { - "name": "Port", - "type": "string", - "label": "Port", - "required": true, - "groupName": "website", - "defaultValue": "80", - "visibleRule": "AddBinding = true", - "helpMarkDown": "Type the port on which Hypertext Transfer Protocol Stack (HTTP.sys) must listen for requests made to this website." - }, - { - "name": "ServerNameIndication", - "type": "boolean", - "label": "Server Name Indication Required", - "required": false, - "groupName": "website", - "defaultValue": "false", - "visibleRule": "Protocol = https", - "helpMarkDown": "Determines whether the website requires Server Name Indication (SNI). SNI extends the SSL and TLS protocols to indicate what host name the client is attempting to connect to. It allows multiple secure websites with different certificates to use the same IP address." - }, - { - "name": "HostNameWithOutSNI", - "type": "string", - "label": "Host Name", - "required": false, - "groupName": "website", - "defaultValue": "", - "visibleRule": "ServerNameIndication = false", - "helpMarkDown": "To assign one or more host names (or domain names) to a computer that uses a single IP address, type a host name here. If a host name is specified then the clients must use the host name instead of the IP address to access the website." - }, - { - "name": "HostNameWithHttp", - "type": "string", - "label": "Host Name", - "required": false, - "groupName": "website", - "defaultValue": "", - "visibleRule": "Protocol = http", - "helpMarkDown": "To assign one or more host names (or domain names) to a computer that uses a single IP address, type a host name here. If a host name is specified then the clients must use the host name instead of the IP address to access the website." - }, - { - "name": "HostNameWithSNI", - "type": "string", - "label": "Host Name", - "required": true, - "groupName": "website", - "defaultValue": "", - "visibleRule": "ServerNameIndication = true", - "helpMarkDown": "To assign one or more host names (or domain names) to a computer that uses a single IP address, type a host name here. If a host name is specified then the clients must use the host name instead of the IP address to access the website." - }, - { - "name": "SSLCertThumbPrint", - "type": "string", - "label": "SSL Certificate Thumb Print", - "required": true, - "groupName": "website", - "defaultValue": "", - "visibleRule": "Protocol = https", - "helpMarkDown": "Thumb-print of the Secure Socket Layer certificate that the website is going to use. The certificate should be already installed on the machine and present under the Local Computer, Personal store." - }, - { - "name": "CreateAppPool", - "type": "boolean", - "label": "Create or Update Application Pool", - "required": false, - "groupName": "applicationPool", - "defaultValue": "false", - "helpMarkDown": "Select the option to create an application pool or to update an existing application pool." - }, - { - "name": "AppPoolName", - "type": "string", - "label": "Name", - "defaultValue": "", - "required": true, - "groupName": "applicationPool", - "visibleRule": "CreateAppPool = true", - "helpMarkDown": "Name of the IIS application pool to create or update. Existing application pool will be updated with the settings specified here." - }, - { - "name": "DotNetVersion", - "type": "pickList", - "label": ".NET Version", - "defaultValue": "v4.0", - "required": true, - "groupName": "applicationPool", - "visibleRule": "CreateAppPool = true", - "helpMarkDown": "Version of the .NET Framework that is loaded by this application pool. If the applications assigned to this application pool do not contain managed code, select the No Managed Code option from the list.", - "options": { - "v4.0": "v4.0", - "v2.0": "v2.0", - "No Managed Code": "No Managed Code" - } - }, - { - "name": "PipeLineMode", - "type": "pickList", - "label": "Managed Pipeline Mode", - "defaultValue": "Integrated", - "required": true, - "groupName": "applicationPool", - "visibleRule": "CreateAppPool = true", - "helpMarkDown": "Managed pipeline mode specifies how IIS processes requests for managed content. Use classic mode only when the applications in the application pool cannot run in the Integrated mode.", - "options": { - "Integrated": "Integrated", - "Classic": "Classic" - } - }, - { - "name": "AppPoolIdentity", - "type": "pickList", - "label": "Identity", - "defaultValue": "ApplicationPoolIdentity", - "required": true, - "groupName": "applicationPool", - "visibleRule": "CreateAppPool = true", - "helpMarkDown": "Configure the account under which an application pool's worker process runs. Select one of the predefined security accounts or configure a custom account.", - "options": { - "ApplicationPoolIdentity": "ApplicationPoolIdentity", - "LocalService": "LocalService", - "LocalSystem": "LocalSystem", - "NetworkService": "NetworkService", - "SpecificUser": "Custom Account" - } - }, - { - "name": "AppPoolUsername", - "type": "string", - "label": "Username", - "defaultValue": "", - "required": true, - "groupName": "applicationPool", - "visibleRule": "AppPoolIdentity = SpecificUser" - }, - { - "name": "AppPoolPassword", - "type": "string", - "label": "Password", - "defaultValue": "", - "required": false, - "helpMarkDown": "If you are using a gMSA, this is not required.", - "groupName": "applicationPool", - "visibleRule": "AppPoolIdentity = SpecificUser" - }, - { - "name": "AppCmdCommands", - "type": "multiLine", - "label": "Additional AppCmd.exe Commands", - "required": false, - "groupName": "advanced", - "defaultValue": "", - "helpMarkDown": "Additional AppCmd.exe commands to set website or application pool properties. For more than one command use line separator, e.g.,
list apppools
list sites" - }, - { - "name": "DeployInParallel", - "type": "boolean", - "label": "Deploy in Parallel", - "defaultValue": "true", - "required": false, - "groupName": "advanced", - "helpMarkDown": "Setting it to true will deploy the Web application in-parallel on the target machines." - }, - { - "name": "ResourceFilteringMethod", - "type": "radio", - "label": "Select Machines By", - "required": false, - "defaultValue": "machineNames", - "options": { - "machineNames": "Machine Names", - "tags": "Tags" - }, - "groupName": "advanced", - "helpMarkDown": "Optionally, select a subset of machines either by providing machine names or tags." - }, - { - "name": "MachineFilter", - "type": "string", - "label": "Deploy to Machines", - "required": false, - "defaultValue": "", - "groupName": "advanced", - "helpMarkDown": "This input is valid only for machine groups and is not supported for flat list of machines or output variables yet. Provide a list of machines like, dbserver.fabrikam.com, webserver.fabrikam.com, 192.168.12.34, or tags like, Role:DB; OS:Win8.1. If multiple tags are provided, then the task will run in all the machines with the specified tags. For Azure Resource Groups, provide the virtual machine's name like, ffweb, ffdb. The default is to run the task in all machines." - } - ], - "instanceNameFormat": "[Deprecated] Deploy IIS App: $(WebDeployPackage)", - "execution": { - "PowerShell": { - "target": "$(currentDirectory)\\DeployIISWebApp.ps1", - "argumentFormat": "", - "workingDirectory": "$(currentDirectory)" - } - } -} \ No newline at end of file diff --git a/Tasks/IISWebAppDeployment/task.loc.json b/Tasks/IISWebAppDeployment/task.loc.json deleted file mode 100644 index 915719ded3c1..000000000000 --- a/Tasks/IISWebAppDeployment/task.loc.json +++ /dev/null @@ -1,416 +0,0 @@ -{ - "id": "89A3A82D-4B3E-4A09-8D40-A793849DC94F", - "name": "IISWebAppDeployment", - "friendlyName": "ms-resource:loc.friendlyName", - "description": "ms-resource:loc.description", - "helpMarkDown": "ms-resource:loc.helpMarkDown", - "category": "Deploy", - "visibility": [ - "Preview", - "Build", - "Release" - ], - "author": "Microsoft Corporation", - "version": { - "Major": 1, - "Minor": 0, - "Patch": 20 - }, - "demands": [], - "minimumAgentVersion": "1.91.0", - "groups": [ - { - "name": "deployment", - "displayName": "ms-resource:loc.group.displayName.deployment", - "isExpanded": true - }, - { - "name": "website", - "displayName": "ms-resource:loc.group.displayName.website", - "isExpanded": true - }, - { - "name": "applicationPool", - "displayName": "ms-resource:loc.group.displayName.applicationPool", - "isExpanded": true - }, - { - "name": "advanced", - "displayName": "ms-resource:loc.group.displayName.advanced", - "isExpanded": false - } - ], - "inputs": [ - { - "name": "EnvironmentName", - "type": "multiLine", - "label": "ms-resource:loc.input.label.EnvironmentName", - "defaultValue": "", - "required": true, - "helpMarkDown": "ms-resource:loc.input.help.EnvironmentName" - }, - { - "name": "AdminUserName", - "type": "string", - "label": "ms-resource:loc.input.label.AdminUserName", - "defaultValue": "", - "required": false, - "helpMarkDown": "ms-resource:loc.input.help.AdminUserName" - }, - { - "name": "AdminPassword", - "type": "string", - "label": "ms-resource:loc.input.label.AdminPassword", - "defaultValue": "", - "required": false, - "helpMarkDown": "ms-resource:loc.input.help.AdminPassword" - }, - { - "name": "WinRMProtocol", - "type": "radio", - "label": "ms-resource:loc.input.label.WinRMProtocol", - "required": false, - "defaultValue": "", - "options": { - "Http": "HTTP", - "Https": "HTTPS" - }, - "helpMarkDown": "ms-resource:loc.input.help.WinRMProtocol" - }, - { - "name": "TestCertificate", - "type": "boolean", - "label": "ms-resource:loc.input.label.TestCertificate", - "defaultValue": "true", - "visibleRule": "WinRMProtocol = Https", - "required": false, - "helpMarkDown": "ms-resource:loc.input.help.TestCertificate" - }, - { - "name": "WebDeployPackage", - "type": "string", - "label": "ms-resource:loc.input.label.WebDeployPackage", - "required": true, - "groupName": "deployment", - "defaultValue": "", - "helpMarkDown": "ms-resource:loc.input.help.WebDeployPackage" - }, - { - "name": "WebDeployParamFile", - "type": "string", - "label": "ms-resource:loc.input.label.WebDeployParamFile", - "required": false, - "groupName": "deployment", - "defaultValue": "", - "helpMarkDown": "ms-resource:loc.input.help.WebDeployParamFile" - }, - { - "name": "OverRideParams", - "type": "multiLine", - "label": "ms-resource:loc.input.label.OverRideParams", - "required": false, - "groupName": "deployment", - "defaultValue": "", - "helpMarkDown": "ms-resource:loc.input.help.OverRideParams" - }, - { - "name": "CreateWebSite", - "type": "boolean", - "label": "ms-resource:loc.input.label.CreateWebSite", - "required": false, - "groupName": "website", - "defaultValue": "false", - "helpMarkDown": "ms-resource:loc.input.help.CreateWebSite" - }, - { - "name": "WebSiteName", - "type": "string", - "label": "ms-resource:loc.input.label.WebSiteName", - "required": true, - "groupName": "website", - "defaultValue": "", - "visibleRule": "CreateWebSite = true", - "helpMarkDown": "ms-resource:loc.input.help.WebSiteName" - }, - { - "name": "WebSitePhysicalPath", - "type": "string", - "label": "ms-resource:loc.input.label.WebSitePhysicalPath", - "required": true, - "groupName": "website", - "defaultValue": "%SystemDrive%\\inetpub\\wwwroot", - "visibleRule": "CreateWebSite = true", - "helpMarkDown": "ms-resource:loc.input.help.WebSitePhysicalPath" - }, - { - "name": "WebSitePhysicalPathAuth", - "type": "pickList", - "label": "ms-resource:loc.input.label.WebSitePhysicalPathAuth", - "required": true, - "groupName": "website", - "defaultValue": "Application User (Pass-through)", - "visibleRule": "CreateWebSite = true", - "options": { - "WebSiteUserPassThrough": "Application User (Pass-through)", - "WebSiteWindowsAuth": "Windows Authentication" - }, - "helpMarkDown": "ms-resource:loc.input.help.WebSitePhysicalPathAuth" - }, - { - "name": "WebSiteAuthUserName", - "type": "string", - "label": "ms-resource:loc.input.label.WebSiteAuthUserName", - "required": true, - "groupName": "website", - "defaultValue": "", - "visibleRule": "WebSitePhysicalPathAuth = WebSiteWindowsAuth", - "helpMarkDown": "ms-resource:loc.input.help.WebSiteAuthUserName" - }, - { - "name": "WebSiteAuthUserPassword", - "type": "string", - "label": "ms-resource:loc.input.label.WebSiteAuthUserPassword", - "required": false, - "groupName": "website", - "defaultValue": "", - "visibleRule": "WebSitePhysicalPathAuth = WebSiteWindowsAuth", - "helpMarkDown": "ms-resource:loc.input.help.WebSiteAuthUserPassword" - }, - { - "name": "AddBinding", - "type": "boolean", - "label": "ms-resource:loc.input.label.AddBinding", - "required": false, - "groupName": "website", - "defaultValue": "true", - "visibleRule": "CreateWebSite = true", - "helpMarkDown": "ms-resource:loc.input.help.AddBinding" - }, - { - "name": "AssignDuplicateBinding", - "type": "boolean", - "label": "ms-resource:loc.input.label.AssignDuplicateBinding", - "required": false, - "groupName": "website", - "defaultValue": "false", - "visibleRule": "AddBinding = true", - "helpMarkDown": "ms-resource:loc.input.help.AssignDuplicateBinding" - }, - { - "name": "Protocol", - "type": "pickList", - "label": "ms-resource:loc.input.label.Protocol", - "required": true, - "groupName": "website", - "defaultValue": "http", - "options": { - "https": "https", - "http": "http" - }, - "visibleRule": "AddBinding = true", - "helpMarkDown": "ms-resource:loc.input.help.Protocol" - }, - { - "name": "IPAddress", - "type": "string", - "label": "ms-resource:loc.input.label.IPAddress", - "required": true, - "groupName": "website", - "defaultValue": "All Unassigned", - "visibleRule": "AddBinding = true", - "helpMarkDown": "ms-resource:loc.input.help.IPAddress" - }, - { - "name": "Port", - "type": "string", - "label": "ms-resource:loc.input.label.Port", - "required": true, - "groupName": "website", - "defaultValue": "80", - "visibleRule": "AddBinding = true", - "helpMarkDown": "ms-resource:loc.input.help.Port" - }, - { - "name": "ServerNameIndication", - "type": "boolean", - "label": "ms-resource:loc.input.label.ServerNameIndication", - "required": false, - "groupName": "website", - "defaultValue": "false", - "visibleRule": "Protocol = https", - "helpMarkDown": "ms-resource:loc.input.help.ServerNameIndication" - }, - { - "name": "HostNameWithOutSNI", - "type": "string", - "label": "ms-resource:loc.input.label.HostNameWithOutSNI", - "required": false, - "groupName": "website", - "defaultValue": "", - "visibleRule": "ServerNameIndication = false", - "helpMarkDown": "ms-resource:loc.input.help.HostNameWithOutSNI" - }, - { - "name": "HostNameWithHttp", - "type": "string", - "label": "ms-resource:loc.input.label.HostNameWithHttp", - "required": false, - "groupName": "website", - "defaultValue": "", - "visibleRule": "Protocol = http", - "helpMarkDown": "ms-resource:loc.input.help.HostNameWithHttp" - }, - { - "name": "HostNameWithSNI", - "type": "string", - "label": "ms-resource:loc.input.label.HostNameWithSNI", - "required": true, - "groupName": "website", - "defaultValue": "", - "visibleRule": "ServerNameIndication = true", - "helpMarkDown": "ms-resource:loc.input.help.HostNameWithSNI" - }, - { - "name": "SSLCertThumbPrint", - "type": "string", - "label": "ms-resource:loc.input.label.SSLCertThumbPrint", - "required": true, - "groupName": "website", - "defaultValue": "", - "visibleRule": "Protocol = https", - "helpMarkDown": "ms-resource:loc.input.help.SSLCertThumbPrint" - }, - { - "name": "CreateAppPool", - "type": "boolean", - "label": "ms-resource:loc.input.label.CreateAppPool", - "required": false, - "groupName": "applicationPool", - "defaultValue": "false", - "helpMarkDown": "ms-resource:loc.input.help.CreateAppPool" - }, - { - "name": "AppPoolName", - "type": "string", - "label": "ms-resource:loc.input.label.AppPoolName", - "defaultValue": "", - "required": true, - "groupName": "applicationPool", - "visibleRule": "CreateAppPool = true", - "helpMarkDown": "ms-resource:loc.input.help.AppPoolName" - }, - { - "name": "DotNetVersion", - "type": "pickList", - "label": "ms-resource:loc.input.label.DotNetVersion", - "defaultValue": "v4.0", - "required": true, - "groupName": "applicationPool", - "visibleRule": "CreateAppPool = true", - "helpMarkDown": "ms-resource:loc.input.help.DotNetVersion", - "options": { - "v4.0": "v4.0", - "v2.0": "v2.0", - "No Managed Code": "No Managed Code" - } - }, - { - "name": "PipeLineMode", - "type": "pickList", - "label": "ms-resource:loc.input.label.PipeLineMode", - "defaultValue": "Integrated", - "required": true, - "groupName": "applicationPool", - "visibleRule": "CreateAppPool = true", - "helpMarkDown": "ms-resource:loc.input.help.PipeLineMode", - "options": { - "Integrated": "Integrated", - "Classic": "Classic" - } - }, - { - "name": "AppPoolIdentity", - "type": "pickList", - "label": "ms-resource:loc.input.label.AppPoolIdentity", - "defaultValue": "ApplicationPoolIdentity", - "required": true, - "groupName": "applicationPool", - "visibleRule": "CreateAppPool = true", - "helpMarkDown": "ms-resource:loc.input.help.AppPoolIdentity", - "options": { - "ApplicationPoolIdentity": "ApplicationPoolIdentity", - "LocalService": "LocalService", - "LocalSystem": "LocalSystem", - "NetworkService": "NetworkService", - "SpecificUser": "Custom Account" - } - }, - { - "name": "AppPoolUsername", - "type": "string", - "label": "ms-resource:loc.input.label.AppPoolUsername", - "defaultValue": "", - "required": true, - "groupName": "applicationPool", - "visibleRule": "AppPoolIdentity = SpecificUser" - }, - { - "name": "AppPoolPassword", - "type": "string", - "label": "ms-resource:loc.input.label.AppPoolPassword", - "defaultValue": "", - "required": false, - "helpMarkDown": "ms-resource:loc.input.help.AppPoolPassword", - "groupName": "applicationPool", - "visibleRule": "AppPoolIdentity = SpecificUser" - }, - { - "name": "AppCmdCommands", - "type": "multiLine", - "label": "ms-resource:loc.input.label.AppCmdCommands", - "required": false, - "groupName": "advanced", - "defaultValue": "", - "helpMarkDown": "ms-resource:loc.input.help.AppCmdCommands" - }, - { - "name": "DeployInParallel", - "type": "boolean", - "label": "ms-resource:loc.input.label.DeployInParallel", - "defaultValue": "true", - "required": false, - "groupName": "advanced", - "helpMarkDown": "ms-resource:loc.input.help.DeployInParallel" - }, - { - "name": "ResourceFilteringMethod", - "type": "radio", - "label": "ms-resource:loc.input.label.ResourceFilteringMethod", - "required": false, - "defaultValue": "machineNames", - "options": { - "machineNames": "Machine Names", - "tags": "Tags" - }, - "groupName": "advanced", - "helpMarkDown": "ms-resource:loc.input.help.ResourceFilteringMethod" - }, - { - "name": "MachineFilter", - "type": "string", - "label": "ms-resource:loc.input.label.MachineFilter", - "required": false, - "defaultValue": "", - "groupName": "advanced", - "helpMarkDown": "ms-resource:loc.input.help.MachineFilter" - } - ], - "instanceNameFormat": "ms-resource:loc.instanceNameFormat", - "execution": { - "PowerShell": { - "target": "$(currentDirectory)\\DeployIISWebApp.ps1", - "argumentFormat": "", - "workingDirectory": "$(currentDirectory)" - } - } -} \ No newline at end of file diff --git a/Tasks/IISWebAppDeploymentOnMachineGroup/package.json b/Tasks/IISWebAppDeploymentOnMachineGroup/package.json index 4fc23cbd07aa..0d11a311a1a3 100644 --- a/Tasks/IISWebAppDeploymentOnMachineGroup/package.json +++ b/Tasks/IISWebAppDeploymentOnMachineGroup/package.json @@ -18,7 +18,7 @@ "homepage": "https://github.com/Microsoft/vsts-tasks#readme", "dependencies": { - "q": "^1.4.1" + "q": "1.4.1" }, "devDependencies": { "mocha": "^3.1.2" diff --git a/Tasks/IISWebAppDeploymentOnMachineGroup/task.json b/Tasks/IISWebAppDeploymentOnMachineGroup/task.json index 6523f5b8c2ae..1f2c151dfe26 100644 --- a/Tasks/IISWebAppDeploymentOnMachineGroup/task.json +++ b/Tasks/IISWebAppDeploymentOnMachineGroup/task.json @@ -16,7 +16,7 @@ "version": { "Major": 0, "Minor": 0, - "Patch": 2 + "Patch": 3 }, "demands": [ ], diff --git a/Tasks/IISWebAppDeploymentOnMachineGroup/task.loc.json b/Tasks/IISWebAppDeploymentOnMachineGroup/task.loc.json index 0c066d159f3a..cbd5d9966591 100644 --- a/Tasks/IISWebAppDeploymentOnMachineGroup/task.loc.json +++ b/Tasks/IISWebAppDeploymentOnMachineGroup/task.loc.json @@ -16,7 +16,7 @@ "version": { "Major": 0, "Minor": 0, - "Patch": 2 + "Patch": 3 }, "demands": [], "minimumAgentVersion": "1.102.0", diff --git a/Tasks/JenkinsDownloadArtifacts/task.json b/Tasks/JenkinsDownloadArtifacts/task.json index af99dd6c6a33..2bd715f101de 100644 --- a/Tasks/JenkinsDownloadArtifacts/task.json +++ b/Tasks/JenkinsDownloadArtifacts/task.json @@ -8,13 +8,17 @@ "visibility": [ "Build", "Release" + ], + "runsOn": [ + "Agent", + "MachineGroup" ], "author": "Microsoft", "demands": [], "version": { "Major": 1, "Minor": 0, - "Patch": 3 + "Patch": 4 }, "groups": [ { diff --git a/Tasks/JenkinsDownloadArtifacts/task.loc.json b/Tasks/JenkinsDownloadArtifacts/task.loc.json index f66065f29ae2..4ead7e19c168 100644 --- a/Tasks/JenkinsDownloadArtifacts/task.loc.json +++ b/Tasks/JenkinsDownloadArtifacts/task.loc.json @@ -9,12 +9,16 @@ "Build", "Release" ], + "runsOn": [ + "Agent", + "MachineGroup" + ], "author": "Microsoft", "demands": [], "version": { "Major": 1, "Minor": 0, - "Patch": 3 + "Patch": 4 }, "groups": [ { diff --git a/Tasks/JenkinsQueueJob/Strings/resources.resjson/en-US/resources.resjson b/Tasks/JenkinsQueueJob/Strings/resources.resjson/en-US/resources.resjson index ddb795a95ea6..1844d5d873af 100644 --- a/Tasks/JenkinsQueueJob/Strings/resources.resjson/en-US/resources.resjson +++ b/Tasks/JenkinsQueueJob/Strings/resources.resjson/en-US/resources.resjson @@ -5,15 +5,15 @@ "loc.instanceNameFormat": "Queue Jenkins Job: $(jobName)", "loc.group.displayName.advanced": "Advanced", "loc.input.label.serverEndpoint": "Jenkins service endpoint", - "loc.input.help.serverEndpoint": "Select the service endpoint for your Jenkins instance. To create one, click the Manage link and create a new Jenkins Service Endpoint.", + "loc.input.help.serverEndpoint": "Select the service endpoint for your Jenkins instance. To create one, click the Manage link and create a new Jenkins service endpoint.", "loc.input.label.jobName": "Job name", "loc.input.help.jobName": "The name of the Jenkins job to queue. This must exactly match the job name on the Jenkins server.", "loc.input.label.captureConsole": "Capture console output and wait for completion", "loc.input.help.captureConsole": "If selected, this step will capture the Jenkins build console output, wait for the Jenkins build to complete, and succeed/fail based on the Jenkins build result. Otherwise, once the Jenkins job is successfully queued, this step will successfully complete without waiting for the Jenkins build to run.", "loc.input.label.capturePipeline": "Capture pipeline output and wait for pipeline completion", - "loc.input.help.capturePipeline": "If selected, this step will capture the full Jenkins build pipeline console output, wait for the full Jenkins build pipeline to complete, and succeed/fail based on the Jenkins build pipeline result. Otherwise, once the Jenkins job is completes, this step will successfully complete without waiting for full Jenkins build pipeline to run.", + "loc.input.help.capturePipeline": "If selected, this step will capture the full Jenkins build pipeline console output, wait for the full Jenkins build pipeline to complete, and succeed/fail based on the Jenkins build pipeline result. Otherwise, once the first Jenkins job completes, this step will successfully complete without waiting for full Jenkins build pipeline to run.", "loc.input.label.parameterizedJob": "Parameterized job", - "loc.input.help.parameterizedJob": "Select if the Jenkins job accepts parameters. This should be selected even if all the default parameters are used and no parameters are actually specified.", + "loc.input.help.parameterizedJob": "Select if the Jenkins job accepts parameters. This should be selected even if all default parameter values are used and no parameters are actually specified.", "loc.input.label.jobParameters": "Job parameters", - "loc.input.help.jobParameters": "Specify job parameters, one per line, in the form `=`

To set a parameter to an empty value (useful for overriding a default value) leave off the paramter value, e.g. specify `=`

Variables are supported, e.g. to define the `commitId` paramter to be the `git commit ID` for the build, use: `commitId=$(Build.SourceVersion)`. See the [documentation on variables](https://www.visualstudio.com/docs/build/define/variables) for more details.

Supported Jenkins parameter types are:

  • `Boolean`
  • `String`
  • `Choice`
  • `Password`
" + "loc.input.help.jobParameters": "Specify job parameters, one per line, in the form `=`

To set a parameter to an empty value (useful for overriding a default value), leave off the parameter value. For example, specify `=`

Variables are supported. For example, to set a `commitId` parameter value to the Git commit ID of the build, use: `commitId=$(Build.SourceVersion)`. See the [documentation on variables](https://www.visualstudio.com/docs/build/define/variables) for more details.

Supported Jenkins parameter types are:

  • `Boolean`
  • `Choice`
  • `Password`
  • `String`
" } \ No newline at end of file diff --git a/Tasks/JenkinsQueueJob/job.ts b/Tasks/JenkinsQueueJob/job.ts index 44ec2fc7fafe..66eea27a1914 100644 --- a/Tasks/JenkinsQueueJob/job.ts +++ b/Tasks/JenkinsQueueJob/job.ts @@ -17,16 +17,25 @@ import unzip = require('./unzip'); import * as Util from './util'; +// Jobs transition between states as follows: +// ------------------------------------------ +// BEGINNING STATE: New +// New → Locating, Streaming, Joined, Cut +// Locating → Streaming, Joined, Cut +// Streaming → Finishing +// Finishing → Downloading, Queued, Done +// Downloading → Done +// TERMINAL STATES: Done, Queued, Joined, Cut export enum JobState { - New, // 0 - Locating, // 1 - Streaming, // 2 - Finishing, // 3 - Done, // 4 - Joined, // 5 - Queued, // 6 - Cut, // 7 - Downloading// 8 + New, // 0 - The job is yet to begin + Locating, // 1 - The job is being located + Streaming, // 2 - The job is running and its console output is streaming + Finishing, // 3 - The job has run and is "finishing" + Done, // 4 - The job has run and is done + Joined, // 5 - The job is considered complete because it has been joined to the execution of another matching job execution + Queued, // 6 - The job was queued and will not be tracked for completion (as specified by the "Capture..." task setting) + Cut, // 7 - The job was cut from execution by the pipeline + Downloading// 8 - The job has run and its results are being downloaded (occurs when the TFS Plugin for Jenkins is installed) } export class Job { @@ -98,7 +107,7 @@ export class Job { } else if (oldState == JobState.Streaming) { validStateChange = (newState == JobState.Finishing); } else if (oldState == JobState.Finishing) { - validStateChange = (newState == JobState.Downloading || newState == JobState.Done); + validStateChange = (newState == JobState.Downloading || newState == JobState.Queued || newState == JobState.Done); } else if (oldState == JobState.Downloading) { validStateChange = (newState == JobState.Done); } else if (oldState == JobState.Done || oldState == JobState.Joined || oldState == JobState.Cut) { @@ -281,7 +290,7 @@ export class Job { /** * Checks the success of the job * - * JobState = Finishing, transition to Done or Queued possible + * JobState = Finishing, transition to Downloading, Done, or Queued possible */ finish(): void { var thisJob: Job = this; diff --git a/Tasks/JenkinsQueueJob/jobsearch.ts b/Tasks/JenkinsQueueJob/jobsearch.ts index 1c42abd5ecb9..0e3a14c8f722 100644 --- a/Tasks/JenkinsQueueJob/jobsearch.ts +++ b/Tasks/JenkinsQueueJob/jobsearch.ts @@ -119,7 +119,11 @@ export class JobSearch { for (var i in causes) { var job = thisSearch.queue.findJob(causes[i].upstreamUrl, causes[i].upstreamBuild); if (job) { // we know about it - if (job.state == JobState.Streaming || job.state == JobState.Finishing || job.state == JobState.Done) { + if (job.state == JobState.Streaming || + job.state == JobState.Finishing || + job.state == JobState.Downloading || + job.state == JobState.Queued || + job.state == JobState.Done) { causesThatRan.push(job); } else if (job.state == JobState.New || job.state == JobState.Locating) { causesThatMayRun.push(job); @@ -264,7 +268,17 @@ export class JobSearch { * So, for all jobs being tracked (within this code), one is consisdered the main job (which will be followed), and * all others are considered joined and will not be tracked further. */ - var causes : any = parsedBody.actions[0].causes; + var findCauses = function(actions) { + for (var i in actions) { + if (actions[i].causes) { + return actions[i].causes; + } + } + + return null; + }; + + var causes : any = findCauses(parsedBody.actions); thisSearch.foundCauses[thisSearch.nextSearchBuildNumber] = causes; thisSearch.determineMainJob(thisSearch.nextSearchBuildNumber, function (mainJob: Job, secondaryJobs: Job[]) { if (mainJob != null) { diff --git a/Tasks/JenkinsQueueJob/task.json b/Tasks/JenkinsQueueJob/task.json index fae520ce8648..ff79f05a10c2 100644 --- a/Tasks/JenkinsQueueJob/task.json +++ b/Tasks/JenkinsQueueJob/task.json @@ -14,7 +14,7 @@ "version": { "Major": 1, "Minor": 1, - "Patch": 3 + "Patch": 5 }, "groups": [ { @@ -31,7 +31,7 @@ "label": "Jenkins service endpoint", "defaultValue": "", "required": true, - "helpMarkDown": "Select the service endpoint for your Jenkins instance. To create one, click the Manage link and create a new Jenkins Service Endpoint." + "helpMarkDown": "Select the service endpoint for your Jenkins instance. To create one, click the Manage link and create a new Jenkins service endpoint." }, { "name": "jobName", @@ -55,7 +55,7 @@ "label": "Capture pipeline output and wait for pipeline completion", "defaultValue": true, "required": true, - "helpMarkDown": "If selected, this step will capture the full Jenkins build pipeline console output, wait for the full Jenkins build pipeline to complete, and succeed/fail based on the Jenkins build pipeline result. Otherwise, once the Jenkins job is completes, this step will successfully complete without waiting for full Jenkins build pipeline to run.", + "helpMarkDown": "If selected, this step will capture the full Jenkins build pipeline console output, wait for the full Jenkins build pipeline to complete, and succeed/fail based on the Jenkins build pipeline result. Otherwise, once the first Jenkins job completes, this step will successfully complete without waiting for full Jenkins build pipeline to run.", "visibleRule": "captureConsole = true" }, { @@ -64,7 +64,7 @@ "label": "Parameterized job", "defaultValue": false, "required": true, - "helpMarkDown": "Select if the Jenkins job accepts parameters. This should be selected even if all the default parameters are used and no parameters are actually specified.", + "helpMarkDown": "Select if the Jenkins job accepts parameters. This should be selected even if all default parameter values are used and no parameters are actually specified.", "groupName": "advanced" }, { @@ -73,7 +73,7 @@ "label": "Job parameters", "defaultValue": "", "required": false, - "helpMarkDown": "Specify job parameters, one per line, in the form `=`

To set a parameter to an empty value (useful for overriding a default value) leave off the paramter value, e.g. specify `=`

Variables are supported, e.g. to define the `commitId` paramter to be the `git commit ID` for the build, use: `commitId=$(Build.SourceVersion)`. See the [documentation on variables](https://www.visualstudio.com/docs/build/define/variables) for more details.

Supported Jenkins parameter types are:

  • `Boolean`
  • `String`
  • `Choice`
  • `Password`
", + "helpMarkDown": "Specify job parameters, one per line, in the form `=`

To set a parameter to an empty value (useful for overriding a default value), leave off the parameter value. For example, specify `=`

Variables are supported. For example, to set a `commitId` parameter value to the Git commit ID of the build, use: `commitId=$(Build.SourceVersion)`. See the [documentation on variables](https://www.visualstudio.com/docs/build/define/variables) for more details.

Supported Jenkins parameter types are:

  • `Boolean`
  • `Choice`
  • `Password`
  • `String`
", "groupName": "advanced", "visibleRule": "parameterizedJob = true", "properties": { @@ -88,4 +88,4 @@ "argumentFormat": "" } } -} \ No newline at end of file +} diff --git a/Tasks/JenkinsQueueJob/task.loc.json b/Tasks/JenkinsQueueJob/task.loc.json index 67d449866d56..1775cad115bf 100644 --- a/Tasks/JenkinsQueueJob/task.loc.json +++ b/Tasks/JenkinsQueueJob/task.loc.json @@ -14,7 +14,7 @@ "version": { "Major": 1, "Minor": 1, - "Patch": 3 + "Patch": 5 }, "groups": [ { diff --git a/Tasks/Maven/README.md b/Tasks/Maven/README.md index e0af3359e3fe..ee497548278b 100644 --- a/Tasks/Maven/README.md +++ b/Tasks/Maven/README.md @@ -37,10 +37,16 @@ Use the next options to manage your `JAVA_HOME` attribute by JDK Version and Pat - **JDK Architecture :** Select the approriate JDK Architecture. By default it is set to `x86` -####SonarQube Analysis +####Code Analysis - **Run SonarQube Analysis :** You can choose to run SonarQube analysis after executing the current goals. 'install' or 'package' goals should be executed first. To know more about this option [click here](https://blogs.msdn.com/b/visualstudioalm/archive/2015/10/08/the-maven-build-task-now-simplifies-sonarqube-analysis.aspx) +- **Run Checkstyle :** You can choose to run the Checkstyle static code analysis tool, which checks the compliance of your source code with coding rules. You will receive a code analysis report with the number of violations detected, as well as the original report files if there were any violations. + +- **Run PMD :** You can choose to run the PMD static code analysis tool, which examines your source code for possible bugs. You will receive a code analysis report with the number of violations detected, as well as the original report files if there were any violations. + +- **Run FindBugs :** You can choose to run the FindBugs static code analysis tool, which examines the bytecode of your program for possible bugs. You will receive a code analysis report with the number of violations detected, as well as the original report files if there were any violations. + diff --git a/Tasks/Maven/task.json b/Tasks/Maven/task.json index 16818377b75a..b0c4d4fd6c5d 100644 --- a/Tasks/Maven/task.json +++ b/Tasks/Maven/task.json @@ -8,6 +8,10 @@ "visibility": [ "Build", "Release" + ], + "runsOn": [ + "Agent", + "MachineGroup" ], "author": "Microsoft Corporation", "demands": [ @@ -16,7 +20,7 @@ "version": { "Major": 1, "Minor": 0, - "Patch": 76 + "Patch": 77 }, "minimumAgentVersion": "1.89.0", "instanceNameFormat": "Maven $(mavenPOMFile)", diff --git a/Tasks/Maven/task.loc.json b/Tasks/Maven/task.loc.json index d43f5312cdf2..f557af7d8b51 100644 --- a/Tasks/Maven/task.loc.json +++ b/Tasks/Maven/task.loc.json @@ -9,6 +9,10 @@ "Build", "Release" ], + "runsOn": [ + "Agent", + "MachineGroup" + ], "author": "Microsoft Corporation", "demands": [ "maven" @@ -16,7 +20,7 @@ "version": { "Major": 1, "Minor": 0, - "Patch": 76 + "Patch": 77 }, "minimumAgentVersion": "1.89.0", "instanceNameFormat": "ms-resource:loc.instanceNameFormat", diff --git a/Tasks/Npm/task.json b/Tasks/Npm/task.json index 8b5d6d8cf9b7..1e260904b3ac 100644 --- a/Tasks/Npm/task.json +++ b/Tasks/Npm/task.json @@ -11,6 +11,10 @@ "Minor": 2, "Patch": 20 }, + "runsOn": [ + "Agent", + "MachineGroup" + ], "demands": [ "npm" ], diff --git a/Tasks/Npm/task.loc.json b/Tasks/Npm/task.loc.json index 4f4ccf9218fa..d858a5130fbb 100644 --- a/Tasks/Npm/task.loc.json +++ b/Tasks/Npm/task.loc.json @@ -9,8 +9,12 @@ "version": { "Major": 0, "Minor": 2, - "Patch": 19 + "Patch": 20 }, + "runsOn": [ + "Agent", + "MachineGroup" + ], "demands": [ "npm" ], diff --git a/Tasks/NuGetInstaller/task.json b/Tasks/NuGetInstaller/task.json index a219a4dcf9fc..5965db5b5dd6 100644 --- a/Tasks/NuGetInstaller/task.json +++ b/Tasks/NuGetInstaller/task.json @@ -9,8 +9,12 @@ "version": { "Major": 0, "Minor": 2, - "Patch": 24 + "Patch": 25 }, + "runsOn": [ + "Agent", + "MachineGroup" + ], "minimumAgentVersion": "1.83.0", "groups": [ { diff --git a/Tasks/NuGetInstaller/task.loc.json b/Tasks/NuGetInstaller/task.loc.json index ee813d5f9ea9..3ec1d98acc1f 100644 --- a/Tasks/NuGetInstaller/task.loc.json +++ b/Tasks/NuGetInstaller/task.loc.json @@ -9,8 +9,12 @@ "version": { "Major": 0, "Minor": 2, - "Patch": 24 + "Patch": 25 }, + "runsOn": [ + "Agent", + "MachineGroup" + ], "minimumAgentVersion": "1.83.0", "groups": [ { diff --git a/Tasks/NuGetPublisher/task.json b/Tasks/NuGetPublisher/task.json index 4a95f901387d..c156f1f8b83c 100644 --- a/Tasks/NuGetPublisher/task.json +++ b/Tasks/NuGetPublisher/task.json @@ -9,8 +9,12 @@ "version": { "Major": 0, "Minor": 2, - "Patch": 24 + "Patch": 25 }, + "runsOn": [ + "Agent", + "MachineGroup" + ], "demands": [ "Cmd" ], diff --git a/Tasks/NuGetPublisher/task.loc.json b/Tasks/NuGetPublisher/task.loc.json index bdcf32a5090f..dfd110a91825 100644 --- a/Tasks/NuGetPublisher/task.loc.json +++ b/Tasks/NuGetPublisher/task.loc.json @@ -9,8 +9,12 @@ "version": { "Major": 0, "Minor": 2, - "Patch": 24 + "Patch": 25 }, + "runsOn": [ + "Agent", + "MachineGroup" + ], "demands": [ "Cmd" ], diff --git a/Tasks/PublishCodeCoverageResults/task.json b/Tasks/PublishCodeCoverageResults/task.json index 84e1a7621b99..0ef863a7c638 100644 --- a/Tasks/PublishCodeCoverageResults/task.json +++ b/Tasks/PublishCodeCoverageResults/task.json @@ -7,12 +7,16 @@ "category": "Test", "visibility": [ "Build" + ], + "runsOn": [ + "Agent", + "MachineGroup" ], "author": "Microsoft Corporation", "version": { "Major": 1, "Minor": 0, - "Patch": 16 + "Patch": 17 }, "demands": [], "minimumAgentVersion": "1.90.0", diff --git a/Tasks/PublishCodeCoverageResults/task.loc.json b/Tasks/PublishCodeCoverageResults/task.loc.json index e80d1c93dcc2..8cb72aa126f5 100644 --- a/Tasks/PublishCodeCoverageResults/task.loc.json +++ b/Tasks/PublishCodeCoverageResults/task.loc.json @@ -8,11 +8,15 @@ "visibility": [ "Build" ], + "runsOn": [ + "Agent", + "MachineGroup" + ], "author": "Microsoft Corporation", "version": { "Major": 1, "Minor": 0, - "Patch": 16 + "Patch": 17 }, "demands": [], "minimumAgentVersion": "1.90.0", diff --git a/Tasks/QuickPerfTest/CltTasksUtility.ps1 b/Tasks/QuickPerfTest/CltTasksUtility.ps1 index 1818ea42f172..7ce94246cf0c 100644 --- a/Tasks/QuickPerfTest/CltTasksUtility.ps1 +++ b/Tasks/QuickPerfTest/CltTasksUtility.ps1 @@ -1,9 +1,9 @@ function InvokeRestMethod($headers, $contentType, $uri , $method= "Get", $body) { - $ServicePoint = [System.Net.ServicePointManager]::FindServicePoint($uri) - $result = Invoke-RestMethod -ContentType "application/json" -UserAgent $global:userAgent -TimeoutSec $global:RestTimeout -Uri $uri -Method $method -Headers $headers -Body $body - $ServicePoint.CloseConnectionGroup("") - return $result + $ServicePoint = [System.Net.ServicePointManager]::FindServicePoint($uri) + $result = Invoke-RestMethod -ContentType "application/json" -UserAgent $global:userAgent -TimeoutSec $global:RestTimeout -Uri $uri -Method $method -Headers $headers -Body $body + $ServicePoint.CloseConnectionGroup("") + return $result } function ComposeTestDropJson($name, $duration, $homepage, $vu, $geoLocation) @@ -28,32 +28,32 @@ function ComposeTestDropJson($name, $duration, $homepage, $vu, $geoLocation) } "@ - return $tdjson + return $tdjson } function CreateTestDrop($headers, $dropJson, $CltAccountUrl) { - $uri = [String]::Format("{0}/_apis/clt/testdrops?api-version=1.0", $CltAccountUrl) - $drop = InvokeRestMethod -contentType "application/json" -uri $uri -method Post -headers $headers -body $dropJson + $uri = [String]::Format("{0}/_apis/clt/testdrops?api-version=1.0", $CltAccountUrl) + $drop = InvokeRestMethod -contentType "application/json" -uri $uri -method Post -headers $headers -body $dropJson - return $drop + return $drop } function GetTestDrop($headers, $drop, $CltAccountUrl) { - $uri = [String]::Format("{0}/_apis/clt/testdrops/{1}?api-version=1.0", $CltAccountUrl, $drop.id) - $testdrop = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers + $uri = [String]::Format("{0}/_apis/clt/testdrops/{1}?api-version=1.0", $CltAccountUrl, $drop.id) + $testdrop = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers - return $testdrop + return $testdrop } function UploadTestDrop($testdrop) { - $uri = New-Object System.Uri($testdrop.accessData.dropContainerUrl) - $sas = New-Object Microsoft.WindowsAzure.Storage.Auth.StorageCredentials($testdrop.accessData.sasKey) - $container = New-Object Microsoft.WindowsAzure.Storage.Blob.CloudBlobContainer($uri, $sas) + $uri = New-Object System.Uri($testdrop.accessData.dropContainerUrl) + $sas = New-Object Microsoft.WindowsAzure.Storage.Auth.StorageCredentials($testdrop.accessData.sasKey) + $container = New-Object Microsoft.WindowsAzure.Storage.Blob.CloudBlobContainer($uri, $sas) - return $container + return $container } #function GetTestRuns($headers, $CltAccountUrl) @@ -66,59 +66,59 @@ function UploadTestDrop($testdrop) function GetTestRunUri($testRunId, $headers, $CltAccountUrl) { - $uri = [String]::Format("{0}/_apis/clt/testruns/{1}?api-version=1.0", $CltAccountUrl,$testRunId) - $run = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers - - return $run.WebResultUrl + $uri = [String]::Format("{0}/_apis/clt/testruns/{1}?api-version=1.0", $CltAccountUrl,$testRunId) + $run = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers + + return $run.WebResultUrl } function RunInProgress($run) { - return $run.state -eq "queued" -or $run.state -eq "inProgress" + return $run.state -eq "queued" -or $run.state -eq "inProgress" } function MonitorTestRun($headers, $run, $CltAccountUrl) { - $uri = [String]::Format("{0}/_apis/clt/testruns/{1}?api-version=1.0", $CltAccountUrl, $run.id) - $prevState = $run.state - $prevSubState = $run.subState - Write-Output ("Load test '{0}' is in state '{1}|{2}'." -f $run.name, $run.state, $run.subState) - - do - { - Start-Sleep -s 15 - $run = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers - if ($prevState -ne $run.state -or $prevSubState -ne $run.subState) - { - $prevState = $run.state - $prevSubState = $run.subState - Write-Output ("Load test '{0}' is in state '{1}|{2}'." -f $run.name, $run.state, $run.subState) - } - } - while (RunInProgress $run) - - $run = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers - Write-Output "------------------------------------" - $uri = [String]::Format("{0}/_apis/clt/testruns/{1}/messages?api-version=1.0", $CltAccountUrl, $run.id) - $messages = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers - - if ($messages) - { - $timeSorted = $messages.value | Sort-Object loggedDate - foreach ($message in $timeSorted) - { - switch ($message.messageType) - { - "info" { Write-Host -NoNewline ("[Message]{0}" -f $message.message) } - "output" { Write-Host -NoNewline ("[Output]{0}" -f $message.message) } - "warning" { Write-Warning $message.message } - "error" { Write-Error $message.message } - "critical" { Write-Error $message.message } - } - } - } - - Write-Output "------------------------------------" + $uri = [String]::Format("{0}/_apis/clt/testruns/{1}?api-version=1.0", $CltAccountUrl, $run.id) + $prevState = $run.state + $prevSubState = $run.subState + Write-Output ("Load test '{0}' is in state '{1}|{2}'." -f $run.name, $run.state, $run.subState) + + do + { + Start-Sleep -s 15 + $run = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers + if ($prevState -ne $run.state -or $prevSubState -ne $run.subState) + { + $prevState = $run.state + $prevSubState = $run.subState + Write-Output ("Load test '{0}' is in state '{1}|{2}'." -f $run.name, $run.state, $run.subState) + } + } + while (RunInProgress $run) + + $run = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers + Write-Output "------------------------------------" + $uri = [String]::Format("{0}/_apis/clt/testruns/{1}/messages?api-version=1.0", $CltAccountUrl, $run.id) + $messages = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers + + if ($messages) + { + $timeSorted = $messages.value | Sort-Object loggedDate + foreach ($message in $timeSorted) + { + switch ($message.messageType) + { + "info" { Write-Host -NoNewline ("[Message]{0}" -f $message.message) } + "output" { Write-Host -NoNewline ("[Output]{0}" -f $message.message) } + "warning" { Write-Warning $message.message } + "error" { Write-Error $message.message } + "critical" { Write-Error $message.message } + } + } + } + + Write-Output "------------------------------------" } function ComposeTestRunJson($name, $tdid, $machineType) @@ -134,44 +134,44 @@ function ComposeTestRunJson($name, $tdid, $machineType) } "@ - return $trjson + return $trjson } function QueueTestRun($headers, $runJson, $CltAccountUrl) { - $uri = [String]::Format("{0}/_apis/clt/testruns?api-version=1.0", $CltAccountUrl) - $run = InvokeRestMethod -contentType "application/json" -uri $uri -method Post -headers $headers -body $runJson + $uri = [String]::Format("{0}/_apis/clt/testruns?api-version=1.0", $CltAccountUrl) + $run = InvokeRestMethod -contentType "application/json" -uri $uri -method Post -headers $headers -body $runJson $start = @" { - "state": "queued" + "state": "queued" } "@ - $uri = [String]::Format("{0}/_apis/clt/testruns/{1}?api-version=1.0", $CltAccountUrl, $run.id) - InvokeRestMethod -contentType "application/json" -uri $uri -method Patch -headers $headers -body $start - $run = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers + $uri = [String]::Format("{0}/_apis/clt/testruns/{1}?api-version=1.0", $CltAccountUrl, $run.id) + InvokeRestMethod -contentType "application/json" -uri $uri -method Patch -headers $headers -body $start + $run = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers - return $run + return $run } function ComposeAccountUrl($connectedServiceUrl, $headers) { #Load all dependent files for execution - . $PSScriptRoot/VssConnectionHelper.ps1 + . $PSScriptRoot/VssConnectionHelper.ps1 $connectedServiceUrl = $connectedServiceUrl.TrimEnd('/') Write-Host "Getting Clt Endpoint:" $elsUrl = Get-CltEndpoint $connectedServiceUrl $headers - return $elsUrl + return $elsUrl } function ValidateInputs($websiteUrl, $tfsCollectionUrl, $connectedServiceName) { - if (![System.Uri]::IsWellFormedUriString($websiteUrl, [System.UriKind]::Absolute)) - { - throw "Website Url is not well formed." - } + if (![System.Uri]::IsWellFormedUriString($websiteUrl, [System.UriKind]::Absolute)) + { + throw "Website Url is not well formed." + } if([string]::IsNullOrWhiteSpace($connectedServiceName) -and $tfsCollectionUrl -notlike "*VISUALSTUDIO.COM*" -and $tfsCollectionUrl -notlike "*TFSALLIN.NET*") { @@ -189,3 +189,10 @@ function UploadSummaryMdReport($summaryMdPath) } } +function IsNumericValue ($str) { + $numericValue = 0 + $isNum = [System.Int32]::TryParse($str, [ref]$numericValue) + return $isNum +} + + diff --git a/Tasks/QuickPerfTest/CltThresholdValidationHelper.ps1 b/Tasks/QuickPerfTest/CltThresholdValidationHelper.ps1 new file mode 100644 index 000000000000..ea7e6c6971e4 --- /dev/null +++ b/Tasks/QuickPerfTest/CltThresholdValidationHelper.ps1 @@ -0,0 +1,37 @@ +function GetResultsSummary($cltAccountUrl,$headers,$testRunId) +{ + $getResultsSummaryUri = [string]::Format("{0}/_apis/clt/testRuns/{1}/ResultSummary", $cltAccountUrl, $testRunId) + $resultsSummary = InvokeRestMethod -Uri $getResultsSummaryUri -contentType "application/json" -headers $headers -Method Get + if($resultsSummary -eq $null) + { + throw "Unable to fetch the result summary for the run" + } + return $resultsSummary +} + +function ValidateAvgResponseTimeThresholdInput($avgResponseTimeThreshold) +{ + if ($avgResponseTimeThreshold -eq 0) + { + return $null + } + + if(((IsNumericValue $avgResponseTimeThreshold) -ne $true) -or [System.Int32]$avgResponseTimeThreshold -lt 0) + { + throw "Avg. Response Time threshold should be a positive numeric value.Please specify a valid threshold value and try again " + } + return $avgResponseTimeThreshold +} + +function ValidateAvgResponseTimeThreshold($cltAccountUrl,$headers,$testRunId,$avgResponseTimeThreshold) +{ + $resultsSummary = GetResultsSummary $cltAccountUrl $headers $testRunId + if($resultsSummary -and $resultsSummary.overallRequestSummary -and $resultsSummary.overallRequestSummary.averageResponseTime) + { + return ($resultsSummary.overallRequestSummary.averageResponseTime -lt ($avgResponseTimeThreshold/1000)) + } + else + { + throw "Unable to fetch the result summary for the run" + } +} \ No newline at end of file diff --git a/Tasks/QuickPerfTest/Invoke-QuickPerfTest.ps1 b/Tasks/QuickPerfTest/Invoke-QuickPerfTest.ps1 index 07e5ef655423..1e127f06d79f 100644 --- a/Tasks/QuickPerfTest/Invoke-QuickPerfTest.ps1 +++ b/Tasks/QuickPerfTest/Invoke-QuickPerfTest.ps1 @@ -1,53 +1,55 @@ [CmdletBinding(DefaultParameterSetName = 'None')] param ( - [String] - $env:SYSTEM_DEFINITIONID, - [String] - $env:BUILD_BUILDID, - - [String] [Parameter(Mandatory = $false)] - $connectedServiceName, - - [String] [Parameter(Mandatory = $true)] - $websiteUrl, - [String] [Parameter(Mandatory = $true)] - $testName, - [String] [Parameter(Mandatory = $true)] - $vuLoad, - [String] [Parameter(Mandatory = $true)] - $runDuration, - [String] [Parameter(Mandatory = $true)] - $geoLocation, - [String] [Parameter(Mandatory = $true)] - $machineType +[String] +$env:SYSTEM_DEFINITIONID, +[String] +$env:BUILD_BUILDID, + +[String] [Parameter(Mandatory = $false)] +$connectedServiceName, + +[String] [Parameter(Mandatory = $true)] +$websiteUrl, +[String] [Parameter(Mandatory = $true)] +$testName, +[String] [Parameter(Mandatory = $true)] +$vuLoad, +[String] [Parameter(Mandatory = $true)] +$runDuration, +[String] [Parameter(Mandatory = $true)] +$geoLocation, +[String] [Parameter(Mandatory = $true)] +$machineType, +[String] [Parameter(Mandatory = $false)] +$avgResponseTimeThreshold ) function InitializeRestHeaders() { - $restHeaders = New-Object -TypeName "System.Collections.Generic.Dictionary[[String], [String]]" + $restHeaders = New-Object -TypeName "System.Collections.Generic.Dictionary[[String], [String]]" if([string]::IsNullOrWhiteSpace($connectedServiceName)) { - $patToken = Get-AccessToken $connectedServiceDetails + $patToken = GetAccessToken $connectedServiceDetails ValidatePatToken $patToken $restHeaders.Add("Authorization", [String]::Concat("Bearer ", $patToken)) - - } + + } else { - $Username = $connectedServiceDetails.Authorization.Parameters.Username - Write-Verbose "Username = $Username" -Verbose - $Password = $connectedServiceDetails.Authorization.Parameters.Password - $alternateCreds = [String]::Concat($Username, ":", $Password) - $basicAuth = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($alternateCreds)) - $restHeaders.Add("Authorization", [String]::Concat("Basic ", $basicAuth)) + $Username = $connectedServiceDetails.Authorization.Parameters.Username + Write-Verbose "Username = $Username" -Verbose + $Password = $connectedServiceDetails.Authorization.Parameters.Password + $alternateCreds = [String]::Concat($Username, ":", $Password) + $basicAuth = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($alternateCreds)) + $restHeaders.Add("Authorization", [String]::Concat("Basic ", $basicAuth)) } - return $restHeaders + return $restHeaders } -function Get-AccessToken($vssEndPoint) +function GetAccessToken($vssEndPoint) { - return $vssEndpoint.Authorization.Parameters.AccessToken + return $vssEndpoint.Authorization.Parameters.AccessToken } function ValidatePatToken($token) @@ -58,10 +60,11 @@ function ValidatePatToken($token) } } - # Load all dependent files for execution - . $PSScriptRoot/CltTasksUtility.ps1 - . $PSScriptRoot/VssConnectionHelper.ps1 - +# Load all dependent files for execution +. $PSScriptRoot/CltTasksUtility.ps1 +. $PSScriptRoot/VssConnectionHelper.ps1 +. $PSScriptRoot/CltThresholdValidationHelper + $userAgent = "QuickPerfTestBuildTask" $global:RestTimeout = 60 @@ -85,13 +88,18 @@ Write-Output "Run source identifier = build/$env:SYSTEM_DEFINITIONID/$env:BUILD_ #Validate Input ValidateInputs $websiteUrl $env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI $connectedServiceName +#Process Threshold Rules +Write-Output "Initializing threshold rule for avg. response time with value(ms) : $avgResponseTimeThreshold " +$avgResponseTimeThreshold = ValidateAvgResponseTimeThresholdInput $avgResponseTimeThreshold + +#Initialize Connected Service Details if([string]::IsNullOrWhiteSpace($connectedServiceName)) { $connectedServiceDetails = Get-ServiceEndpoint -Context $distributedTaskContext -Name SystemVssConnection } else { - $connectedServiceDetails = Get-ServiceEndpoint -Context $distributedTaskContext -Name $connectedServiceName + $connectedServiceDetails = Get-ServiceEndpoint -Context $distributedTaskContext -Name $connectedServiceName } $VSOAccountUrl = $connectedServiceDetails.Url.AbsoluteUri @@ -109,30 +117,54 @@ $drop = CreateTestDrop $headers $dropjson $CltAccountUrl if ($drop.dropType -eq "InPlaceDrop") { - $runJson = ComposeTestRunJson $testName $drop.id $MachineType - $run = QueueTestRun $headers $runJson $CltAccountUrl - MonitorTestRun $headers $run $CltAccountUrl - $webResultsUrl = GetTestRunUri $run.id $headers $CltAccountUrl + $runJson = ComposeTestRunJson $testName $drop.id $MachineType + $run = QueueTestRun $headers $runJson $CltAccountUrl + MonitorTestRun $headers $run $CltAccountUrl + $webResultsUrl = GetTestRunUri $run.id $headers $CltAccountUrl + + Write-Output ("Run-id for this load test is {0} and its name is '{1}'." -f $run.runNumber, $run.name) + Write-Output ("To view run details navigate to {0}" -f $webResultsUrl) + Write-Output "To view detailed results navigate to Load Test | Load Test Manager in Visual Studio IDE, and open this run." + + $resultsMDFolder = New-Item -ItemType Directory -Force -Path "$env:Temp\LoadTestResultSummary" + $resultFilePattern = ("QuickPerfTestResults_{0}_{1}_*.md" -f $env:AGENT_ID, $env:SYSTEM_DEFINITIONID) + $excludeFilePattern = ("QuickPerfTestResults_{0}_{1}_{2}_*.md" -f $env:AGENT_ID, $env:SYSTEM_DEFINITIONID, $env:BUILD_BUILDID) - Write-Output ("Run-id for this load test is {0} and its name is '{1}'." -f $run.runNumber, $run.name) - Write-Output ("To view run details navigate to {0}" -f $webResultsUrl) - Write-Output "To view detailed results navigate to Load Test | Load Test Manager in Visual Studio IDE, and open this run." - - $resultsMDFolder = New-Item -ItemType Directory -Force -Path "$env:Temp\LoadTestResultSummary" - $resultFilePattern = ("QuickPerfTestResults_{0}_{1}_*.md" -f $env:AGENT_ID, $env:SYSTEM_DEFINITIONID) - $excludeFilePattern = ("QuickPerfTestResults_{0}_{1}_{2}_*.md" -f $env:AGENT_ID, $env:SYSTEM_DEFINITIONID, $env:BUILD_BUILDID) - Remove-Item $resultsMDFolder\$resultFilePattern -Exclude $excludeFilePattern -Force - $summaryFile = ("{0}\QuickPerfTestResults_{1}_{2}_{3}_{4}.md" -f $resultsMDFolder, $env:AGENT_ID, $env:SYSTEM_DEFINITIONID, $env:BUILD_BUILDID, $run.id) - $summary = ('[Test Run: {0}]({1}) using {2}.
' -f $run.runNumber, $webResultsUrl ,$run.name) - - ('

{0}

' -f $summary) >> $summaryFile - UploadSummaryMdReport $summaryFile + if($avgResponseTimeThreshold) + { + $avgResponseTimeThresholdValidationResult = ValidateAvgResponseTimeThreshold $CltAccountUrl $headers $run.id $avgResponseTimeThreshold + if($avgResponseTimeThresholdValidationResult -eq $false) + { + Write-Output "The Avg.Response Time for the run is greater than the threshold value of $avgResponseTimeThreshold specified for the run " + Write-Output "To view detailed results navigate to Load Test | Load Test Manager in Visual Studio IDE, and open this run." + Write-Error "Load test task is marked as failed, as there were threshold violations for the Avg. Response Time" + } + } + + Remove-Item $resultsMDFolder\$resultFilePattern -Exclude $excludeFilePattern -Force + $summaryFile = ("{0}\QuickPerfTestResults_{1}_{2}_{3}_{4}.md" -f $resultsMDFolder, $env:AGENT_ID, $env:SYSTEM_DEFINITIONID, $env:BUILD_BUILDID, $run.id) + + if ($thresholdViolationsCount -gt 0) + { + $thresholdMessage=("{0} thresholds violated." -f $thresholdViolationsCount) + $thresholdImage="bowtie-status-error" + } + else + { + $thresholdMessage="No thresholds violated." + $thresholdImage="bowtie-status-success" + } + $summary = ('[Test Run: {0}]({1}) using {2}.
' -f $run.runNumber, $webResultsUrl ,$run.name) + $summary = (' {4}
[Test Run: {0}]({1}) using {2}.
' -f $run.runNumber, $webResultsUri , $run.name, $thresholdImage, $thresholdMessage) + + ('

{0}

' -f $summary) | Out-File $summaryFile -Encoding ascii -Append + UploadSummaryMdReport $summaryFile } else { - Write-Error ("Failed to connect to the endpoint '{0}' for VSO account '{1}'" -f $EndpointName, $VSOAccountUrl) + Write-Error ("Failed to connect to the endpoint '{0}' for VSO account '{1}'" -f $EndpointName, $VSOAccountUrl) } - + Write-Output "Quick Perf Test Script execution completed" diff --git a/Tasks/QuickPerfTest/VssConnectionHelper.ps1 b/Tasks/QuickPerfTest/VssConnectionHelper.ps1 index 1365d4e155c8..06cb56d398a4 100644 --- a/Tasks/QuickPerfTest/VssConnectionHelper.ps1 +++ b/Tasks/QuickPerfTest/VssConnectionHelper.ps1 @@ -1,13 +1,12 @@ function Get-CltEndpoint($connectedServiceUrl, $headers) { - # Load all dependent files for execution - . $PSScriptRoot/CltTasksUtility.ps1 - $vsoUrl = $connectedServiceUrl - Write-Host "Fetching the Clt endpoint for $vsoUrl" - $spsLocation = Get-SpsLocation $vsoUrl $headers - $cltLocation = Get-CltLocation $spsLocation $headers - - return $cltLocation + # Load all dependent files for execution + . $PSScriptRoot/CltTasksUtility.ps1 + $vsoUrl = $connectedServiceUrl + Write-Host "Fetching the Clt endpoint for $vsoUrl" + $spsLocation = Get-SpsLocation $vsoUrl $headers + $cltLocation = Get-CltLocation $spsLocation $headers + return $cltLocation } @@ -15,27 +14,26 @@ function Get-SpsLocation($vsoUrl, $headers) { Write-Host "Fetching the SPS endpoint for $vsoUrl" $spsUniqueIdentifier = "951917AC-A960-4999-8464-E3F0AA25B381" - $spsLocation = Get-ServiceLocation $vsoUrl $headers $spsUniqueIdentifier - return $spsLocation + $spsLocation = Get-ServiceLocation $vsoUrl $headers $spsUniqueIdentifier + return $spsLocation } function Get-CltLocation($spsUrl, $headers) { Write-Host "Fetching the CLT endpoint for $vsoUrl" - $cltUniqueIdentifier = "6C404D78-EF65-4E65-8B6A-DF19D6361EAE" - return Get-ServiceLocation $spsUrl $headers $cltUniqueIdentifier + $cltUniqueIdentifier = "6C404D78-EF65-4E65-8B6A-DF19D6361EAE" + return Get-ServiceLocation $spsUrl $headers $cltUniqueIdentifier } function Get-ServiceLocation($baseUrl, $headers, $serviceUniqueIdentifier) { # Load all dependent files for execution - . $PSScriptRoot/CltTasksUtility.ps1 - $locationCallUri = [string]::Format("{0}/_apis/servicedefinitions/LocationService2/{1}", $baseUrl, $serviceUniqueIdentifier) - $locationCallJsonResponse = InvokeRestMethod -Uri $locationCallUri -contentType "application/json" -headers $headers -Method Get - if($locationCallJsonResponse) - { - return $locationCallJsonResponse.locationMappings.location|Select -First 1 - } - + . $PSScriptRoot/CltTasksUtility.ps1 + $locationCallUri = [string]::Format("{0}/_apis/servicedefinitions/LocationService2/{1}", $baseUrl, $serviceUniqueIdentifier) + $locationCallJsonResponse = InvokeRestMethod -Uri $locationCallUri -contentType "application/json" -headers $headers -Method Get + if($locationCallJsonResponse) + { + return $locationCallJsonResponse.locationMappings.location|Select -First 1 + } return $null } \ No newline at end of file diff --git a/Tasks/QuickPerfTest/task.json b/Tasks/QuickPerfTest/task.json index 540dc9bd6b24..30d316f7b92c 100644 --- a/Tasks/QuickPerfTest/task.json +++ b/Tasks/QuickPerfTest/task.json @@ -13,7 +13,7 @@ "version": { "Major": 1, "Minor": 0, - "Patch": 15 + "Patch": 17 }, "demands": [ "msbuild", @@ -109,6 +109,13 @@ "0": "Automatically provisioned agents", "2": "Self-provisioned agents" } + }, + { + "name": "avgResponseTimeThreshold", + "type": "string", + "label": "Fail test if Avg.Response Time(ms) exceeds", + "helpMarkDown": "Load test run duration in seconds.", + "defaultValue": "0" } ], "instanceNameFormat": "Quick Web Performance Test $(testName)", diff --git a/Tasks/QuickPerfTest/task.loc.json b/Tasks/QuickPerfTest/task.loc.json index d6ba337c7ca0..a661dff81bb4 100644 --- a/Tasks/QuickPerfTest/task.loc.json +++ b/Tasks/QuickPerfTest/task.loc.json @@ -26,7 +26,7 @@ "type": "connectedService:Generic", "label": "ms-resource:loc.input.label.connectedServiceName", "defaultValue": "", - "required": true, + "required": true, "helpMarkDown": "ms-resource:loc.input.help.connectedServiceName" }, { diff --git a/Tasks/RunJMeterLoadTest/CltTasksUtility.ps1 b/Tasks/RunJMeterLoadTest/CltTasksUtility.ps1 new file mode 100644 index 000000000000..7ae24f7420d4 --- /dev/null +++ b/Tasks/RunJMeterLoadTest/CltTasksUtility.ps1 @@ -0,0 +1,339 @@ +function InvokeRestMethod($headers, $contentType, $uri , $method= "Get", $body) +{ + $restTimeout = 60 + $ServicePoint = [System.Net.ServicePointManager]::FindServicePoint($uri) + $result = Invoke-RestMethod -ContentType "application/json" -UserAgent $global:userAgent -TimeoutSec $restTimeout -Uri $uri -Method $method -Headers $headers -Body $body + $ServicePoint.CloseConnectionGroup("") + return $result +} + +function ComposeTestDropJson($name, $duration, $homepage, $vu, $geoLocation) +{ + $tdjson = @" + { + "dropType": "InplaceDrop", + "loadTestDefinition":{ + "loadTestName":"$name", + "runDuration":$duration, + "urls":["$homepage"], + "browserMixs":[ + {"browserName":"Internet Explorer 11.0","browserPercentage":60.0}, + {"browserName":"Chrome 2","browserPercentage":40.0} + ], + "loadPatternName":"Constant", + "maxVusers":$vu, + "loadGenerationGeoLocations":[ + {"Location":"$geoLocation","Percentage":100} + ] + } + } +"@ + + return $tdjson +} + +function CreateTestDrop($headers, $CltAccountUrl) +{ + $uri = [String]::Format("{0}/_apis/clt/testdrops?{1}", $CltAccountUrl, $global:apiVersion) + $drop = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers -method Post -body "{ ""dropType"": ""TestServiceBlobDrop"" }" + return $drop +} + +function GetTestDrop($headers, $drop, $CltAccountUrl) +{ + $uri = [String]::Format("{0}/_apis/clt/testdrops/{1}?{2}", $CltAccountUrl, $drop.id, $global:apiVersion) + $testdrop = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers + + return $testdrop +} + +function UploadTestDrop($testdrop, $src) +{ + $dest = $testdrop.accessData.dropContainerUrl + $sas = $testdrop.accessData.sasKey + + $azcopy = Get-ToolPath -Name "AzCopy\AzCopy.exe" + Write-Verbose "Calling AzCopy = $azcopy" -Verbose + + $azlog = ("{0}\..\azlog" -f $src) + $args = ("/Source:`"{0}`" /Dest:{1} /DestSAS:{2} /S /Z:`"{3}`"" -f $src, $dest, $sas, $azlog) + Write-Verbose "AzCopy Args = $args" -Verbose + + Invoke-Tool -Path $azcopy -Arguments $args +} + + +function GetTestRun($headers, $runId, $CltAccountUrl) +{ + $uri = [String]::Format("{0}/_apis/clt/testruns/{1}?{2}", $CltAccountUrl, $runId, $global:apiVersion) + $run = Get $headers $uri + return $run +} + +function GetTestRunUri($testRunId, $headers, $CltAccountUrl) +{ + $uri = [String]::Format("{0}/_apis/clt/testruns/{1}?{2}", $CltAccountUrl, $testRunId, $global:apiVersion) + $run = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers + + return $run.WebResultUrl +} + +function RunInProgress($run) +{ + return $run.state -eq "queued" -or $run.state -eq "inProgress" +} + +function MonitorTestRun($headers, $run, $CltAccountUrl, $monitorThresholds) +{ + $runId = $run.id + if ($runId) + { + $abortRun = $false + do + { + Start-Sleep -s 15 + $run = GetTestRun $headers $runId $CltAccountUrl + $abortRun = CheckTestErrors $headers $run $CltAccountUrl $monitorThresholds + if ($abortRun) + { + StopTestRun $headers $run $CltAccountUrl + } + } + while (RunInProgress $run) + } + return $abortRun +} + +function QueueTestRun($headers, $runJson, $CltAccountUrl) +{ + $uri = [String]::Format("{0}/_apis/clt/testruns?{1}", $CltAccountUrl, $global:apiVersion) + $run = InvokeRestMethod -contentType "application/json" -uri $uri -method Post -headers $headers -body $runJson + + $start = @" + { + "state": "queued" + } +"@ + + $uri = [String]::Format("{0}/_apis/clt/testruns/{1}?{2}", $CltAccountUrl, $run.id, $global:apiVersion) + InvokeRestMethod -contentType "application/json" -uri $uri -method Patch -headers $headers -body $start + $run = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers + + return $run +} + +function ComposeAccountUrl($connectedServiceUrl, $headers) +{ + #Load all dependent files for execution + . $PSScriptRoot/VssConnectionHelper.ps1 + $connectedServiceUrl = $connectedServiceUrl.TrimEnd('/') + Write-Host "Getting Clt Endpoint:" + $elsUrl = Get-CltEndpoint $connectedServiceUrl $headers + + return $elsUrl +} + +function UploadSummaryMdReport($summaryMdPath) +{ + Write-Verbose "Summary Markdown Path = $summaryMdPath" + + if (($env:SYSTEM_HOSTTYPE -eq "build") -and (Test-Path($summaryMdPath))) + { + Write-Host "##vso[task.addattachment type=Distributedtask.Core.Summary;name=Load test results;]$summaryMdPath" + } +} + +function isNumericValue ($str) { + $numericValue = 0 + $isNum = [System.Int32]::TryParse($str, [ref]$numericValue) + return $isNum +} + +function ValidateFiles($inputName, $fileName) +{ + $file = Get-ChildItem -Path $TestDrop -recurse | where {$_.Name -eq $fileName} | Select -First 1 + if ($file) + { + # Check for fileName + $global:ScopedTestDrop = $file.Directory.FullName + Write-Host -NoNewline ("Selected {0} is '{1}' under '{2}'" -f $inputName, $file.FullName, $global:ScopedTestDrop) + } + else + { + ErrorMessage "No $inputName is present in the test drop." + } +} + +function ValidateInputs($tfsCollectionUrl, $connectedServiceName, $testDrop, $loadtest) +{ + if (-Not (Test-Path $testDrop)) + { + ErrorMessage "The path for the load test files does not exist. Please provide a valid path." + } + + ValidateFiles "load test file" $loadTest +} + +function Get($headers, $uri) +{ + try + { + $result = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers + return $result + } + catch + { + Write-Host -NoNewline $_.Exception.Message + } +} + +function WriteTaskMessages($message) +{ + Write-Host ("{0}" -f $message ) -NoNewline +} + +function MonitorAcquireResource($headers, $run, $CltAccountUrl) +{ + $runId = $run.id + if ($runId) + { + $elapsed = [System.Diagnostics.Stopwatch]::StartNew() + do + { + Start-Sleep -s 5 + $run = GetTestRun $headers $runId $CltAccountUrl + } + while ($run.state -eq "queued") + if ($run.state -eq "inProgress") + { + WriteTaskMessages ("Acquiring test resources took {0}. Starting test execution." -f $($elapsed.Elapsed.ToString())) + } + } +} + +function ErrorMessage($message) +{ + Write-Error $message + exit $LastExitCode +} + +function StopTestRun($headers, $run, $CltAccountUrl) +{ + $stop = @" + { + "state": "aborted" + } +"@ + $uri = [String]::Format("{0}/_apis/clt/testruns/{1}?{2}", $CltAccountUrl, $run.id, $global:apiVersion) + InvokeRestMethod -contentType "application/json" -uri $uri -method Patch -headers $headers -body $stop + $run = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers + return $run + +} + +function ComposeTestRunJson($name, $tdid, $agentCount, $runDuration, $machineType) +{ + $processPlatform = "x86" + $setupScript="" + $cleanupScript="" + + $trjson = @" + { + "name":"$name", + "runType":"jMeterLoadTest", + "description":"Apache Jmeter test queued from build", + "testSettings":{"cleanupCommand":"$cleanupScript", "hostProcessPlatform":"$processPlatform", "setupCommand":"$setupScript"}, + "runSpecificDetails":{"coreCount":"$agentCount", "duration":"$runDuration", "samplingInterval":15}, + "superSedeRunSettings":{"loadGeneratorMachinesType":"$machineType"}, + "testDrop":{"id":"$tdid"}, + "runSourceIdentifier":"build/$env:SYSTEM_DEFINITIONID/$env:BUILD_BUILDID" + } +"@ + return $trjson +} + +function ShowMessages($headers, $run, $CltAccountUrl) +{ + $uri = [String]::Format("{0}/_apis/clt/testruns/{1}/messages?{2}", $CltAccountUrl, $run.id, $global:apiVersion) + $messages = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers + if ($messages) + { + $sMessages = $messages.value | Sort-Object loggedDate + foreach ($message in $sMessages) + { + switch ($message.messageType) + { + "info" { Write-Host -NoNewline ("[Message]{0}" -f $message.message) } + "output" { Write-Host -NoNewline ("[Message]{0}" -f $message.message) } + "warning" { Write-Warning $message.message } + "error" { Write-Error $message.message } + "critical" { Write-Error $message.message } + } + } + } +} + +function GetTestErrors($headers, $run, $CltAccountUrl) +{ + $uri = [String]::Format("{0}/_apis/clt/testruns/{1}/errors?detailed=true&{2}", $CltAccountUrl, $run.id, $global:apiVersion) + $testerrors = Get $headers $uri + return $testerrors +} + +function PrintErrorSummary($headers, $run, $CltAccountUrl, $monitorThresholds) +{ + $thresholdViolationsCount = 0 + $errors = GetTestErrors $headers $run $CltAccountUrl + if ($errors -and $errors.count -gt 0 -and $errors.types.count -gt 0) + { + foreach ($type in $errors.types) + { + foreach ($subType in $type.subTypes) + { + foreach ($errorDetail in $subType.errorDetailList) + { + if ($type.typeName -eq "ThresholdMessage") + { + Write-Warning ( "[{0}] {1} occurrences of {2} " -f $type.typeName, $errorDetail.occurrences, $errorDetail.messageText) + $thresholdViolationsCount += $errorDetail.occurrences + } + else + { + Write-Warning ( "[{0}] {1} occurrences of ['{2}','{3}','{4}'] : {5} " -f $type.typeName, $errorDetail.occurrences, $errorDetail.scenarioName, $errorDetail.testCaseName, + $subType.subTypeName, $errorDetail.messageText) + } + } + if ($type.typeName -eq "ThresholdMessage" -and $subType.subTypeName -eq "Critical" -and $monitorThresholds -and $subType.occurrences -gt $ThresholdLimit) + { + Write-Error ( "Your loadtest has crossed the permissible {0} threshold violations with {1} violations" -f $ThresholdLimit, $subType.occurrences ) + } + } + } + } + return $thresholdViolationsCount +} + + +function CheckTestErrors($headers, $run, $CltAccountUrl, $MonitorThresholds) +{ + $thresholdExceeded = $false + if ($MonitorThresholds) + { + $uri = [String]::Format("{0}/_apis/clt/testruns/{1}/errors?type=ThresholdMessage&detailed=True&{2}", $CltAccountUrl, $run.id, $global:apiVersion) + $errors = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers + + if ($errors -and $errors.count -gt 0 -and $errors.types.count -gt 0) + { + foreach ($subType in $errors.types.subTypes) + { + if ($subType.subTypeName -eq 'Critical' -and $subType.occurrences -gt $ThresholdLimit) + { + $thresholdExceeded = $true + return $true; + } + } + } + } + return $false; +} + diff --git a/Tasks/RunJMeterLoadTest/Start-ApacheJMeterTest.ps1 b/Tasks/RunJMeterLoadTest/Start-ApacheJMeterTest.ps1 index a3eea0fcf97d..8c7d7e873597 100644 --- a/Tasks/RunJMeterLoadTest/Start-ApacheJMeterTest.ps1 +++ b/Tasks/RunJMeterLoadTest/Start-ApacheJMeterTest.ps1 @@ -1,294 +1,82 @@ [CmdletBinding(DefaultParameterSetName = 'None')] param ( - [String] - $env:SYSTEM_DEFINITIONID, - [String] - $env:BUILD_BUILDID, - - [String] [Parameter(Mandatory = $true)] - $connectedServiceName, - - [String] [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] - $TestDrop, - [String] [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] - $LoadTest, - - [String] [Parameter(Mandatory = $true)] - $agentCount, - [String] [Parameter(Mandatory = $true)] - $runDuration, - [String] [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] - $machineType +[String] +$env:SYSTEM_DEFINITIONID, +[String] +$env:BUILD_BUILDID, + +[String] [Parameter(Mandatory = $false)] +$connectedServiceName, + +[String] [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] +$TestDrop, +[String] [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] +$LoadTest, + +[String] [Parameter(Mandatory = $true)] +$agentCount, +[String] [Parameter(Mandatory = $true)] +$runDuration, +[String] [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] +$machineType ) $userAgent = "ApacheJmeterTestBuildTask" -$apiVersion = "api-version=1.0" - $global:RestTimeout = 60 -$global:ElsAccountUrl = "http://www.visualstudio.com" -$global:TFSAccountUrl = "http://www.visualstudio.com" -$global:ScopedTestDrop = $TestDrop +$global:apiVersion = "api-version=1.0" function InitializeRestHeaders() { - $restHeaders = New-Object -TypeName "System.Collections.Generic.Dictionary[[String], [String]]" - - $alternateCreds = [String]::Concat($Username, ":", $Password) - $basicAuth = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($alternateCreds)) - $restHeaders.Add("Authorization", [String]::Concat("Basic ", $basicAuth)) - - return $restHeaders -} - -function InvokeRestMethod($headers, $contentType, $uri , $method= "Get", $body) -{ - $ServicePoint = [System.Net.ServicePointManager]::FindServicePoint($uri) - $result = Invoke-RestMethod -ContentType "application/json" -UserAgent $userAgent -TimeoutSec $global:RestTimeout -Uri $uri -Method $method -Headers $headers -Body $body - $ServicePoint.CloseConnectionGroup("") - return $result -} - -function CreateTestDrop($headers) -{ - $uri = [String]::Format("{0}/_apis/clt/testdrops?{1}", $global:ElsAccountUrl, $apiVersion) - $drop = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers -method Post -body "{ ""dropType"": ""TestServiceBlobDrop"" }" - return $drop -} - -function Get($headers, $uri) -{ - try - { - $result = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers - return $result - } - catch - { - Write-Host -NoNewline $_.Exception.Message - } -} - -function GetTestDrop($drop, $headers) -{ - $uri = [String]::Format("{0}/_apis/clt/testdrops/{1}?{2}", $global:ElsAccountUrl, $drop.id, $apiVersion) - $testdrop = Get $headers $uri - return $testdrop -} - -function GetTestRun($headers, $runId) -{ - $uri = [String]::Format("{0}/_apis/clt/testruns/{1}?{2}", $global:ElsAccountUrl, $runId, $apiVersion) - $run = Get $headers $uri - return $run -} - -function GetTestErrors($headers, $run) -{ - $uri = [String]::Format("{0}/_apis/clt/testruns/{1}/errors?detailed=true&{2}", $global:ElsAccountUrl, $run.id, $apiVersion) - $testerrors = Get $headers $uri - return $testerrors -} - -function QueueTestRun($headers, $runJson) -{ - $uri = [String]::Format("{0}/_apis/clt/testruns?{1}", $global:ElsAccountUrl, $apiVersion) - $run = InvokeRestMethod -contentType "application/json" -uri $uri -method Post -headers $headers -body $runJson - -$start = @" - { - "state": "queued" - } -"@ - - $uri = [String]::Format("{0}/_apis/clt/testruns/{1}?{2}", $global:ElsAccountUrl, $run.id, $apiVersion) - InvokeRestMethod -contentType "application/json" -uri $uri -method Patch -headers $headers -body $start - $run = InvokeRestMethod -contentType "application/json" -userAgent $userAgent -uri $uri -headers $headers - - return $run -} - -function RunInProgress($run) -{ - return $run.state -ne "completed" -and $run.state -ne "error" -and $run.state -ne "aborted" -} - -function PrintErrorSummary($headers, $run) -{ - $errors = GetTestErrors $headers $run - if ($errors -and $errors.count -gt 0 -and $errors.types.count -gt 0) - { - foreach ($type in $errors.types) - { - foreach ($subType in $type.subTypes) - { - foreach ($errorDetail in $subType.errorDetailList) - { - Write-Warning ( "[{0}] {1} occurrences of ['{2}','{3}','{4}'] : {5} " -f $type.typeName, $errorDetail.occurrences, $errorDetail.scenarioName, $errorDetail.testCaseName, - $subType.subTypeName, $errorDetail.messageText) - } - } - } - } + $restHeaders = New-Object -TypeName "System.Collections.Generic.Dictionary[[String], [String]]" + if([string]::IsNullOrWhiteSpace($connectedServiceName)) + { + $patToken = GetAccessToken $connectedServiceDetails + ValidatePatToken $patToken + $restHeaders.Add("Authorization", [String]::Concat("Bearer ", $patToken)) + + } + else + { + $Username = $connectedServiceDetails.Authorization.Parameters.Username + Write-Verbose "Username = $Username" -Verbose + $Password = $connectedServiceDetails.Authorization.Parameters.Password + $alternateCreds = [String]::Concat($Username, ":", $Password) + $basicAuth = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($alternateCreds)) + $restHeaders.Add("Authorization", [String]::Concat("Basic ", $basicAuth)) + } + return $restHeaders } -function ShowMessages($headers, $run) +function GetAccessToken($vssEndPoint) { - $uri = [String]::Format("{0}/_apis/clt/testruns/{1}/messages?{2}", $global:ElsAccountUrl, $run.id, $apiVersion) - $messages = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers - if ($messages) - { - $sMessages = $messages.value | Sort-Object loggedDate - foreach ($message in $sMessages) - { - switch ($message.messageType) - { - "info" { Write-Host -NoNewline ("[Message]{0}" -f $message.message) } - "output" { Write-Host -NoNewline ("[Message]{0}" -f $message.message) } - "warning" { Write-Warning $message.message } - "error" { Write-Error $message.message } - "critical" { Write-Error $message.message } - } - } - } + return $vssEndpoint.Authorization.Parameters.AccessToken } -function UploadTestDrop($testdrop, $src) +function ValidatePatToken($token) { - $dest = $testdrop.accessData.dropContainerUrl - $sas = $testdrop.accessData.sasKey - - $azcopy = Get-ToolPath -Name "AzCopy\AzCopy.exe" - Write-Verbose "Calling AzCopy = $azcopy" -Verbose - - $azlog = ("{0}\..\azlog" -f $src) - $args = ("/Source:`"{0}`" /Dest:{1} /DestSAS:{2} /S /Z:`"{3}`"" -f $src, $dest, $sas, $azlog) - Write-Verbose "AzCopy Args = $args" -Verbose - - Invoke-Tool -Path $azcopy -Arguments $args -} - -function ComposeTestRunJson($name, $tdid) -{ - $processPlatform = "x86" - $setupScript="" - $cleanupScript="" - -$trjson = @" - { - "name":"$name", - "runType":"jMeterLoadTest", - "description":"Apache Jmeter test queued from build", - "testSettings":{"cleanupCommand":"$cleanupScript", "hostProcessPlatform":"$processPlatform", "setupCommand":"$setupScript"}, - "runSpecificDetails":{"coreCount":"$agentCount", "duration":"$runDuration", "samplingInterval":15}, - "superSedeRunSettings":{"loadGeneratorMachinesType":"$MachineType"}, - "testDrop":{"id":"$tdid"}, - "runSourceIdentifier":"build/$env:SYSTEM_DEFINITIONID/$env:BUILD_BUILDID" - } -"@ - return $trjson + if([string]::IsNullOrWhiteSpace($token)) + { + throw "Unable to generate Personal Access Token for the user. Contact Project Collection Administrator" + } } function WriteTaskMessages($message) { - Write-Host ("{0}" -f $message ) -NoNewline -} - -function MonitorTestRun($headers, $run) -{ - $runId = $run.id - if ($runId) - { - do - { - Start-Sleep -s 15 - $run = GetTestRun $headers $runId - } - while (RunInProgress $run) - } -} - -function MonitorAcquireResource($headers, $run) -{ - $runId = $run.id - if ($runId) - { - $elapsed = [System.Diagnostics.Stopwatch]::StartNew() - do - { - Start-Sleep -s 5 - $run = GetTestRun $headers $runId - } - while ($run.state -eq "queued") - if ($run.state -eq "inProgress") - { - WriteTaskMessages ("Acquiring test resources took {0}. Starting test execution." -f $($elapsed.Elapsed.ToString())) - } - } -} - -function ComposeAccountUrl($vsoUrl) -{ - $elsUrl = $vsoUrl - - if ($vsoUrl -notlike "*VSCLT.VISUALSTUDIO.COM*") - { - if ($vsoUrl -like "*VISUALSTUDIO.COM*") - { - $accountName = $vsoUrl.Split('//')[2].Split('.')[0] - $elsUrl = ("https://{0}.vsclt.visualstudio.com" -f $accountName) - } - } - - return $elsUrl -} - -function ErrorMessage($message) -{ - Write-Error $message - exit $LastExitCode -} - -function ValidateFiles($inputName, $fileName) -{ - $file = Get-ChildItem -Path $TestDrop -recurse | where {$_.Name -eq $fileName} | Select -First 1 - if ($file) - { - # Check for fileName - $global:ScopedTestDrop = $file.Directory.FullName - Write-Host -NoNewline ("Selected {0} is '{1}' under '{2}'" -f $inputName, $file.FullName, $global:ScopedTestDrop) - } - else - { - ErrorMessage "No $inputName is present in the test drop." - } -} - -function Validate() -{ - if (-Not (Test-Path $TestDrop)) - { - ErrorMessage "The path for the load test files does not exist. Please provide a valid path." - } - - ValidateFiles "load test file" $LoadTest -} - -function UploadSummaryMdReport($summaryMdPath) -{ - Write-Verbose "Summary Markdown Path = $summaryMdPath" - - if (($env:SYSTEM_HOSTTYPE -eq "build") -and (Test-Path($summaryMdPath))) - { - Write-Host "##vso[task.addattachment type=Distributedtask.Core.Summary;name=Load test results;]$summaryMdPath" - } + Write-Host ("{0}" -f $message ) -NoNewline } ############################################## PS Script execution starts here ########################################## WriteTaskMessages "Starting Load Test Script" +# Load all dependent files for execution +. $PSScriptRoot/CltTasksUtility.ps1 +. $PSScriptRoot/VssConnectionHelper.ps1 + import-module "Microsoft.TeamFoundation.DistributedTask.Task.Internal" import-module "Microsoft.TeamFoundation.DistributedTask.Task.Common" +import-module "Microsoft.TeamFoundation.DistributedTask.Task.DTA" +import-module "Microsoft.TeamFoundation.DistributedTask.Task.DevTestLabs" Write-Output "Test drop = $TestDrop" Write-Output "Load test = $LoadTest" @@ -296,76 +84,81 @@ Write-Output "Load generator machine type = $machineType" Write-Output "Run source identifier = build/$env:SYSTEM_DEFINITIONID/$env:BUILD_BUILDID" #Validate Input -Validate +ValidateInputs $env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI $connectedServiceName $testDrop $loadTest -$connectedServiceDetails = Get-ServiceEndpoint -Context $distributedTaskContext -Name $connectedServiceName - -$Username = $connectedServiceDetails.Authorization.Parameters.Username -Write-Verbose "Username = $userName" -Verbose -$Password = $connectedServiceDetails.Authorization.Parameters.Password -$global:ElsAccountUrl = ComposeAccountUrl($connectedServiceDetails.Url.AbsoluteUri).TrimEnd('/') -$global:TFSAccountUrl = $env:System_TeamFoundationCollectionUri.TrimEnd('/') - -Write-Verbose "VSO account Url = $global:TFSAccountUrl" -Verbose -Write-Verbose "CLT account Url = $global:ElsAccountUrl" -Verbose +#Initialize Connected Service Details +if([string]::IsNullOrWhiteSpace($connectedServiceName)) +{ + $connectedServiceDetails = Get-ServiceEndpoint -Context $distributedTaskContext -Name SystemVssConnection +} +else +{ + $connectedServiceDetails = Get-ServiceEndpoint -Context $distributedTaskContext -Name $connectedServiceName +} -#Setting Headers and account Url accordingly +$VSOAccountUrl = $connectedServiceDetails.Url.AbsoluteUri +Write-Output "VSO Account URL is : $VSOAccountUrl" $headers = InitializeRestHeaders +$CltAccountUrl = ComposeAccountUrl $VSOAccountUrl $headers +$TFSAccountUrl = $env:System_TeamFoundationCollectionUri.TrimEnd('/') + +Write-Output "TFS account Url = $TFSAccountUrl" -Verbose +Write-Output "CLT account Url = $CltAccountUrl" -Verbose #Upload the test drop $elapsed = [System.Diagnostics.Stopwatch]::StartNew() -$drop = CreateTestDrop $headers +$drop = CreateTestDrop $headers $CltAccountUrl if ($drop.dropType -eq "TestServiceBlobDrop") { - $drop = GetTestDrop $drop $headers - UploadTestDrop $drop $global:ScopedTestDrop - WriteTaskMessages ("Uploading test files took {0}. Queuing the test run." -f $($elapsed.Elapsed.ToString())) + $drop = GetTestDrop $headers $drop $CltAccountUrl + UploadTestDrop $drop $global:ScopedTestDrop + WriteTaskMessages ("Uploading test files took {0}. Queuing the test run." -f $($elapsed.Elapsed.ToString())) - #Queue the test run - $runJson = ComposeTestRunJson $LoadTest $drop.id - $run = QueueTestRun $headers $runJson - MonitorAcquireResource $headers $run + #Queue the test run + $runJson = ComposeTestRunJson $LoadTest $drop.id $agentCount $runDuration $machineType + $run = QueueTestRun $headers $runJson $CltAccountUrl + MonitorAcquireResource $headers $run $CltAccountUrl - #Monitor the test run - $elapsed = [System.Diagnostics.Stopwatch]::StartNew() - MonitorTestRun $headers $run - WriteTaskMessages ( "Run execution took {0}. Collecting results." -f $($elapsed.Elapsed.ToString())) + #Monitor the test run + $elapsed = [System.Diagnostics.Stopwatch]::StartNew() + MonitorTestRun $headers $run $CltAccountUrl + WriteTaskMessages ( "Run execution took {0}. Collecting results." -f $($elapsed.Elapsed.ToString())) - #Print the error and messages - $run = GetTestRun $headers $run.id - ShowMessages $headers $run - PrintErrorSummary $headers $run + #Print the error and messages + $run = GetTestRun $headers $run.id $CltAccountUrl + ShowMessages $headers $run $CltAccountUrl + PrintErrorSummary $headers $run $CltAccountUrl - if ($run.state -ne "completed") - { - Write-Error "Load test has failed. Please check error messages to fix the problem." - } - else - { - WriteTaskMessages "The load test completed successfully." - } + if ($run.state -ne "completed") + { + Write-Error "Load test has failed. Please check error messages to fix the problem." + } + else + { + WriteTaskMessages "The load test completed successfully." + } - $run = GetTestRun $headers $run.id + $run = GetTestRun $headers $run.id $CltAccountUrl $webResultsUrl = $run.WebResultUrl - Write-Output ("Run-id for this load test is {0} and its name is '{1}'." -f $run.runNumber, $run.name) - Write-Output ("To view run details navigate to {0}" -f $webResultsUrl) + Write-Output ("Run-id for this load test is {0} and its name is '{1}'." -f $run.runNumber, $run.name) + Write-Output ("To view run details navigate to {0}" -f $webResultsUrl) - $resultsMDFolder = New-Item -ItemType Directory -Force -Path "$env:Temp\LoadTestResultSummary" - $resultFilePattern = ("ApacheJMeterTestResults_{0}_{1}_*.md" -f $env:AGENT_ID, $env:SYSTEM_DEFINITIONID) - $excludeFilePattern = ("ApacheJMeterTestResults_{0}_{1}_{2}_*.md" -f $env:AGENT_ID, $env:SYSTEM_DEFINITIONID, $env:BUILD_BUILDID) - Remove-Item $resultsMDFolder\$resultFilePattern -Exclude $excludeFilePattern -Force - $summaryFile = ("{0}\ApacheJMeterTestResults_{1}_{2}_{3}_{4}.md" -f $resultsMDFolder, $env:AGENT_ID, $env:SYSTEM_DEFINITIONID, $env:BUILD_BUILDID, $run.id) + $resultsMDFolder = New-Item -ItemType Directory -Force -Path "$env:Temp\LoadTestResultSummary" + $resultFilePattern = ("ApacheJMeterTestResults_{0}_{1}_*.md" -f $env:AGENT_ID, $env:SYSTEM_DEFINITIONID) + $excludeFilePattern = ("ApacheJMeterTestResults_{0}_{1}_{2}_*.md" -f $env:AGENT_ID, $env:SYSTEM_DEFINITIONID, $env:BUILD_BUILDID) + Remove-Item $resultsMDFolder\$resultFilePattern -Exclude $excludeFilePattern -Force + $summaryFile = ("{0}\ApacheJMeterTestResults_{1}_{2}_{3}_{4}.md" -f $resultsMDFolder, $env:AGENT_ID, $env:SYSTEM_DEFINITIONID, $env:BUILD_BUILDID, $run.id) - $summary = ('[Test Run: {0}]({1}) using {2}.
' -f $run.runNumber, $webResultsUrl , $run.name) - + $summary = ('[Test Run: {0}]({1}) using {2}.
' -f $run.runNumber, $webResultsUrl , $run.name) + ('

{0}

' -f $summary) | Out-File $summaryFile -Encoding ascii -Append - UploadSummaryMdReport $summaryFile + UploadSummaryMdReport $summaryFile } else { - Write-Error ("Connection '{0}' failed for service '{1}'" -f $connectedServiceName, $connectedServiceDetails.Url.AbsoluteUri) - ("Connection '{0}' failed for service '{1}'" -f $connectedServiceName, $connectedServiceDetails.Url.AbsoluteUri) >> $summaryFile + Write-Error ("Connection '{0}' failed for service '{1}'" -f $connectedServiceName, $connectedServiceDetails.Url.AbsoluteUri) + ("Connection '{0}' failed for service '{1}'" -f $connectedServiceName, $connectedServiceDetails.Url.AbsoluteUri) >> $summaryFile } WriteTaskMessages "JMeter Test Script execution completed" diff --git a/Tasks/RunJMeterLoadTest/VssConnectionHelper.ps1 b/Tasks/RunJMeterLoadTest/VssConnectionHelper.ps1 new file mode 100644 index 000000000000..06cb56d398a4 --- /dev/null +++ b/Tasks/RunJMeterLoadTest/VssConnectionHelper.ps1 @@ -0,0 +1,39 @@ +function Get-CltEndpoint($connectedServiceUrl, $headers) +{ + # Load all dependent files for execution + . $PSScriptRoot/CltTasksUtility.ps1 + $vsoUrl = $connectedServiceUrl + Write-Host "Fetching the Clt endpoint for $vsoUrl" + $spsLocation = Get-SpsLocation $vsoUrl $headers + $cltLocation = Get-CltLocation $spsLocation $headers + return $cltLocation + +} + +function Get-SpsLocation($vsoUrl, $headers) +{ + Write-Host "Fetching the SPS endpoint for $vsoUrl" + $spsUniqueIdentifier = "951917AC-A960-4999-8464-E3F0AA25B381" + $spsLocation = Get-ServiceLocation $vsoUrl $headers $spsUniqueIdentifier + return $spsLocation +} + +function Get-CltLocation($spsUrl, $headers) +{ + Write-Host "Fetching the CLT endpoint for $vsoUrl" + $cltUniqueIdentifier = "6C404D78-EF65-4E65-8B6A-DF19D6361EAE" + return Get-ServiceLocation $spsUrl $headers $cltUniqueIdentifier +} + +function Get-ServiceLocation($baseUrl, $headers, $serviceUniqueIdentifier) +{ + # Load all dependent files for execution + . $PSScriptRoot/CltTasksUtility.ps1 + $locationCallUri = [string]::Format("{0}/_apis/servicedefinitions/LocationService2/{1}", $baseUrl, $serviceUniqueIdentifier) + $locationCallJsonResponse = InvokeRestMethod -Uri $locationCallUri -contentType "application/json" -headers $headers -Method Get + if($locationCallJsonResponse) + { + return $locationCallJsonResponse.locationMappings.location|Select -First 1 + } + return $null +} \ No newline at end of file diff --git a/Tasks/RunJMeterLoadTest/task.json b/Tasks/RunJMeterLoadTest/task.json index 18d491044d00..8b7ae6d40d3a 100644 --- a/Tasks/RunJMeterLoadTest/task.json +++ b/Tasks/RunJMeterLoadTest/task.json @@ -1,97 +1,96 @@ { - "id": "F20661EB-E0F7-4AFD-9A86-9FE9D1A93382", - "name": "ApacheJMeterLoadTest", - "friendlyName": "Cloud-based Apache JMeter Load Test", - "description": "Runs the Apache JMeter load test in cloud", - "helpMarkDown": "This task can be used to trigger an Apache JMeter load test in cloud using Visual Studio Team Services. [Learn more](https://go.microsoft.com/fwlink/?LinkId=784929).", - "category": "Test", - "visibility": [ - "Build", - "Release" - ], - "author": "Microsoft Corporation", - "version": { - "Major": 1, - "Minor": 0, - "Patch": 9 + "id": "F20661EB-E0F7-4AFD-9A86-9FE9D1A93382", + "name": "ApacheJMeterLoadTest", + "friendlyName": "Cloud-based Apache JMeter Load Test", + "description": "Runs the Apache JMeter load test in cloud", + "helpMarkDown": "This task can be used to trigger an Apache JMeter load test in cloud using Visual Studio Team Services. [Learn more](https://go.microsoft.com/fwlink/?LinkId=784929).", + "category": "Test", + "visibility": [ + "Build", + "Release" + ], + "author": "Microsoft Corporation", + "version": { + "Major": 1, + "Minor": 0, + "Patch": 10 + }, + "demands": [ + "azureps" + ], + "minimumAgentVersion": "1.83.0", + "inputs": [ + { + "name": "connectedServiceName", + "type": "connectedService:Generic", + "label": "VS Team Services Connection", + "defaultValue": "", + "helpMarkDown": "Select a previously registered service connection to talk to the cloud-based load test service. Choose 'Manage' to register a new connection." }, - "demands": [ - "azureps" - ], - "minimumAgentVersion": "1.83.0", - "inputs": [ - { - "name": "connectedServiceName", - "type": "connectedService:Generic", - "label": "VS Team Service Endpoint", - "defaultValue": "", - "required": true, - "helpMarkDown": "Select a service endpoint to connect to the Cloud-based Load Test service. Choose 'Manage' to register a new endpoint." - }, - { - "name": "TestDrop", - "type": "filePath", - "label": "Apache JMeter test files folder", - "defaultValue": "", - "required": true, - "helpMarkDown": "Relative path from repo root where the load test files are available." - }, - { - "name": "LoadTest", - "type": "string", - "label": "Apache JMeter file", - "defaultValue": "jmeter.jmx", - "required": true, - "helpMarkDown": "The Apache JMeter test filename to be used under the load test folder specified above." - }, - { - "name": "agentCount", - "type": "pickList", - "label": "Agent Count", - "required": true, - "helpMarkDown": "Number of test agents (dual-core) used in the run.", - "defaultValue": "1", - "options": { - "1": "1", - "2": "2", - "3": "3", - "4": "4", - "5": "5" - } - }, - { - "name": "runDuration", - "type": "pickList", - "label": "Run Duration (sec)", - "required": true, - "helpMarkDown": "Load test run duration in seconds.", - "defaultValue": "60", - "options": { - "60": "60", - "120": "120", - "180": "180", - "240": "240", - "300": "300" - } - }, - { - "name": "machineType", - "type": "radio", - "label": "Run load test using", - "required": true, - "defaultValue": "0", - "options": { - "0": "Automatically provisioned agents", - "2": "Self-provisioned agents" - } - } - ], - "instanceNameFormat": "Apache JMeter Test $(LoadTest)", - "execution": { - "PowerShell": { - "target": "$(currentDirectory)\\Start-ApacheJMeterTest.ps1", - "argumentFormat": "", - "workingDirectory": "$(currentDirectory)" - } + { + "name": "TestDrop", + "type": "filePath", + "label": "Apache JMeter test files folder", + "defaultValue": "", + "required": true, + "helpMarkDown": "Relative path from repo root where the load test files are available." + }, + { + "name": "LoadTest", + "type": "string", + "label": "Apache JMeter file", + "defaultValue": "jmeter.jmx", + "required": true, + "helpMarkDown": "The Apache JMeter test filename to be used under the load test folder specified above." + }, + { + "name": "agentCount", + "type": "pickList", + "label": "Agent Count", + "required": true, + "helpMarkDown": "Number of test agents (dual-core) used in the run.", + "defaultValue": "1", + "options": { + "1":"1", + "2":"2", + "3":"3", + "4":"4", + "5":"5" + } + }, + { + "name": "runDuration", + "type": "pickList", + "label": "Run Duration (sec)", + "required": true, + "helpMarkDown": "Load test run duration in seconds.", + "defaultValue": "60", + "options": { + "60":"60", + "120":"120", + "180":"180", + "240":"240", + "300":"300" + } + }, + { + "name": "machineType", + "type": "radio", + "label": "Run load test using", + "required": true, + "defaultValue": "0", + "options": { + "0": "Automatically provisioned agents", + "2": "Self-provisioned agents" + } + } + ], + "instanceNameFormat": "Apache JMeter Test $(LoadTest)", + "execution": { + "PowerShell": { + "target": "$(currentDirectory)\\Start-ApacheJMeterTest.ps1", + "argumentFormat": "", + "workingDirectory": "$(currentDirectory)" } -} \ No newline at end of file + } +} diff --git a/Tasks/RunLoadTest/CltTasksUtility.ps1 b/Tasks/RunLoadTest/CltTasksUtility.ps1 new file mode 100644 index 000000000000..2854e63987f3 --- /dev/null +++ b/Tasks/RunLoadTest/CltTasksUtility.ps1 @@ -0,0 +1,356 @@ +function InvokeRestMethod($headers, $contentType, $uri , $method= "Get", $body) +{ + $restTimeout = 60 + $ServicePoint = [System.Net.ServicePointManager]::FindServicePoint($uri) + $result = Invoke-RestMethod -ContentType "application/json" -UserAgent $global:userAgent -TimeoutSec $restTimeout -Uri $uri -Method $method -Headers $headers -Body $body + $ServicePoint.CloseConnectionGroup("") + return $result +} + +function ComposeTestDropJson($name, $duration, $homepage, $vu, $geoLocation) +{ + $tdjson = @" + { + "dropType": "InplaceDrop", + "loadTestDefinition":{ + "loadTestName":"$name", + "runDuration":$duration, + "urls":["$homepage"], + "browserMixs":[ + {"browserName":"Internet Explorer 11.0","browserPercentage":60.0}, + {"browserName":"Chrome 2","browserPercentage":40.0} + ], + "loadPatternName":"Constant", + "maxVusers":$vu, + "loadGenerationGeoLocations":[ + {"Location":"$geoLocation","Percentage":100} + ] + } + } +"@ + + return $tdjson +} + +function CreateTestDrop($headers, $CltAccountUrl) +{ + $uri = [String]::Format("{0}/_apis/clt/testdrops?{1}", $CltAccountUrl, $global:apiVersion) + $drop = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers -method Post -body "{ ""dropType"": ""TestServiceBlobDrop"" }" + return $drop +} + +function GetTestDrop($headers, $drop, $CltAccountUrl) +{ + $uri = [String]::Format("{0}/_apis/clt/testdrops/{1}?api-version=1.0", $CltAccountUrl, $drop.id) + $testdrop = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers + + return $testdrop +} + +function UploadTestDrop($testdrop, $src) +{ + $dest = $testdrop.accessData.dropContainerUrl + $sas = $testdrop.accessData.sasKey + + $azcopy = Get-ToolPath -Name "AzCopy\AzCopy.exe" + Write-Verbose "Calling AzCopy = $azcopy" -Verbose + + $azlog = ("{0}\..\azlog" -f $src) + $args = ("/Source:`"{0}`" /Dest:{1} /DestSAS:{2} /S /Z:`"{3}`"" -f $src, $dest, $sas, $azlog) + Write-Verbose "AzCopy Args = $args" -Verbose + + Invoke-Tool -Path $azcopy -Arguments $args +} + + +function GetTestRun($headers, $runId, $CltAccountUrl) +{ + $uri = [String]::Format("{0}/_apis/clt/testruns/{1}?{2}", $CltAccountUrl, $runId, $global:apiVersion) + $run = Get $headers $uri + return $run +} + +function GetTestRunUri($testRunId, $headers, $CltAccountUrl) +{ + $uri = [String]::Format("{0}/_apis/clt/testruns/{1}?api-version=1.0", $CltAccountUrl,$testRunId) + $run = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers + + return $run.WebResultUrl +} + +function RunInProgress($run) +{ + return $run.state -eq "queued" -or $run.state -eq "inProgress" +} + +function MonitorTestRun($headers, $run, $CltAccountUrl, $monitorThresholds) +{ + $runId = $run.id + if ($runId) + { + $abortRun = $false + do + { + Start-Sleep -s 15 + $run = GetTestRun $headers $runId $CltAccountUrl + $abortRun = CheckTestErrors $headers $run $CltAccountUrl $monitorThresholds + if ($abortRun) + { + StopTestRun $headers $run $CltAccountUrl + } + } + while (RunInProgress $run) + } + return $abortRun +} + +function QueueTestRun($headers, $runJson, $CltAccountUrl) +{ + $uri = [String]::Format("{0}/_apis/clt/testruns?api-version=1.0", $CltAccountUrl) + $run = InvokeRestMethod -contentType "application/json" -uri $uri -method Post -headers $headers -body $runJson + + $start = @" + { + "state": "queued" + } +"@ + + $uri = [String]::Format("{0}/_apis/clt/testruns/{1}?api-version=1.0", $CltAccountUrl, $run.id) + InvokeRestMethod -contentType "application/json" -uri $uri -method Patch -headers $headers -body $start + $run = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers + + return $run +} + +function ComposeAccountUrl($connectedServiceUrl, $headers) +{ + #Load all dependent files for execution + . $PSScriptRoot/VssConnectionHelper.ps1 + $connectedServiceUrl = $connectedServiceUrl.TrimEnd('/') + Write-Host "Getting Clt Endpoint:" + $elsUrl = Get-CltEndpoint $connectedServiceUrl $headers + + return $elsUrl +} + +function UploadSummaryMdReport($summaryMdPath) +{ + Write-Verbose "Summary Markdown Path = $summaryMdPath" + + if (($env:SYSTEM_HOSTTYPE -eq "build") -and (Test-Path($summaryMdPath))) + { + Write-Host "##vso[task.addattachment type=Distributedtask.Core.Summary;name=Load test results;]$summaryMdPath" + } +} + +function isNumericValue ($str) { + $numericValue = 0 + $isNum = [System.Int32]::TryParse($str, [ref]$numericValue) + return $isNum +} + +function ValidateFiles($inputName, $fileName) +{ + $file = Get-ChildItem -Path $TestDrop -recurse | where {$_.Name -eq $fileName} | Select -First 1 + if ($file) + { + # Check for fileName + $global:ScopedTestDrop = $file.Directory.FullName + Write-Host -NoNewline ("Selected {0} is '{1}' under '{2}'" -f $inputName, $file.FullName, $global:ScopedTestDrop) + } + else + { + ErrorMessage "No $inputName is present in the test drop." + } +} + +function ValidateInputs($tfsCollectionUrl, $connectedServiceName, $testSettings, $testDrop, $loadtest) +{ + if (-Not (Test-Path $testSettings)) + { + ErrorMessage "The path for the test settings file does not exist. Please provide a valid path." + } + + if (-Not (Test-Path $testDrop)) + { + ErrorMessage "The path for the load test files does not exist. Please provide a valid path." + } + + ValidateFiles "load test file" $loadTest +} + +function Get($headers, $uri) +{ + try + { + $result = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers + return $result + } + catch + { + Write-Host -NoNewline $_.Exception.Message + } +} + +function WriteTaskMessages($message) +{ + Write-Host ("{0}" -f $message ) -NoNewline +} + +function MonitorAcquireResource($headers, $run, $CltAccountUrl) +{ + $runId = $run.id + if ($runId) + { + $elapsed = [System.Diagnostics.Stopwatch]::StartNew() + do + { + Start-Sleep -s 5 + $run = GetTestRun $headers $runId $CltAccountUrl + } + while ($run.state -eq "queued") + if ($run.state -eq "inProgress") + { + WriteTaskMessages ("Acquiring test resources took {0}. Starting test execution." -f $($elapsed.Elapsed.ToString())) + } + } +} + +function ErrorMessage($message) +{ + Write-Error $message + exit $LastExitCode +} + +function StopTestRun($headers, $run, $CltAccountUrl) +{ + $stop = @" + { + "state": "aborted" + } +"@ + $uri = [String]::Format("{0}/_apis/clt/testruns/{1}?{2}", $CltAccountUrl, $run.id, $global:apiVersion) + InvokeRestMethod -contentType "application/json" -uri $uri -method Patch -headers $headers -body $stop + $run = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers + return $run + +} + +function ComposeTestRunJson($name, $tdid, $machineType) +{ + $processPlatform = "x86" + $setupScript="" + $cleanupScript="" + + [xml]$tsxml = Get-Content $TestSettings + if ($tsxml.TestSettings.Scripts.setupScript) + { + $setupScript = [System.IO.Path]::GetFileName($tsxml.TestSettings.Scripts.setupScript) + } + if ($tsxml.TestSettings.Scripts.cleanupScript) + { + $cleanupScript = [System.IO.Path]::GetFileName($tsxml.TestSettings.Scripts.cleanupScript) + } + if ($tsxml.TestSettings.Execution.hostProcessPlatform) + { + $processPlatform = $tsxml.TestSettings.Execution.hostProcessPlatform + } + + $trjson = @" + { + "name":"$name", + "description":"Load Test queued from build", + "testSettings":{"cleanupCommand":"$cleanupScript", "hostProcessPlatform":"$processPlatform", "setupCommand":"$setupScript"}, + "superSedeRunSettings":{"loadGeneratorMachinesType":"$machineType"}, + "testDrop":{"id":"$tdid"}, + "runSourceIdentifier":"build/$env:SYSTEM_DEFINITIONID/$env:BUILD_BUILDID" + } +"@ + return $trjson +} + +function ShowMessages($headers, $run, $CltAccountUrl) +{ + $uri = [String]::Format("{0}/_apis/clt/testruns/{1}/messages?{2}", $CltAccountUrl, $run.id, $global:apiVersion) + $messages = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers + if ($messages) + { + $sMessages = $messages.value | Sort-Object loggedDate + foreach ($message in $sMessages) + { + switch ($message.messageType) + { + "info" { Write-Host -NoNewline ("[Message]{0}" -f $message.message) } + "output" { Write-Host -NoNewline ("[Message]{0}" -f $message.message) } + "warning" { Write-Warning $message.message } + "error" { Write-Error $message.message } + "critical" { Write-Error $message.message } + } + } + } +} + +function GetTestErrors($headers, $run, $CltAccountUrl) +{ + $uri = [String]::Format("{0}/_apis/clt/testruns/{1}/errors?detailed=true&{2}", $CltAccountUrl, $run.id, $global:apiVersion) + $testerrors = Get $headers $uri + return $testerrors +} + +function PrintErrorSummary($headers, $run, $CltAccountUrl, $monitorThresholds) +{ + $thresholdViolationsCount = 0 + $errors = GetTestErrors $headers $run $CltAccountUrl + if ($errors -and $errors.count -gt 0 -and $errors.types.count -gt 0) + { + foreach ($type in $errors.types) + { + foreach ($subType in $type.subTypes) + { + foreach ($errorDetail in $subType.errorDetailList) + { + if ($type.typeName -eq "ThresholdMessage") + { + Write-Warning ( "[{0}] {1} occurrences of {2} " -f $type.typeName, $errorDetail.occurrences, $errorDetail.messageText) + $thresholdViolationsCount += $errorDetail.occurrences + } + else + { + Write-Warning ( "[{0}] {1} occurrences of ['{2}','{3}','{4}'] : {5} " -f $type.typeName, $errorDetail.occurrences, $errorDetail.scenarioName, $errorDetail.testCaseName, + $subType.subTypeName, $errorDetail.messageText) + } + } + if ($type.typeName -eq "ThresholdMessage" -and $subType.subTypeName -eq "Critical" -and $monitorThresholds -and $subType.occurrences -gt $ThresholdLimit) + { + Write-Error ( "Your loadtest has crossed the permissible {0} threshold violations with {1} violations" -f $ThresholdLimit, $subType.occurrences ) + } + } + } + } + return $thresholdViolationsCount +} + + +function CheckTestErrors($headers, $run, $CltAccountUrl, $MonitorThresholds) +{ + $thresholdExceeded = $false + if ($MonitorThresholds) + { + $uri = [String]::Format("{0}/_apis/clt/testruns/{1}/errors?type=ThresholdMessage&detailed=True&{2}", $CltAccountUrl, $run.id, $global:apiVersion) + $errors = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers + + if ($errors -and $errors.count -gt 0 -and $errors.types.count -gt 0) + { + foreach ($subType in $errors.types.subTypes) + { + if ($subType.subTypeName -eq 'Critical' -and $subType.occurrences -gt $ThresholdLimit) + { + $thresholdExceeded = $true + return $true; + } + } + } + } + return $false; +} + diff --git a/Tasks/RunLoadTest/Start-CloudLoadTest.ps1 b/Tasks/RunLoadTest/Start-CloudLoadTest.ps1 index fb78be9b90b2..90852640631f 100644 --- a/Tasks/RunLoadTest/Start-CloudLoadTest.ps1 +++ b/Tasks/RunLoadTest/Start-CloudLoadTest.ps1 @@ -1,480 +1,196 @@ [CmdletBinding(DefaultParameterSetName = 'None')] param ( - [String] - $env:SYSTEM_DEFINITIONID, - [String] - $env:BUILD_BUILDID, - - [String] [Parameter(Mandatory = $true)] - $connectedServiceName, - - [String] [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] - $TestSettings, - [String] [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] - $TestDrop, - [String] [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] - $LoadTest, - [String] - $ThresholdLimit, - [String] [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] - $MachineType +[String] +$env:SYSTEM_DEFINITIONID, +[String] +$env:BUILD_BUILDID, + +[String] [Parameter(Mandatory = $false)] +$connectedServiceName, + +[String] [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] +$TestSettings, +[String] [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] +$TestDrop, +[String] [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] +$LoadTest, +[String] +$ThresholdLimit, +[String] [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] +$MachineType ) -$userAgent = "CloudLoadTestBuildTask" -$apiVersion = "api-version=1.0" - -$global:ThresholdExceeded = $false -$global:RestTimeout = 60 -$global:MonitorThresholds = $false -$global:ElsAccountUrl = "http://www.visualstudio.com" -$global:TFSAccountUrl = "http://www.visualstudio.com" +$global:userAgent = "CloudLoadTestBuildTask" +$global:apiVersion = "api-version=1.0" $global:ScopedTestDrop = $TestDrop -$global:ThresholdsViolationCount = 0 +$ThresholdExceeded = $false +$MonitorThresholds = $false function InitializeRestHeaders() { - $restHeaders = New-Object -TypeName "System.Collections.Generic.Dictionary[[String], [String]]" - - $alternateCreds = [String]::Concat($Username, ":", $Password) - $basicAuth = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($alternateCreds)) - $restHeaders.Add("Authorization", [String]::Concat("Basic ", $basicAuth)) - - return $restHeaders -} - -function InvokeRestMethod($headers, $contentType, $uri , $method= "Get", $body) -{ - $ServicePoint = [System.Net.ServicePointManager]::FindServicePoint($uri) - $result = Invoke-RestMethod -ContentType "application/json" -UserAgent $userAgent -TimeoutSec $global:RestTimeout -Uri $uri -Method $method -Headers $headers -Body $body - $ServicePoint.CloseConnectionGroup("") - return $result -} - -function CreateTestDrop($headers) -{ - $uri = [String]::Format("{0}/_apis/clt/testdrops?{1}", $global:ElsAccountUrl, $apiVersion) - $drop = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers -method Post -body "{ ""dropType"": ""TestServiceBlobDrop"" }" - return $drop -} - -function Get($headers, $uri) -{ - try - { - $result = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers - return $result - } - catch - { - Write-Host -NoNewline $_.Exception.Message - } -} - -function GetTestDrop($drop, $headers) -{ - $uri = [String]::Format("{0}/_apis/clt/testdrops/{1}?{2}", $global:ElsAccountUrl, $drop.id, $apiVersion) - $testdrop = Get $headers $uri - return $testdrop -} - -function GetTestRun($headers, $runId) -{ - $uri = [String]::Format("{0}/_apis/clt/testruns/{1}?{2}", $global:ElsAccountUrl, $runId, $apiVersion) - $run = Get $headers $uri - return $run -} - -function GetTestErrors($headers, $run) -{ - $uri = [String]::Format("{0}/_apis/clt/testruns/{1}/errors?detailed=true&{2}", $global:ElsAccountUrl, $run.id, $apiVersion) - $testerrors = Get $headers $uri - return $testerrors -} - -function QueueTestRun($headers, $runJson) -{ - $uri = [String]::Format("{0}/_apis/clt/testruns?{1}", $global:ElsAccountUrl, $apiVersion) - $run = InvokeRestMethod -contentType "application/json" -uri $uri -method Post -headers $headers -body $runJson - -$start = @" - { - "state": "queued" - } -"@ - - $uri = [String]::Format("{0}/_apis/clt/testruns/{1}?{2}", $global:ElsAccountUrl, $run.id, $apiVersion) - InvokeRestMethod -contentType "application/json" -uri $uri -method Patch -headers $headers -body $start - $run = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers - - return $run -} - -function StopTestRun($headers, $run) -{ -$stop = @" - { - "state": "aborted" - } -"@ - $uri = [String]::Format("{0}/_apis/clt/testruns/{1}?{2}", $global:ElsAccountUrl, $run.id, $apiVersion) - InvokeRestMethod -contentType "application/json" -uri $uri -method Patch -headers $headers -body $stop - $run = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers - return $run - -} - -function RunInProgress($run) -{ - return $run.state -ne "completed" -and $run.state -ne "error" -and $run.state -ne "aborted" -} - -function PrintErrorSummary($headers, $run) -{ - $errors = GetTestErrors $headers $run - if ($errors -and $errors.count -gt 0 -and $errors.types.count -gt 0) - { - foreach ($type in $errors.types) - { - foreach ($subType in $type.subTypes) - { - foreach ($errorDetail in $subType.errorDetailList) - { - if ($type.typeName -eq "ThresholdMessage") - { - Write-Warning ( "[{0}] {1} occurrences of {2} " -f $type.typeName, $errorDetail.occurrences, $errorDetail.messageText) - $global:ThresholdsViolationCount += $errorDetail.occurrences - } - else - { - Write-Warning ( "[{0}] {1} occurrences of ['{2}','{3}','{4}'] : {5} " -f $type.typeName, $errorDetail.occurrences, $errorDetail.scenarioName, $errorDetail.testCaseName, - $subType.subTypeName, $errorDetail.messageText) - } - } - if ($type.typeName -eq "ThresholdMessage" -and $subType.subTypeName -eq "Critical" -and $global:MonitorThresholds -and $subType.occurrences -gt $ThresholdLimit) - { - Write-Error ( "Your loadtest has crossed the permissible {0} threshold violations with {1} violations" -f $ThresholdLimit, $subType.occurrences ) - } - } - } - } -} - -function CheckTestErrors($headers, $run) -{ - if ($global:MonitorThresholds) - { - $uri = [String]::Format("{0}/_apis/clt/testruns/{1}/errors?type=ThresholdMessage&detailed=True&{2}", $global:ElsAccountUrl, $run.id, $apiVersion) - $errors = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers - - if ($errors -and $errors.count -gt 0 -and $errors.types.count -gt 0) - { - foreach ($subType in $errors.types.subTypes) - { - if ($subType.subTypeName -eq 'Critical' -and $subType.occurrences -gt $ThresholdLimit) - { - $global:ThresholdExceeded = $true - return $true; - } - } - } - } - return $false; -} - -function ShowMessages($headers, $run) -{ - $uri = [String]::Format("{0}/_apis/clt/testruns/{1}/messages?{2}", $global:ElsAccountUrl, $run.id, $apiVersion) - $messages = InvokeRestMethod -contentType "application/json" -uri $uri -headers $headers - if ($messages) - { - $sMessages = $messages.value | Sort-Object loggedDate - foreach ($message in $sMessages) - { - switch ($message.messageType) - { - "info" { Write-Host -NoNewline ("[Message]{0}" -f $message.message) } - "output" { Write-Host -NoNewline ("[Message]{0}" -f $message.message) } - "warning" { Write-Warning $message.message } - "error" { Write-Error $message.message } - "critical" { Write-Error $message.message } - } - } - } -} - -function UploadTestDrop($testdrop, $src) -{ - $dest = $testdrop.accessData.dropContainerUrl - $sas = $testdrop.accessData.sasKey - - $azcopy = Get-ToolPath -Name "AzCopy\AzCopy.exe" - Write-Verbose "Calling AzCopy = $azcopy" -Verbose - - $azlog = ("{0}\..\azlog" -f $src) - $args = ("/Source:`"{0}`" /Dest:{1} /DestSAS:{2} /S /Z:`"{3}`"" -f $src, $dest, $sas, $azlog) - Write-Verbose "AzCopy Args = $args" -Verbose - - Invoke-Tool -Path $azcopy -Arguments $args -} - -function ComposeTestRunJson($name, $tdid) -{ - $processPlatform = "x86" - $setupScript="" - $cleanupScript="" - - [xml]$tsxml = Get-Content $TestSettings - if ($tsxml.TestSettings.Scripts.setupScript) - { - $setupScript = [System.IO.Path]::GetFileName($tsxml.TestSettings.Scripts.setupScript) - } - if ($tsxml.TestSettings.Scripts.cleanupScript) - { - $cleanupScript = [System.IO.Path]::GetFileName($tsxml.TestSettings.Scripts.cleanupScript) - } - if ($tsxml.TestSettings.Execution.hostProcessPlatform) - { - $processPlatform = $tsxml.TestSettings.Execution.hostProcessPlatform - } - -$trjson = @" - { - "name":"$name", - "description":"Load Test queued from build", - "testSettings":{"cleanupCommand":"$cleanupScript", "hostProcessPlatform":"$processPlatform", "setupCommand":"$setupScript"}, - "superSedeRunSettings":{"loadGeneratorMachinesType":"$MachineType"}, - "testDrop":{"id":"$tdid"}, - "runSourceIdentifier":"build/$env:SYSTEM_DEFINITIONID/$env:BUILD_BUILDID" - } -"@ - return $trjson -} - -function WriteTaskMessages($message) -{ - Write-Host ("{0}" -f $message ) -NoNewline -} - -function MonitorTestRun($headers, $run) -{ - $runId = $run.id - if ($runId) - { - $abortRun = $false - do - { - Start-Sleep -s 15 - $run = GetTestRun $headers $runId - $abortRun = CheckTestErrors $headers $run - if ($abortRun) - { - StopTestRun $headers $run - } - } - while (RunInProgress $run) - } -} - -function MonitorAcquireResource($headers, $run) -{ - $runId = $run.id - if ($runId) - { - $elapsed = [System.Diagnostics.Stopwatch]::StartNew() - do - { - Start-Sleep -s 5 - $run = GetTestRun $headers $runId - } - while ($run.state -eq "queued") - if ($run.state -eq "inProgress") - { - WriteTaskMessages ("Acquiring test resources took {0}. Starting test execution." -f $($elapsed.Elapsed.ToString())) - } - } -} - -function ComposeAccountUrl($vsoUrl) -{ - $elsUrl = $vsoUrl - - if ($vsoUrl -notlike "*VSCLT.VISUALSTUDIO.COM*") - { - if ($vsoUrl -like "*VISUALSTUDIO.COM*") - { - $accountName = $vsoUrl.Split('//')[2].Split('.')[0] - $elsUrl = ("https://{0}.vsclt.visualstudio.com" -f $accountName) - } - } - - return $elsUrl -} - -function ErrorMessage($message) -{ - Write-Error $message - exit $LastExitCode -} - -function ValidateFiles($inputName, $fileName) -{ - $file = Get-ChildItem -Path $TestDrop -recurse | where {$_.Name -eq $fileName} | Select -First 1 - if ($file) - { - # Check for fileName - $global:ScopedTestDrop = $file.Directory.FullName - Write-Host -NoNewline ("Selected {0} is '{1}' under '{2}'" -f $inputName, $file.FullName, $global:ScopedTestDrop) - } - else - { - ErrorMessage "No $inputName is present in the test drop." - } + $restHeaders = New-Object -TypeName "System.Collections.Generic.Dictionary[[String], [String]]" + if([string]::IsNullOrWhiteSpace($connectedServiceName)) + { + $patToken = Get-AccessToken $connectedServiceDetails + ValidatePatToken $patToken + $restHeaders.Add("Authorization", [String]::Concat("Bearer ", $patToken)) + + } + else + { + $Username = $connectedServiceDetails.Authorization.Parameters.Username + Write-Verbose "Username = $Username" -Verbose + $Password = $connectedServiceDetails.Authorization.Parameters.Password + $alternateCreds = [String]::Concat($Username, ":", $Password) + $basicAuth = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($alternateCreds)) + $restHeaders.Add("Authorization", [String]::Concat("Basic ", $basicAuth)) + } + return $restHeaders } -function Validate() +function Get-AccessToken($vssEndPoint) { - if (-Not (Test-Path $TestSettings)) - { - ErrorMessage "The path for the test settings file does not exist. Please provide a valid path." - } - - if (-Not (Test-Path $TestDrop)) - { - ErrorMessage "The path for the load test files does not exist. Please provide a valid path." - } - - ValidateFiles "load test file" $LoadTest + return $vssEndpoint.Authorization.Parameters.AccessToken } -function UploadSummaryMdReport($summaryMdPath) +function ValidatePatToken($token) { - Write-Verbose "Summary Markdown Path = $summaryMdPath" - - if (($env:SYSTEM_HOSTTYPE -eq "build") -and (Test-Path($summaryMdPath))) - { - Write-Host "##vso[task.addattachment type=Distributedtask.Core.Summary;name=Load test results;]$summaryMdPath" + if([string]::IsNullOrWhiteSpace($token)) + { + throw "Unable to generate Personal Access Token for the user. Contact Project Collection Administrator" } } +# Load all dependent files for execution +. $PSScriptRoot/CltTasksUtility.ps1 +. $PSScriptRoot/VssConnectionHelper.ps1 + ############################################## PS Script execution starts here ########################################## WriteTaskMessages "Starting Load Test Script" import-module "Microsoft.TeamFoundation.DistributedTask.Task.Internal" import-module "Microsoft.TeamFoundation.DistributedTask.Task.Common" +import-module "Microsoft.TeamFoundation.DistributedTask.Task.DTA" +import-module "Microsoft.TeamFoundation.DistributedTask.Task.DevTestLabs" -Write-Output "Test settings = $TestSettings" -Write-Output "Test drop = $TestDrop" -Write-Output "Load test = $LoadTest" +Write-Output "Test settings = $testSettings" +Write-Output "Test drop = $testDrop" +Write-Output "Load test = $loadTest" Write-Output "Load generator machine type = $machineType" Write-Output "Run source identifier = build/$env:SYSTEM_DEFINITIONID/$env:BUILD_BUILDID" #Validate Input -Validate +ValidateInputs $env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI $connectedServiceName $testSettings $testDrop $loadTest #Setting monitoring of Threshold rule appropriately if ($ThresholdLimit -and $ThresholdLimit -ge 0) { - $global:MonitorThresholds = $true - Write-Output "Threshold limit = $ThresholdLimit" + $MonitorThresholds = $true + Write-Output "Threshold limit = $ThresholdLimit" } -$connectedServiceDetails = Get-ServiceEndpoint -Context $distributedTaskContext -Name $connectedServiceName - -$Username = $connectedServiceDetails.Authorization.Parameters.Username -Write-Verbose "Username = $Username" -Verbose -$Password = $connectedServiceDetails.Authorization.Parameters.Password -$global:ElsAccountUrl = ComposeAccountUrl($connectedServiceDetails.Url.AbsoluteUri).TrimEnd('/') -$global:TFSAccountUrl = $env:System_TeamFoundationCollectionUri.TrimEnd('/') - -Write-Verbose "VSO account Url = $global:TFSAccountUrl" -Verbose -Write-Verbose "CLT account Url = $global:ElsAccountUrl" -Verbose +#Initialize Connected Service Details +if([string]::IsNullOrWhiteSpace($connectedServiceName)) +{ + $connectedServiceDetails = Get-ServiceEndpoint -Context $distributedTaskContext -Name SystemVssConnection +} +else +{ + $connectedServiceDetails = Get-ServiceEndpoint -Context $distributedTaskContext -Name $connectedServiceName +} -#Setting Headers and account Url accordingly +$VSOAccountUrl = $connectedServiceDetails.Url.AbsoluteUri +Write-Output "VSO Account URL is : $VSOAccountUrl" $headers = InitializeRestHeaders +$CltAccountUrl = ComposeAccountUrl $VSOAccountUrl $headers +$TFSAccountUrl = $env:System_TeamFoundationCollectionUri.TrimEnd('/') + +Write-Output "TFS account Url = $TFSAccountUrl" -Verbose +Write-Output "CLT account Url = $CltAccountUrl" -Verbose #Upload the test drop $elapsed = [System.Diagnostics.Stopwatch]::StartNew() -$drop = CreateTestDrop $headers +$drop = CreateTestDrop $headers $CltAccountUrl if ($drop.dropType -eq "TestServiceBlobDrop") { - $drop = GetTestDrop $drop $headers - UploadTestDrop $drop $global:ScopedTestDrop - WriteTaskMessages ("Uploading test files took {0}. Queuing the test run." -f $($elapsed.Elapsed.ToString())) + $drop = GetTestDrop $headers $drop $CltAccountUrl + Write-Output "Test Drop Source Location: $global:ScopedTestDrop" + UploadTestDrop $drop $global:ScopedTestDrop + WriteTaskMessages ("Uploading test files took {0}. Queuing the test run." -f $($elapsed.Elapsed.ToString())) - #Queue the test run - $runJson = ComposeTestRunJson $LoadTest $drop.id + #Queue the test run + $runJson = ComposeTestRunJson $LoadTest $drop.id $MachineType - $run = QueueTestRun $headers $runJson - MonitorAcquireResource $headers $run + $run = QueueTestRun $headers $runJson $CltAccountUrl + MonitorAcquireResource $headers $run $CltAccountUrl - #Monitor the test run - $elapsed = [System.Diagnostics.Stopwatch]::StartNew() - MonitorTestRun $headers $run - WriteTaskMessages ( "Run execution took {0}. Collecting results." -f $($elapsed.Elapsed.ToString())) + #Monitor the test run + $elapsed = [System.Diagnostics.Stopwatch]::StartNew() + $thresholdExceeded = MonitorTestRun $headers $run $CltAccountUrl $MonitorThresholds + WriteTaskMessages ( "Run execution took {0}. Collecting results." -f $($elapsed.Elapsed.ToString())) - #Print the error and messages - $run = GetTestRun $headers $run.id - ShowMessages $headers $run - PrintErrorSummary $headers $run + #Print the error and messages + $run = GetTestRun $headers $run.id $CltAccountUrl + ShowMessages $headers $run $CltAccountUrl + $thresholdsViolatedCount = PrintErrorSummary $headers $run $CltAccountUrl $MonitorThresholds - if ($run.state -ne "completed") - { - Write-Error "Load test has failed. Please check error messages to fix the problem." - } - elseif ($global:ThresholdExceeded -eq $true) - { - Write-Error "Load test task is marked as failed, as the number of threshold errors has exceeded permissible limit." - } - else - { - WriteTaskMessages "The load test completed successfully." - } + if ($run.state -ne "completed") + { + Write-Error "Load test has failed. Please check error messages to fix the problem." + } + elseif ($thresholdExceeded -eq $true) + { + Write-Error "Load test task is marked as failed, as the number of threshold errors has exceeded permissible limit." + } + else + { + WriteTaskMessages "The load test completed successfully." + } - $run = GetTestRun $headers $run.id + $run = GetTestRun $headers $run.id $CltAccountUrl $webResultsUri = $run.WebResultUrl - Write-Output ("Run-id for this load test is {0} and its name is '{1}'." -f $run.runNumber, $run.name) - Write-Output ("To view run details navigate to {0}" -f $webResultsUri) - Write-Output "To view detailed results navigate to Load Test | Load Test Manager in Visual Studio IDE, and open this run." - - $resultsMDFolder = New-Item -ItemType Directory -Force -Path "$env:Temp\LoadTestResultSummary" - $resultFilePattern = ("CloudLoadTestResults_{0}_{1}_*.md" -f $env:AGENT_ID, $env:SYSTEM_DEFINITIONID) - $excludeFilePattern = ("CloudLoadTestResults_{0}_{1}_{2}_*.md" -f $env:AGENT_ID, $env:SYSTEM_DEFINITIONID, $env:BUILD_BUILDID) - Remove-Item $resultsMDFolder\$resultFilePattern -Exclude $excludeFilePattern -Force - $summaryFile = ("{0}\CloudLoadTestResults_{1}_{2}_{3}_{4}.md" -f $resultsMDFolder, $env:AGENT_ID, $env:SYSTEM_DEFINITIONID, $env:BUILD_BUILDID, $run.id) + Write-Output ("Run-id for this load test is {0} and its name is '{1}'." -f $run.runNumber, $run.name) + Write-Output ("To view run details navigate to {0}" -f $webResultsUri) + Write-Output "To view detailed results navigate to Load Test | Load Test Manager in Visual Studio IDE, and open this run." + + $resultsMDFolder = New-Item -ItemType Directory -Force -Path "$env:Temp\LoadTestResultSummary" + $resultFilePattern = ("CloudLoadTestResults_{0}_{1}_*.md" -f $env:AGENT_ID, $env:SYSTEM_DEFINITIONID) + $excludeFilePattern = ("CloudLoadTestResults_{0}_{1}_{2}_*.md" -f $env:AGENT_ID, $env:SYSTEM_DEFINITIONID, $env:BUILD_BUILDID) + Remove-Item $resultsMDFolder\$resultFilePattern -Exclude $excludeFilePattern -Force + $summaryFile = ("{0}\CloudLoadTestResults_{1}_{2}_{3}_{4}.md" -f $resultsMDFolder, $env:AGENT_ID, $env:SYSTEM_DEFINITIONID, $env:BUILD_BUILDID, $run.id) - if ($global:ThresholdExceeded -eq $true) + if ($thresholdExceeded -eq $true) { - $thresholdMessage=("{0} thresholds violated." -f $global:ThresholdsViolationCount) - $thresholdImage="bowtie-status-error" + $thresholdMessage=("{0} thresholds violated." -f $thresholdsViolatedCount) + $thresholdImage="bowtie-status-error" } - elseif ($global:ThresholdsViolationCount -gt 1) + elseif ($thresholdsViolatedCount -gt 1) { - $thresholdMessage=("{0} thresholds violated." -f $global:ThresholdsViolationCount) - $thresholdImage="bowtie-status-warning" + $thresholdMessage=("{0} thresholds violated." -f $thresholdsViolatedCount) + $thresholdImage="bowtie-status-warning" } - elseif ($global:ThresholdsViolationCount -eq 1) + elseif ($thresholdsViolatedCount -eq 1) { - $thresholdMessage=("{0} threshold violated." -f $global:ThresholdsViolationCount) - $thresholdImage="bowtie-status-warning" + $thresholdMessage=("{0} threshold violated." -f $thresholdsViolatedCount) + $thresholdImage="bowtie-status-warning" } else - { - $thresholdMessage="No thresholds violated." - $thresholdImage="bowtie-status-success" + { + $thresholdMessage="No thresholds violated." + $thresholdImage="bowtie-status-success" } - $summary = (' {4}
[Test Run: {0}]({1}) using {2}.
' -f $run.runNumber, $webResultsUri , $run.name, $thresholdImage, $thresholdMessage) - + $summary = (' {4}
[Test Run: {0}]({1}) using {2}.
' -f $run.runNumber, $webResultsUri , $run.name, $thresholdImage, $thresholdMessage) ('

{0}

' -f $summary) | Out-File $summaryFile -Encoding ascii -Append - UploadSummaryMdReport $summaryFile + UploadSummaryMdReport $summaryFile } else { - Write-Error ("Connection '{0}' failed for service '{1}'" -f $connectedServiceName, $connectedServiceDetails.Url.AbsoluteUri) + Write-Error ("Connection '{0}' failed for service '{1}'" -f $connectedServiceName, $connectedServiceDetails.Url.AbsoluteUri) } WriteTaskMessages "Load Test Script execution completed" diff --git a/Tasks/RunLoadTest/VssConnectionHelper.ps1 b/Tasks/RunLoadTest/VssConnectionHelper.ps1 new file mode 100644 index 000000000000..06cb56d398a4 --- /dev/null +++ b/Tasks/RunLoadTest/VssConnectionHelper.ps1 @@ -0,0 +1,39 @@ +function Get-CltEndpoint($connectedServiceUrl, $headers) +{ + # Load all dependent files for execution + . $PSScriptRoot/CltTasksUtility.ps1 + $vsoUrl = $connectedServiceUrl + Write-Host "Fetching the Clt endpoint for $vsoUrl" + $spsLocation = Get-SpsLocation $vsoUrl $headers + $cltLocation = Get-CltLocation $spsLocation $headers + return $cltLocation + +} + +function Get-SpsLocation($vsoUrl, $headers) +{ + Write-Host "Fetching the SPS endpoint for $vsoUrl" + $spsUniqueIdentifier = "951917AC-A960-4999-8464-E3F0AA25B381" + $spsLocation = Get-ServiceLocation $vsoUrl $headers $spsUniqueIdentifier + return $spsLocation +} + +function Get-CltLocation($spsUrl, $headers) +{ + Write-Host "Fetching the CLT endpoint for $vsoUrl" + $cltUniqueIdentifier = "6C404D78-EF65-4E65-8B6A-DF19D6361EAE" + return Get-ServiceLocation $spsUrl $headers $cltUniqueIdentifier +} + +function Get-ServiceLocation($baseUrl, $headers, $serviceUniqueIdentifier) +{ + # Load all dependent files for execution + . $PSScriptRoot/CltTasksUtility.ps1 + $locationCallUri = [string]::Format("{0}/_apis/servicedefinitions/LocationService2/{1}", $baseUrl, $serviceUniqueIdentifier) + $locationCallJsonResponse = InvokeRestMethod -Uri $locationCallUri -contentType "application/json" -headers $headers -Method Get + if($locationCallJsonResponse) + { + return $locationCallJsonResponse.locationMappings.location|Select -First 1 + } + return $null +} \ No newline at end of file diff --git a/Tasks/RunLoadTest/task.json b/Tasks/RunLoadTest/task.json index b70b84969439..0b68f4340e9b 100644 --- a/Tasks/RunLoadTest/task.json +++ b/Tasks/RunLoadTest/task.json @@ -1,83 +1,82 @@ { - "id": "9E9DB38A-B40B-4C13-B7F0-31031C894C22", - "name": "CloudLoadTest", - "friendlyName": "Cloud-based Load Test", - "description": "Runs the load test in the cloud with Visual Studio Team Services", - "helpMarkDown": "This task triggers a cloud-based load test using Visual Studio Team Services. [Learn more](https://go.microsoft.com/fwlink/?linkid=546976).", - "category": "Test", - "visibility": [ - "Build", - "Release" - ], - "author": "Microsoft Corporation", - "version": { - "Major": 1, - "Minor": 0, - "Patch": 14 + "id": "9E9DB38A-B40B-4C13-B7F0-31031C894C22", + "name": "CloudLoadTest", + "friendlyName": "Cloud-based Load Test", + "description": "Runs the load test in the cloud with Visual Studio Team Services", + "helpMarkDown": "This task triggers a cloud-based load test using Visual Studio Team Services. [Learn more](https://go.microsoft.com/fwlink/?linkid=546976).", + "category": "Test", + "visibility": [ + "Build", + "Release" + ], + "author": "Microsoft Corporation", + "version": { + "Major": 1, + "Minor": 0, + "Patch": 16 + }, + "demands": [ + "msbuild", + "azureps" + ], + "minimumAgentVersion": "1.83.0", + "inputs": [ + { + "name": "connectedServiceName", + "type": "connectedService:Generic", + "label": "VS Team Services Connection", + "defaultValue": "", + "helpMarkDown": "Select a previously registered service connection to talk to the cloud-based load test service. Choose 'Manage' to register a new connection." }, - "demands": [ - "msbuild", - "azureps" - ], - "minimumAgentVersion": "1.83.0", - "inputs": [ - { - "name": "connectedServiceName", - "type": "connectedService:Generic", - "label": "Registered connection", - "defaultValue": "", - "required": true, - "helpMarkDown": "Select a previously registered service connection to talk to the Cloud-based Load Test service. Choose 'Manage' to register a new connection." - }, - { - "name": "TestSettings", - "type": "filePath", - "label": "Test settings file", - "defaultValue": "", - "required": true, - "helpMarkDown": "Relative path from repo root for the test settings file to use for the load test." - }, - { - "name": "TestDrop", - "type": "filePath", - "label": "Load test files folder", - "defaultValue": "", - "required": true, - "helpMarkDown": "Relative path from repo root where the load test solution build output will be available." - }, - { - "name": "LoadTest", - "type": "string", - "label": "Load test file", - "defaultValue": "", - "required": true, - "helpMarkDown": "The load test filename to be used under the load test folder specified above." - }, - { - "name": "ThresholdLimit", - "type": "string", - "label": "Number of permissible threshold violations", - "required": false, - "helpMarkDown": "Number of threshold violations above which the load test outcome is considered unsuccessful." - }, - { - "name": "MachineType", - "type": "radio", - "label": "Run load test using", - "required": true, - "defaultValue": "0", - "options": { - "0": "Automatically provisioned agents", - "2": "Self-provisioned agents" - } - } - ], - "instanceNameFormat": "Cloud Load Test $(LoadTest)", - "execution": { - "PowerShell": { - "target": "$(currentDirectory)\\Start-CloudLoadTest.ps1", - "argumentFormat": "", - "workingDirectory": "$(currentDirectory)" - } + { + "name": "TestSettings", + "type": "filePath", + "label": "Test settings file", + "defaultValue": "", + "required": true, + "helpMarkDown": "Relative path from repo root for the test settings file to use for the load test." + }, + { + "name": "TestDrop", + "type": "filePath", + "label": "Load test files folder", + "defaultValue": "", + "required": true, + "helpMarkDown": "Relative path from repo root where the load test solution build output will be available." + }, + { + "name": "LoadTest", + "type": "string", + "label": "Load test file", + "defaultValue": "", + "required": true, + "helpMarkDown": "The load test filename to be used under the load test folder specified above." + }, + { + "name": "ThresholdLimit", + "type": "string", + "label": "Number of permissible threshold violations", + "required": false, + "helpMarkDown": "Number of threshold violations above which the load test outcome is considered unsuccessful." + }, + { + "name": "MachineType", + "type": "radio", + "label": "Run load test using", + "required": true, + "defaultValue": "0", + "options": { + "0": "Automatically provisioned agents", + "2": "Self-provisioned agents" + } + } + ], + "instanceNameFormat": "Cloud Load Test $(LoadTest)", + "execution": { + "PowerShell": { + "target": "$(currentDirectory)\\Start-CloudLoadTest.ps1", + "argumentFormat": "", + "workingDirectory": "$(currentDirectory)" } -} \ No newline at end of file + } +} diff --git a/Tasks/SSH/task.json b/Tasks/SSH/task.json index 6d8f4e0f4698..2361c9bea6c8 100644 --- a/Tasks/SSH/task.json +++ b/Tasks/SSH/task.json @@ -8,12 +8,16 @@ "visibility": [ "Build", "Release" + ], + "runsOn": [ + "Agent", + "MachineGroup" ], "author": "Microsoft Corporation", "version": { "Major": 0, "Minor": 1, - "Patch": 2 + "Patch": 3 }, "demands": [], "instanceNameFormat": "Run shell $(runOptions) on remote machine", diff --git a/Tasks/SSH/task.loc.json b/Tasks/SSH/task.loc.json index 0ed0f1b20b7a..b07ef57bca08 100644 --- a/Tasks/SSH/task.loc.json +++ b/Tasks/SSH/task.loc.json @@ -9,11 +9,15 @@ "Build", "Release" ], + "runsOn": [ + "Agent", + "MachineGroup" + ], "author": "Microsoft Corporation", "version": { "Major": 0, "Minor": 1, - "Patch": 2 + "Patch": 3 }, "demands": [], "instanceNameFormat": "ms-resource:loc.instanceNameFormat", diff --git a/Tasks/ServiceFabricDeploy/ServiceFabricSDK/Publish-NewServiceFabricApplication.ps1 b/Tasks/ServiceFabricDeploy/ServiceFabricSDK/Publish-NewServiceFabricApplication.ps1 index 9fb68aa61126..6347472553f4 100644 --- a/Tasks/ServiceFabricDeploy/ServiceFabricSDK/Publish-NewServiceFabricApplication.ps1 +++ b/Tasks/ServiceFabricDeploy/ServiceFabricSDK/Publish-NewServiceFabricApplication.ps1 @@ -36,6 +36,12 @@ .PARAMETER SkipPackageValidation Switch signaling whether the package should be validated or not before deployment. + .PARAMETER CopyPackageTimeoutSec + Timeout in seconds for copying application package to image store. + + .PARAMETER RegisterPackageTimeoutSec + Timeout in seconds for registering application package. + .EXAMPLE Publish-NewServiceFabricApplication -ApplicationPackagePath 'pkg\Debug' -ApplicationParameterFilePath 'Local.xml' @@ -77,7 +83,15 @@ [Parameter(ParameterSetName="ApplicationParameterFilePath")] [Parameter(ParameterSetName="ApplicationName")] - [Switch]$SkipPackageValidation + [Switch]$SkipPackageValidation, + + [Parameter(ParameterSetName="ApplicationParameterFilePath")] + [Parameter(ParameterSetName="ApplicationName")] + [int]$CopyPackageTimeoutSec, + + [Parameter(ParameterSetName="ApplicationParameterFilePath")] + [Parameter(ParameterSetName="ApplicationName")] + [int]$RegisterPackageTimeoutSec ) @@ -118,7 +132,7 @@ if (!$packageValidationSuccess) { $errMsg = (Get-VstsLocString -Key SFSDK_PackageValidationFailed -ArgumentList $ApplicationPackagePath) - throw $errMsg + throw $errMsg } } @@ -180,7 +194,7 @@ if($removeApp) { - Write-Host (Get-VstsLocString -Key SFSDK_AppAlreadyExistsInfo -ArgumentList @($ApplicationName, $app.ApplicationTypeName, $app.ApplicationTypeVersion)) + Write-Host (Get-VstsLocString -Key SFSDK_AppAlreadyExistsInfo -ArgumentList @($ApplicationName, $app.ApplicationTypeName, $app.ApplicationTypeVersion)) try { @@ -225,14 +239,42 @@ $imageStoreConnectionString = Get-ImageStoreConnectionStringFromClusterManifest ([xml] $clusterManifestText) $applicationPackagePathInImageStore = $names.ApplicationTypeName - Copy-ServiceFabricApplicationPackage -ApplicationPackagePath $AppPkgPathToUse -ImageStoreConnectionString $imageStoreConnectionString -ApplicationPackagePathInImageStore $applicationPackagePathInImageStore + $copyParameters = @{ + 'ApplicationPackagePath' = $AppPkgPathToUse + 'ImageStoreConnectionString' = $imageStoreConnectionString + 'ApplicationPackagePathInImageStore' = $applicationPackagePathInImageStore + } + + if ($CopyPackageTimeoutSec) + { + $InstalledSdkVersion = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Service Fabric SDK" -Name FabricSDKVersion).FabricSDKVersion + if ([version]$InstalledSdkVersion -gt [version]"2.3") + { + $copyParameters['TimeOutSec'] = $CopyPackageTimeoutSec + } + else + { + Write-Warning (Get-VstsLocString -Key CopyPackageTimeoutSecWarning $InstalledSdkVersion) + } + } + + Copy-ServiceFabricApplicationPackage @copyParameters if(!$?) { throw (Get-VstsLocString -Key SFSDK_CopyingAppToImageStoreFailed) } + $registerParameters = @{ + 'ApplicationPathInImageStore' = $applicationPackagePathInImageStore + } + + if ($RegisterPackageTimeoutSec) + { + $registerParameters['TimeOutSec'] = $RegisterPackageTimeoutSec + } + Write-Host (Get-VstsLocString -Key SFSDK_RegisterAppType) - Register-ServiceFabricApplicationType -ApplicationPathInImageStore $applicationPackagePathInImageStore + Register-ServiceFabricApplicationType @registerParameters if(!$?) { throw (Get-VstsLocString -Key SFSDK_RegisterAppTypeFailed) diff --git a/Tasks/ServiceFabricDeploy/ServiceFabricSDK/Publish-UpgradedServiceFabricApplication.ps1 b/Tasks/ServiceFabricDeploy/ServiceFabricSDK/Publish-UpgradedServiceFabricApplication.ps1 index 9fcfb104ed0d..3974fc9cccfa 100644 --- a/Tasks/ServiceFabricDeploy/ServiceFabricSDK/Publish-UpgradedServiceFabricApplication.ps1 +++ b/Tasks/ServiceFabricDeploy/ServiceFabricSDK/Publish-UpgradedServiceFabricApplication.ps1 @@ -35,6 +35,12 @@ function Publish-UpgradedServiceFabricApplication .PARAMETER SkipPackageValidation Switch signaling whether the package should be validated or not before deployment. + .PARAMETER CopyPackageTimeoutSec + Timeout in seconds for copying application package to image store. + + .PARAMETER RegisterPackageTimeoutSec + Timeout in seconds for registering application package. + .EXAMPLE Publish-UpgradeServiceFabricApplication -ApplicationPackagePath 'pkg\Debug' -ApplicationParameterFilePath 'AppParameters.Local.xml' @@ -78,7 +84,15 @@ function Publish-UpgradedServiceFabricApplication [Parameter(ParameterSetName="ApplicationParameterFilePath")] [Parameter(ParameterSetName="ApplicationName")] - [Switch]$SkipPackageValidation + [Switch]$SkipPackageValidation, + + [Parameter(ParameterSetName="ApplicationParameterFilePath")] + [Parameter(ParameterSetName="ApplicationName")] + [int]$CopyPackageTimeoutSec, + + [Parameter(ParameterSetName="ApplicationParameterFilePath")] + [Parameter(ParameterSetName="ApplicationName")] + [int]$RegisterPackageTimeoutSec ) @@ -186,14 +200,43 @@ function Publish-UpgradedServiceFabricApplication $applicationPackagePathInImageStore = $names.ApplicationTypeName Write-Host (Get-VstsLocString -Key SFSDK_CopyingAppToImageStore) - Copy-ServiceFabricApplicationPackage -ApplicationPackagePath $AppPkgPathToUse -ImageStoreConnectionString $imageStoreConnectionString -ApplicationPackagePathInImageStore $applicationPackagePathInImageStore + + $copyParameters = @{ + 'ApplicationPackagePath' = $AppPkgPathToUse + 'ImageStoreConnectionString' = $imageStoreConnectionString + 'ApplicationPackagePathInImageStore' = $applicationPackagePathInImageStore + } + + if ($CopyPackageTimeoutSec) + { + $InstalledSdkVersion = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Service Fabric SDK" -Name FabricSDKVersion).FabricSDKVersion + if ([version]$InstalledSdkVersion -gt [version]"2.3") + { + $copyParameters['TimeOutSec'] = $CopyPackageTimeoutSec + } + else + { + Write-Warning (Get-VstsLocString -Key CopyPackageTimeoutSecWarning $InstalledSdkVersion) + } + } + + Copy-ServiceFabricApplicationPackage @copyParameters if(!$?) { throw (Get-VstsLocString -Key SFSDK_CopyingAppToImageStoreFailed) } - + + $registerParameters = @{ + 'ApplicationPathInImageStore' = $applicationPackagePathInImageStore + } + + if ($RegisterPackageTimeoutSec) + { + $registerParameters['TimeOutSec'] = $RegisterPackageTimeoutSec + } + Write-Host (Get-VstsLocString -Key SFSDK_RegisterAppType) - Register-ServiceFabricApplicationType -ApplicationPathInImageStore $applicationPackagePathInImageStore + Register-ServiceFabricApplicationType @registerParameters if(!$?) { throw Write-Host (Get-VstsLocString -Key SFSDK_RegisterAppTypeFailed) @@ -273,7 +316,7 @@ function Publish-UpgradedServiceFabricApplication } elseif($upgradeStatus.UpgradeState -eq "RollingBackCompleted") { - Write-Host (Get-VstsLocString -Key SFSDK_UpgradeRolledBack) + Write-Error (Get-VstsLocString -Key SFSDK_UpgradeRolledBack) } } } \ No newline at end of file diff --git a/Tasks/ServiceFabricDeploy/Strings/resources.resjson/en-US/resources.resjson b/Tasks/ServiceFabricDeploy/Strings/resources.resjson/en-US/resources.resjson index ea49fd237d57..8f765d1eaffc 100644 --- a/Tasks/ServiceFabricDeploy/Strings/resources.resjson/en-US/resources.resjson +++ b/Tasks/ServiceFabricDeploy/Strings/resources.resjson/en-US/resources.resjson @@ -12,6 +12,10 @@ "loc.input.help.publishProfilePath": "Path to the publish profile that defines the settings to use. [Variables](https://go.microsoft.com/fwlink/?LinkID=550988) and wildcards can be used in the path.", "loc.input.label.applicationParameterPath": "Application Parameters", "loc.input.help.applicationParameterPath": "Path to the application parameters file. [Variables](https://go.microsoft.com/fwlink/?LinkID=550988) and wildcards can be used in the path. If specified, this will override the value in the publish profile.", + "loc.input.label.copyPackageTimeoutSec": "CopyPackageTimeoutSec", + "loc.input.help.copyPackageTimeoutSec": "Timeout in seconds for copying application package to image store.", + "loc.input.label.registerPackageTimeoutSec": "RegisterPackageTimeoutSec", + "loc.input.help.registerPackageTimeoutSec": "Timeout in seconds for registering application package.", "loc.input.label.overridePublishProfileSettings": "Override All Publish Profile Upgrade Settings", "loc.input.help.overridePublishProfileSettings": "This will override all upgrade settings with either the value specified below or the default value if not specified.", "loc.input.label.isUpgrade": "Upgrade the Application", @@ -20,7 +24,6 @@ "loc.input.label.UpgradeReplicaSetCheckTimeoutSec": "UpgradeReplicaSetCheckTimeoutSec", "loc.input.label.ReplicaQuorumTimeoutSec": "ReplicaQuorumTimeoutSec", "loc.input.label.TimeoutSec": "TimeoutSec", - "loc.input.label.Force": "Force", "loc.input.label.ForceRestart": "ForceRestart", "loc.input.label.HealthCheckRetryTimeoutSec": "HealthCheckRetryTimeoutSec", "loc.input.label.HealthCheckWaitDurationSec": "HealthCheckWaitDurationSec", @@ -77,5 +80,6 @@ "loc.messages.SFSDK_UpgradeSuccess": "Upgrade completed successfully.", "loc.messages.SFSDK_UpgradeRolledBack": "Upgrade was rolled back.", "loc.messages.SFSDK_UnzipPackage": "Attempting to unzip '{0}' to location '{1}'.", - "loc.messages.SFSDK_UnexpectedError": "Unexpected Error. Error details: $_.Exception.Message" + "loc.messages.SFSDK_UnexpectedError": "Unexpected Error. Error details: $_.Exception.Message", + "loc.messages.CopyPackageTimeoutSecWarning": "The CopyPackageTimeoutSec parameter requires version '2.3' of the Service Fabric SDK, but the installed version is '{0}'. This parameter will be ignored." } \ No newline at end of file diff --git a/Tasks/ServiceFabricDeploy/deploy.ps1 b/Tasks/ServiceFabricDeploy/deploy.ps1 index c4fb0bb13e38..3aef502f2bc8 100644 --- a/Tasks/ServiceFabricDeploy/deploy.ps1 +++ b/Tasks/ServiceFabricDeploy/deploy.ps1 @@ -25,6 +25,9 @@ try { $serviceConnectionName = Get-VstsInput -Name serviceConnectionName -Require $connectedServiceEndpoint = Get-VstsEndpoint -Name $serviceConnectionName -Require + $copyPackageTimeoutSec = Get-VstsInput -Name copyPackageTimeoutSec + $registerPackageTimeoutSec = Get-VstsInput -Name registerPackageTimeoutSec + $clusterConnectionParameters = @{} $regKey = "HKLM:\SOFTWARE\Microsoft\Service Fabric SDK" @@ -129,15 +132,52 @@ try { $applicationName = Get-ApplicationNameFromApplicationParameterFile $applicationParameterFile $app = Get-ServiceFabricApplication -ApplicationName $applicationName - + # Do an upgrade if configured to do so and the app actually exists if ($isUpgrade -and $app) { - Publish-UpgradedServiceFabricApplication -ApplicationPackagePath $applicationPackagePath -ApplicationParameterFilePath $applicationParameterFile -Action RegisterAndUpgrade -UpgradeParameters $upgradeParameters -UnregisterUnusedVersions -ErrorAction Stop + $publishParameters = @{ + 'ApplicationPackagePath' = $applicationPackagePath + 'ApplicationParameterFilePath' = $applicationParameterFile + 'Action' = "RegisterAndUpgrade" + 'UpgradeParameters' = $upgradeParameters + 'UnregisterUnusedVersions' = $true + 'ErrorAction' = "Stop" + } + + if ($copyPackageTimeoutSec) + { + $publishParameters['CopyPackageTimeoutSec'] = $copyPackageTimeoutSec + } + + if ($registerPackageTimeoutSec) + { + $publishParameters['RegisterPackageTimeoutSec'] = $registerPackageTimeoutSec + } + + Publish-UpgradedServiceFabricApplication @publishParameters } else { - Publish-NewServiceFabricApplication -ApplicationPackagePath $ApplicationPackagePath -ApplicationParameterFilePath $applicationParameterFile -Action RegisterAndCreate -OverwriteBehavior SameAppTypeAndVersion -ErrorAction Stop + $publishParameters = @{ + 'ApplicationPackagePath' = $applicationPackagePath + 'ApplicationParameterFilePath' = $applicationParameterFile + 'Action' = "RegisterAndCreate" + 'OverwriteBehavior' = "SameAppTypeAndVersion" + 'ErrorAction' = "Stop" + } + + if ($copyPackageTimeoutSec) + { + $publishParameters['CopyPackageTimeoutSec'] = $copyPackageTimeoutSec + } + + if ($registerPackageTimeoutSec) + { + $publishParameters['RegisterPackageTimeoutSec'] = $registerPackageTimeoutSec + } + + Publish-NewServiceFabricApplication @publishParameters } } finally { Trace-VstsLeavingInvocation $MyInvocation diff --git a/Tasks/ServiceFabricDeploy/task.json b/Tasks/ServiceFabricDeploy/task.json index 47a02ed30ce7..8803717b7c0d 100644 --- a/Tasks/ServiceFabricDeploy/task.json +++ b/Tasks/ServiceFabricDeploy/task.json @@ -12,8 +12,8 @@ ], "version": { "Major": 1, - "Minor": 1, - "Patch": 2 + "Minor": 2, + "Patch": 0 }, "minimumAgentVersion": "1.95.0", "groups": [ @@ -57,6 +57,22 @@ "required": false, "helpMarkDown": "Path to the application parameters file. [Variables](https://go.microsoft.com/fwlink/?LinkID=550988) and wildcards can be used in the path. If specified, this will override the value in the publish profile." }, + { + "name": "copyPackageTimeoutSec", + "type": "string", + "label": "CopyPackageTimeoutSec", + "defaultValue": "", + "required": false, + "helpMarkDown": "Timeout in seconds for copying application package to image store." + }, + { + "name": "registerPackageTimeoutSec", + "type": "string", + "label": "RegisterPackageTimeoutSec", + "defaultValue": "", + "required": false, + "helpMarkDown": "Timeout in seconds for registering application package." + }, { "name": "overridePublishProfileSettings", "type": "boolean", @@ -129,15 +145,6 @@ "groupname": "upgrade", "visibleRule": "overridePublishProfileSettings = true && isUpgrade = true" }, - { - "name": "Force", - "type": "boolean", - "label": "Force", - "defaultValue": "true", - "required": true, - "groupname": "upgrade", - "visibleRule": "overridePublishProfileSettings = true && isUpgrade = true" - }, { "name": "ForceRestart", "type": "boolean", @@ -281,6 +288,7 @@ "SFSDK_UpgradeSuccess": "Upgrade completed successfully.", "SFSDK_UpgradeRolledBack": "Upgrade was rolled back.", "SFSDK_UnzipPackage": "Attempting to unzip '{0}' to location '{1}'.", - "SFSDK_UnexpectedError": "Unexpected Error. Error details: $_.Exception.Message" + "SFSDK_UnexpectedError": "Unexpected Error. Error details: $_.Exception.Message", + "CopyPackageTimeoutSecWarning": "The CopyPackageTimeoutSec parameter requires version '2.3' of the Service Fabric SDK, but the installed version is '{0}'. This parameter will be ignored." } } \ No newline at end of file diff --git a/Tasks/ServiceFabricDeploy/task.loc.json b/Tasks/ServiceFabricDeploy/task.loc.json index 385cc8354063..609081bcb3c2 100644 --- a/Tasks/ServiceFabricDeploy/task.loc.json +++ b/Tasks/ServiceFabricDeploy/task.loc.json @@ -12,8 +12,8 @@ ], "version": { "Major": 1, - "Minor": 1, - "Patch": 2 + "Minor": 2, + "Patch": 0 }, "minimumAgentVersion": "1.95.0", "groups": [ @@ -57,6 +57,22 @@ "required": false, "helpMarkDown": "ms-resource:loc.input.help.applicationParameterPath" }, + { + "name": "copyPackageTimeoutSec", + "type": "string", + "label": "ms-resource:loc.input.label.copyPackageTimeoutSec", + "defaultValue": "", + "required": false, + "helpMarkDown": "ms-resource:loc.input.help.copyPackageTimeoutSec" + }, + { + "name": "registerPackageTimeoutSec", + "type": "string", + "label": "ms-resource:loc.input.label.registerPackageTimeoutSec", + "defaultValue": "", + "required": false, + "helpMarkDown": "ms-resource:loc.input.help.registerPackageTimeoutSec" + }, { "name": "overridePublishProfileSettings", "type": "boolean", @@ -129,15 +145,6 @@ "groupname": "upgrade", "visibleRule": "overridePublishProfileSettings = true && isUpgrade = true" }, - { - "name": "Force", - "type": "boolean", - "label": "ms-resource:loc.input.label.Force", - "defaultValue": "true", - "required": true, - "groupname": "upgrade", - "visibleRule": "overridePublishProfileSettings = true && isUpgrade = true" - }, { "name": "ForceRestart", "type": "boolean", @@ -281,6 +288,7 @@ "SFSDK_UpgradeSuccess": "ms-resource:loc.messages.SFSDK_UpgradeSuccess", "SFSDK_UpgradeRolledBack": "ms-resource:loc.messages.SFSDK_UpgradeRolledBack", "SFSDK_UnzipPackage": "ms-resource:loc.messages.SFSDK_UnzipPackage", - "SFSDK_UnexpectedError": "ms-resource:loc.messages.SFSDK_UnexpectedError" + "SFSDK_UnexpectedError": "ms-resource:loc.messages.SFSDK_UnexpectedError", + "CopyPackageTimeoutSecWarning": "ms-resource:loc.messages.CopyPackageTimeoutSecWarning" } } \ No newline at end of file diff --git a/Tasks/ServiceFabricDeploy/utilities.ps1 b/Tasks/ServiceFabricDeploy/utilities.ps1 index 65829802e2e5..ebf4d2a3602f 100644 --- a/Tasks/ServiceFabricDeploy/utilities.ps1 +++ b/Tasks/ServiceFabricDeploy/utilities.ps1 @@ -231,8 +231,7 @@ function Get-VstsUpgradeParameters "UpgradeReplicaSetCheckTimeoutSec", "ReplicaQuorumTimeoutSec", "TimeoutSec", - "ForceRestart", - "Force" + "ForceRestart" ) $upgradeMode = Get-VstsInput -Name upgradeMode -Require @@ -275,5 +274,7 @@ function Get-VstsUpgradeParameters } } + $parameters["Force"] = $true + return $parameters } \ No newline at end of file diff --git a/Tasks/SonarQubePostTest/SonarQubePostTest.ps1 b/Tasks/SonarQubePostTest/SonarQubePostTest.ps1 index 7beb101eab5b..6564b4980324 100644 --- a/Tasks/SonarQubePostTest/SonarQubePostTest.ps1 +++ b/Tasks/SonarQubePostTest/SonarQubePostTest.ps1 @@ -2,6 +2,10 @@ Write-Verbose "Starting SonarQube PostBuild Step" import-module "Microsoft.TeamFoundation.DistributedTask.Task.Common" +Write-Warning " The ownership of the SonarQube related build tasks is being transferred to SonarSource." +Write-Warning " Please replace this build task with the one brought by SonarSource's extension on the marketplace: https://aka.ms/sqextension" +Write-Warning " For more details go to https://aka.ms/sqtransfer" + . $PSScriptRoot/Common/SonarQubeHelpers/SonarQubeHelper.ps1 # During PR builds only an "issues mode" analysis is allowed. The resulting issues are posted as code review comments. diff --git a/Tasks/SonarQubePostTest/Strings/resources.resjson/en-US/resources.resjson b/Tasks/SonarQubePostTest/Strings/resources.resjson/en-US/resources.resjson index a9ef53d6e823..3f7da261fb84 100644 --- a/Tasks/SonarQubePostTest/Strings/resources.resjson/en-US/resources.resjson +++ b/Tasks/SonarQubePostTest/Strings/resources.resjson/en-US/resources.resjson @@ -1,6 +1,6 @@ { "loc.friendlyName": "SonarQube for MSBuild - End Analysis", "loc.helpMarkDown": "[More Information](https://go.microsoft.com/fwlink/?LinkId=620063)", - "loc.description": "Finish the analysis and upload the results to SonarQube", - "loc.instanceNameFormat": "Finish the analysis and upload the results to SonarQube" + "loc.description": "[DEPRECATED] Finish the analysis and upload the results to SonarQube", + "loc.instanceNameFormat": "[DEPRECATED] Finish the analysis and upload the results to SonarQube" } \ No newline at end of file diff --git a/Tasks/SonarQubePostTest/task.json b/Tasks/SonarQubePostTest/task.json index b5bc4c90cb2d..cd4ed351ba11 100644 --- a/Tasks/SonarQubePostTest/task.json +++ b/Tasks/SonarQubePostTest/task.json @@ -2,9 +2,10 @@ "id": "730D8DE1-7A4F-424C-9542-FE7CC02604EB", "name": "SonarQubePostTest", "friendlyName": "SonarQube for MSBuild - End Analysis", - "description": "Finish the analysis and upload the results to SonarQube", + "description": "[DEPRECATED] Finish the analysis and upload the results to SonarQube", "helpMarkDown": "[More Information](https://go.microsoft.com/fwlink/?LinkId=620063)", "category": "Build", + "deprecated": true, "visibility": [ "Build" ], @@ -12,14 +13,14 @@ "version": { "Major": 1, "Minor": 0, - "Patch": 56 + "Patch": 57 }, "minimumAgentVersion": "1.99.0", "demands": [ "msbuild", "java" ], - "instanceNameFormat": "Finish the analysis and upload the results to SonarQube", + "instanceNameFormat": "[DEPRECATED] Finish the analysis and upload the results to SonarQube", "execution": { "PowerShell": { "target": "$(currentDirectory)\\SonarQubePostTest.ps1", diff --git a/Tasks/SonarQubePostTest/task.loc.json b/Tasks/SonarQubePostTest/task.loc.json index c51b0780f395..0688477d606e 100644 --- a/Tasks/SonarQubePostTest/task.loc.json +++ b/Tasks/SonarQubePostTest/task.loc.json @@ -5,6 +5,7 @@ "description": "ms-resource:loc.description", "helpMarkDown": "ms-resource:loc.helpMarkDown", "category": "Build", + "deprecated": true, "visibility": [ "Build" ], @@ -12,7 +13,7 @@ "version": { "Major": 1, "Minor": 0, - "Patch": 56 + "Patch": 57 }, "minimumAgentVersion": "1.99.0", "demands": [ diff --git a/Tasks/SonarQubePreBuild/SonarQubePreBuild.ps1 b/Tasks/SonarQubePreBuild/SonarQubePreBuild.ps1 index 3287f5d124b9..4466106cffea 100644 --- a/Tasks/SonarQubePreBuild/SonarQubePreBuild.ps1 +++ b/Tasks/SonarQubePreBuild/SonarQubePreBuild.ps1 @@ -27,6 +27,10 @@ Write-Verbose "includeFullReport = $includeFullReport" import-module "Microsoft.TeamFoundation.DistributedTask.Task.Common" import-module "Microsoft.TeamFoundation.DistributedTask.Task.Internal" +Write-Warning " The ownership of the SonarQube related build tasks is being transferred to SonarSource." +Write-Warning " Please replace this build task with the one brought by SonarSource's extension on the marketplace: https://aka.ms/sqextension" +Write-Warning " For more details go to https://aka.ms/sqtransfer" + . $PSScriptRoot/Common/SonarQubeHelpers/SonarQubeHelper.ps1 # During PR builds only an "issues mode" analysis is allowed. The resulting issues are posted as code review comments. @@ -35,10 +39,4 @@ ExitOnPRBuild . $PSScriptRoot/SonarQubePreBuildImpl.ps1 -InvokePreBuildTask - - - - - - +InvokePreBuildTask \ No newline at end of file diff --git a/Tasks/SonarQubePreBuild/Strings/resources.resjson/en-US/resources.resjson b/Tasks/SonarQubePreBuild/Strings/resources.resjson/en-US/resources.resjson index 5f6309959c6d..3c22c37a5b11 100644 --- a/Tasks/SonarQubePreBuild/Strings/resources.resjson/en-US/resources.resjson +++ b/Tasks/SonarQubePreBuild/Strings/resources.resjson/en-US/resources.resjson @@ -1,8 +1,8 @@ { "loc.friendlyName": "SonarQube for MSBuild - Begin Analysis", "loc.helpMarkDown": "[More Information](https://go.microsoft.com/fwlink/?LinkId=620063)", - "loc.description": "Fetch the Quality Profile from SonarQube to configure the analysis", - "loc.instanceNameFormat": "Fetch the Quality Profile from SonarQube", + "loc.description": "[DEPRECATED] Fetch the Quality Profile from SonarQube to configure the analysis", + "loc.instanceNameFormat": "[DEPRECATED] Fetch the Quality Profile from SonarQube", "loc.group.displayName.serverSettings": "SonarQube Server", "loc.group.displayName.project": "SonarQube Project Settings", "loc.group.displayName.dbSettings": "Database Settings (not required for SonarQube 5.2+)", diff --git a/Tasks/SonarQubePreBuild/task.json b/Tasks/SonarQubePreBuild/task.json index e2150bebb5eb..ed9098ffed86 100644 --- a/Tasks/SonarQubePreBuild/task.json +++ b/Tasks/SonarQubePreBuild/task.json @@ -2,9 +2,10 @@ "id": "EAE5B2CC-AC5E-4CBA-B022-A06621F9C01F", "name": "SonarQubePreBuild", "friendlyName": "SonarQube for MSBuild - Begin Analysis", - "description": "Fetch the Quality Profile from SonarQube to configure the analysis", + "description": "[DEPRECATED] Fetch the Quality Profile from SonarQube to configure the analysis", "helpMarkDown": "[More Information](https://go.microsoft.com/fwlink/?LinkId=620063)", "category": "Build", + "deprecated": true, "visibility": [ "Build" ], @@ -12,7 +13,7 @@ "version": { "Major": 1, "Minor": 0, - "Patch": 48 + "Patch": 49 }, "minimumAgentVersion": "1.99.0", "demands": [ @@ -135,7 +136,7 @@ "groupName": "advanced" } ], - "instanceNameFormat": "Fetch the Quality Profile from SonarQube", + "instanceNameFormat": "[DEPRECATED] Fetch the Quality Profile from SonarQube", "execution": { "PowerShell": { "target": "$(currentDirectory)\\SonarQubePreBuild.ps1", diff --git a/Tasks/SonarQubePreBuild/task.loc.json b/Tasks/SonarQubePreBuild/task.loc.json index 18b78760ec3d..aa4fece6f84c 100644 --- a/Tasks/SonarQubePreBuild/task.loc.json +++ b/Tasks/SonarQubePreBuild/task.loc.json @@ -5,6 +5,7 @@ "description": "ms-resource:loc.description", "helpMarkDown": "ms-resource:loc.helpMarkDown", "category": "Build", + "deprecated": true, "visibility": [ "Build" ], @@ -12,7 +13,7 @@ "version": { "Major": 1, "Minor": 0, - "Patch": 48 + "Patch": 49 }, "minimumAgentVersion": "1.99.0", "demands": [ diff --git a/Tasks/SqlAzureDacpacDeployment/Tests/L0.ts b/Tasks/SqlAzureDacpacDeployment/Tests/L0.ts new file mode 100644 index 000000000000..4a7a3a9c5045 --- /dev/null +++ b/Tasks/SqlAzureDacpacDeployment/Tests/L0.ts @@ -0,0 +1,87 @@ +/// +/// +/// + +import Q = require('q'); +import assert = require('assert'); +import path = require('path'); + +var psm = require('../../../Tests/lib/psRunner'); +var shell = require('shelljs'); +var ps = shell.which('powershell.exe'); +var psr = null; + +describe('SqlAzureDacpacDeployment Suite', function () { + this.timeout(20000); + + before((done) => { + if (ps) { + psr = new psm.PSRunner(); + psr.start(); + } + done(); + }); + + after(function () { + psr.kill(); + }); + + if(ps) { + it('(DACPAC) Should throw if Multiple Dacpac files or none present', (done) => { + psr.run(path.join(__dirname, 'L0DacpacTaskFileCheck.ps1'), done); + }); + + it('(SQL) Should throw if Multiple Sql files or none present', (done) => { + psr.run(path.join(__dirname, 'L0SqlTaskFileCheck.ps1'), done); + }); + it('(DACPAC) Should run successfully for all valid inputs', (done) => { + psr.run(path.join(__dirname, 'L0ValidDacpacInput.ps1'), done); + }); + it('(SQL) Should run successfully for all valid inputs', (done) => { + psr.run(path.join(__dirname, 'L0ValidSqlInput.ps1'), done); + }); + } +}); + +describe('SqlAzureDacpacDeployment - Utility Suite', function () { + this.timeout(10000); + + before((done) => { + if (ps) { + psr = new psm.PSRunner(); + psr.start(); + } + done(); + }); + + after(function () { + psr.kill(); + }); + + if(ps) { + it('Validate Username end point (Create-AzureSqlDatabaseServerFirewallRule)', (done) => { + psr.run(path.join(__dirname, 'L0UtilityUsernameCreate.ps1'), done); + }); + it('Validate SPN end point (Create-AzureSqlDatabaseServerFirewallRule) ', (done) => { + psr.run(path.join(__dirname, 'L0UtilitySPNCreate.ps1'), done); + }); + it('Validate Certificate end point (Create-AzureSqlDatabaseServerFirewallRule)', (done) => { + psr.run(path.join(__dirname, 'L0UtilityCertificateCreate.ps1'), done); + }); + it('Validate Username end point (Delete-AzureSqlDatabaseServerFirewallRule)', (done) => { + psr.run(path.join(__dirname, 'L0UtilityUsernameDelete.ps1'), done); + }); + it('Validate SPN end point (Delete-AzureSqlDatabaseServerFirewallRule)', (done) => { + psr.run(path.join(__dirname, 'L0UtilitySPNDelete.ps1'), done); + }); + it('Validate Certificate end point (Delete-AzureSqlDatabaseServerFirewallRule)', (done) => { + psr.run(path.join(__dirname, 'L0UtilityCertificateDelete.ps1'), done); + }); + it('IP Address Range Check (Get-AgentIPAddress)', (done) => { + psr.run(path.join(__dirname, 'L0UtilityIPRange.ps1'), done); + }); + it('Validate SQL Package Command Line Arguments (Get-SqlPackageCommandArguments)', (done) => { + psr.run(path.join(__dirname, 'L0UtilityGetSqlCmdArgs.ps1'), done); + }); + } +}); diff --git a/Tasks/SqlAzureDacpacDeployment/Tests/L0DacpacTaskFileCheck.ps1 b/Tasks/SqlAzureDacpacDeployment/Tests/L0DacpacTaskFileCheck.ps1 new file mode 100644 index 000000000000..373fa96f7844 --- /dev/null +++ b/Tasks/SqlAzureDacpacDeployment/Tests/L0DacpacTaskFileCheck.ps1 @@ -0,0 +1,28 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 +. $PSScriptRoot\MockVariable.ps1 + +Register-Mock Get-VstsInput { "DacpacTask" } -ParametersEvaluator { $Name -eq "TaskNameSelector" } +Register-Mock Get-VstsInput { "MultipleDacpacFiles" } -ParametersEvaluator { $Name -eq "DacpacFile" } +Register-Mock Get-VstsInput { "Mock Value"} -ParametersEvaluator { $Name -ne "TaskNameSelector" -and $Name -ne "DacpacFile" } + +Register-Mock Find-VstsFiles { + return @("Dacpac1.dacpac", "Dacpac2.dacpac", "DacpacN.dacpac") +} -ArgumentsEvaluator {$args.count -eq 2 -and $args[0] -like "LegacyPattern" -and $args[1] -like "MultipleDacpacFiles" } + +Assert-Throws { + & "$PSScriptRoot\..\DeploySqlAzure.ps1" +} -MessagePattern "*SAD_FoundMoreFiles*" + +Unregister-Mock Get-VstsInput +Register-Mock Get-VstsInput { "DacpacTask" } -ParametersEvaluator { $Name -eq "TaskNameSelector" } +Register-Mock Get-VstsInput { "NoDacpacFile" } -ParametersEvaluator { $Name -eq "DacpacFile" } +Register-Mock Get-VstsInput { "Mock Value"} -ParametersEvaluator { $Name -ne "TaskNameSelector" -and $Name -ne "DacpacFile" } + +Register-Mock Find-VstsFiles { $null } -ArgumentsEvaluator {$args.count -eq 2 -and $args[0] -like "LegacyPattern" -and $args[1] -like "NoDacpacFile" } + +Assert-Throws { + & "$PSScriptRoot\..\DeploySqlAzure.ps1" +} -MessagePattern "*SAD_NoFilesMatch*" diff --git a/Tasks/SqlAzureDacpacDeployment/Tests/L0SqlTaskFileCheck.ps1 b/Tasks/SqlAzureDacpacDeployment/Tests/L0SqlTaskFileCheck.ps1 new file mode 100644 index 000000000000..d6a30c1bc8c0 --- /dev/null +++ b/Tasks/SqlAzureDacpacDeployment/Tests/L0SqlTaskFileCheck.ps1 @@ -0,0 +1,39 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 +. $PSScriptRoot\MockVariable.ps1 + +Register-Mock Get-VstsInput { "SqlTask" } -ParametersEvaluator { $Name -eq "TaskNameSelector" } +Register-Mock Get-VstsInput { "MultipleSqlTaskFiles" } -ParametersEvaluator { $Name -eq "SqlFile" } +Register-Mock Get-VstsInput { "Mock Value" } -ParametersEvaluator { $Name -ne "TaskNameSelector" -and $Name -ne "SqlFile" } + +Register-Mock Find-VstsFiles { + return @("Dacpac1.sql", "Dacpac2.sql", "DacpacN.sql") +} -ArgumentsEvaluator {$args.count -eq 2 -and $args[0] -like "LegacyPattern" -and $args[1] -like "MultipleSqlTaskFiles" } + +Assert-Throws { + & "$PSScriptRoot\..\DeploySqlAzure.ps1" +} -MessagePattern "*SAD_FoundMoreFiles*" + +Unregister-Mock Get-VstsInput +Register-Mock Get-VstsInput { "SqlTask" } -ParametersEvaluator { $Name -eq "TaskNameSelector" } +Register-Mock Get-VstsInput { "NoSqlTaskFile" } -ParametersEvaluator { $Name -eq "SqlFile" } +Register-Mock Get-VstsInput { "Mock Value" } -ParametersEvaluator { $Name -ne "TaskNameSelector" -and $Name -ne "SqlFile"} + +Register-Mock Find-VstsFiles { $null } -ArgumentsEvaluator {$args.count -eq 2 -and $args[0] -like "LegacyPattern" -and $args[1] -like "NoSqlTaskFile" } + +Assert-Throws { + & "$PSScriptRoot\..\DeploySqlAzure.ps1" +} -MessagePattern "*SAD_NoFilesMatch*" + +Unregister-Mock Get-VstsInput +Register-Mock Get-VstsInput { "SqlTask" } -ParametersEvaluator { $Name -eq "TaskNameSelector" } +Register-Mock Get-VstsInput { "NonSqlTaskFile" } -ParametersEvaluator { $Name -eq "SqlFile" } +Register-Mock Get-VstsInput { "Mock Value" } -ParametersEvaluator { $Name -ne "TaskNameSelector" -and $Name -ne "SqlFile" } + +Register-Mock Find-VstsFiles { "nonsql.ps1" } -ArgumentsEvaluator {$args.count -eq 2 -and $args[0] -like "LegacyPattern" -and $args[1] -like "NonSqlTaskFile" } + +Assert-Throws { + & "$PSScriptRoot\..\DeploySqlAzure.ps1" +} -MessagePattern "*SAD_InvalidSqlFile*" \ No newline at end of file diff --git a/Tasks/SqlAzureDacpacDeployment/Tests/L0UtilityCertificateCreate.ps1 b/Tasks/SqlAzureDacpacDeployment/Tests/L0UtilityCertificateCreate.ps1 new file mode 100644 index 000000000000..f9b4dd870b2f --- /dev/null +++ b/Tasks/SqlAzureDacpacDeployment/Tests/L0UtilityCertificateCreate.ps1 @@ -0,0 +1,38 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 +. $PSScriptRoot\MockVariable.ps1 + + +#path to Utility.ps1 for SqlAzureDacpacDeployment task +. "$PSScriptRoot\..\Utility.ps1" + +Register-Mock Add-AzureSqlDatabaseServerFirewallRule { + throw "IPAddress mentioned is not a valid IPv4 address." +} -ParametersEvaluator { $startIPAddress -eq $outOfRangeIPAddress } + +Register-Mock Add-AzureSqlDatabaseServerFirewallRule { + throw "Sql Database Server: '$invalidAzureSqlServerName' not found." +} -ParametersEvaluator { $serverName -eq $invalidAzureSqlServerName } + +Assert-Throws { + Create-AzureSqlDatabaseServerFirewallRule -startIp $outOfRangeIPAddress -endIP $endIP -serverName $azureSqlServerName -endpoint $certEndpoint +} -MessagePattern "IPAddress mentioned is not a valid IPv4 address." + +Assert-Throws { + Create-AzureSqlDatabaseServerFirewallRule -startIp $startIP -endIP $endIP -serverName $invalidAzureSqlServerName -endpoint $certEndpoint +} -MessagePattern "Sql Database Server: '$invalidAzureSqlServerName' not found." + +Register-Mock Add-AzureSqlDatabaseServerFirewallRule { + $azureSqlDatabaseServerFirewallRule = @{ }; + $azureSqlDatabaseServerFirewallRule.RuleName = "RuleName"; + $azureSqlDatabaseServerFirewallRule.IsConfigured = $true; + return $azureSqlDatabaseServerFirewallRule; +} -ParametersEvaluator { $endpoint.Auth.Scheme -eq $certAuth.Scheme } + +$azureSqlDatabaseServerFirewallRule = Create-AzureSqlDatabaseServerFirewallRule -startIp $startIP -endIP $endIP -serverName $azureSqlServerName -endpoint $certEndpoint + +Assert-IsNotNullOrEmpty $azureSqlDatabaseServerFirewallRule "Firewall Rule - certificate end point cannot be null" +Assert-IsNotNullOrEmpty $azureSqlDatabaseServerFirewallRule.RuleName "Firewall Rule - certificate end point 'Rule Name' cannot be null" +Assert-AreEqual $true $azureSqlDatabaseServerFirewallRule.IsConfigured diff --git a/Tasks/SqlAzureDacpacDeployment/Tests/L0UtilityCertificateDelete.ps1 b/Tasks/SqlAzureDacpacDeployment/Tests/L0UtilityCertificateDelete.ps1 new file mode 100644 index 000000000000..7ae29a0af6fd --- /dev/null +++ b/Tasks/SqlAzureDacpacDeployment/Tests/L0UtilityCertificateDelete.ps1 @@ -0,0 +1,20 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 +. $PSScriptRoot\MockVariable.ps1 + +#path to Utility.ps1 for SqlAzureDacpacDeployment task +. "$PSScriptRoot\..\Utility.ps1" + +Register-Mock Remove-AzureSqlDatabaseServerFirewallRule { throw "Invalid Firewall Rule provided" } -ParametersEvaluator { $firewallRuleName -eq $invalidfirewallRuleName } +Register-Mock Remove-AzureSqlDatabaseServerFirewallRule { } -ParametersEvaluator { $firewallRuleName -eq $certificateFirewallRuleName } + +Assert-Throws { + Delete-AzureSqlDatabaseServerFirewallRule -serverName $azureSqlServerName -firewallRuleName $invalidfirewallRuleName ` + -endpoint $usernameEndpoint -deleteFireWallRule $true -isFirewallConfigured $true +} -MessagePattern "Invalid Firewall Rule provided" + +#should not throw +Delete-AzureSqlDatabaseServerFirewallRule -serverName $azureSqlServerName -firewallRuleName $certificateFirewallRuleName ` + -endpoint $usernameEndpoint -deleteFireWallRule $true -isFirewallConfigured $true \ No newline at end of file diff --git a/Tasks/SqlAzureDacpacDeployment/Tests/L0UtilityGetSqlCmdArgs.ps1 b/Tasks/SqlAzureDacpacDeployment/Tests/L0UtilityGetSqlCmdArgs.ps1 new file mode 100644 index 000000000000..26ef6cb0977d --- /dev/null +++ b/Tasks/SqlAzureDacpacDeployment/Tests/L0UtilityGetSqlCmdArgs.ps1 @@ -0,0 +1,37 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 +. $PSScriptRoot\MockVariable.ps1 + + +#path to Utility.ps1 for SqlAzureDacpacDeployment task +. "$PSScriptRoot\..\Utility.ps1" + +$sqlPackageCommandLineArguments = Get-SqlPackageCommandArguments -dacpacFile "azureDacpac.dacpac" -targetMethod "server" -serverName "yyy.database.windows.net" ` + -databaseName "databaseName" -sqlUsername "sqlUsername" -sqlPassword "sqlPassword" -publishProfile "Profile.xml" -additionalArguments "Add_args" + +Assert-AreEqual '/SourceFile:"azureDacpac.dacpac" /Action:Publish /TargetServerName:"yyy.database.windows.net" /TargetDatabaseName:"databaseName" /TargetUser:"sqlUsername" /TargetPassword:"sqlPassword" /Profile:"Profile.xml" Add_args' ` + $sqlPackageCommandLineArguments "Should have constructed Argument for TargetMethod Server" + +$sqlPackageCommandLineArguments = Get-SqlPackageCommandArguments -dacpacFile "azureDacpac.dacpac" -targetMethod "server" -serverName "yyy.database.windows.net" ` + -databaseName "databaseName" -sqlUsername "sqlUsername" -sqlPassword "sqlPassword" -publishProfile "Profile.xml" ` + -additionalArguments "Add_args" -isOutputSecure + +Assert-AreEqual '/SourceFile:"azureDacpac.dacpac" /Action:Publish /TargetServerName:"yyy.database.windows.net" /TargetDatabaseName:"databaseName" /TargetUser:"sqlUsername" /TargetPassword:"********" /Profile:"Profile.xml" Add_args' ` + $sqlPackageCommandLineArguments "Should have mocked paasword" + +$sqlPackageCommandLineArguments = Get-SqlPackageCommandArguments -dacpacFile "azureDacpac.dacpac" -targetMethod "connectionString" -connectionString "connectionString:10/20/30" ` + -publishProfile "Profile.xml" -additionalArguments "Add_args" -isOutputSecure +Assert-AreEqual '/SourceFile:"azureDacpac.dacpac" /Action:Publish /TargetConnectionString:"connectionString:10/20/30" /Profile:"Profile.xml" Add_args' ` + $sqlPackageCommandLineArguments "Should have constructed Argument for Connection String" + +Assert-Throws { + Get-SqlPackageCommandArguments -dacpacFile "azureDacpac.dacpac" -targetMethod "connectionString" -connectionString "connectionString:10/20/30" -publishProfile "Profile.json" ` + -additionalArguments "Add_args" -isOutputSecure +} -MessagePattern "*SAD_InvalidPublishProfile*" + +Assert-Throws { + Get-SqlPackageCommandArguments -dacpacFile "azureDacpac.sql" -targetMethod "connectionString" -connectionString "connectionString:10/20/30" -publishProfile "Profile.xml" ` + -additionalArguments "Add_args" -isOutputSecure +} -MessagePattern "*SAD_InvalidDacpacFile*" diff --git a/Tasks/SqlAzureDacpacDeployment/Tests/L0UtilityIPRange.ps1 b/Tasks/SqlAzureDacpacDeployment/Tests/L0UtilityIPRange.ps1 new file mode 100644 index 000000000000..31bc0b503dc8 --- /dev/null +++ b/Tasks/SqlAzureDacpacDeployment/Tests/L0UtilityIPRange.ps1 @@ -0,0 +1,19 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 +. $PSScriptRoot\MockVariable.ps1 + +#path to Utility.ps1 for SqlAzureDacpacDeployment task +. "$PSScriptRoot\..\Utility.ps1" + +#should not throw +$IPAddress = Get-AgentIPAddress -startIPAddress $outOfRangeIPAddress -endIPAddress $endIP -ipDetectionMethod $ipDetectionMethod + +Assert-AreEqual $outOfRangeIPAddress $IPAddress.StartIPAddress +Assert-AreEqual $endIP $IPAddress.EndIPAddress + + $IPAddress = Get-AgentIPAddress -startIPAddress $startIP -endIPAddress $endIP -ipDetectionMethod $ipDetectionMethod + +Assert-AreEqual $startIP $IPAddress.StartIPAddress +Assert-AreEqual $endIP $IPAddress.EndIPAddress \ No newline at end of file diff --git a/Tasks/SqlAzureDacpacDeployment/Tests/L0UtilitySPNCreate.ps1 b/Tasks/SqlAzureDacpacDeployment/Tests/L0UtilitySPNCreate.ps1 new file mode 100644 index 000000000000..568e2605dfed --- /dev/null +++ b/Tasks/SqlAzureDacpacDeployment/Tests/L0UtilitySPNCreate.ps1 @@ -0,0 +1,32 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 +. $PSScriptRoot\MockVariable.ps1 + +#path to Utility.ps1 for SqlAzureDacpacDeployment task +. "$PSScriptRoot\..\Utility.ps1" + +Register-Mock Add-AzureSqlDatabaseServerFirewallRule { throw "IPAddress mentioned is not a valid IPv4 address." } -ParametersEvaluator { $startIPAddress -eq $outOfRangeIPAddress } +Register-Mock Add-AzureSqlDatabaseServerFirewallRule { throw "Sql Database Server: '$invalidAzureSqlServerName' not found."} -ParametersEvaluator { $serverName -eq $invalidAzureSqlServerName } + +Assert-Throws { + Create-AzureSqlDatabaseServerFirewallRule -startIp $outOfRangeIPAddress -endIP $endIP -serverName $azureSqlServerName -endpoint $spnEndpoint +} -MessagePattern "IPAddress mentioned is not a valid IPv4 address." + +Assert-Throws { + Create-AzureSqlDatabaseServerFirewallRule -startIp $startIP -endIP $endIP -serverName $invalidAzureSqlServerName -endpoint $spnEndpoint +} -MessagePattern "Sql Database Server: '$invalidAzureSqlServerName' not found." + +Register-Mock Add-AzureSqlDatabaseServerFirewallRule { + $azureSqlDatabaseServerFirewallRule = @{ }; + $azureSqlDatabaseServerFirewallRule.RuleName = "RuleName"; + $azureSqlDatabaseServerFirewallRule.IsConfigured = $true; + return $azureSqlDatabaseServerFirewallRule; +} -ParametersEvaluator { $endpoint.Auth.Scheme -eq $spnAuth.Scheme } + +$azureSqlDatabaseServerFirewallRule = Create-AzureSqlDatabaseServerFirewallRule -startIp $startIP -endIP $endIP -serverName $azureSqlServerName -endpoint $spnEndpoint + +Assert-IsNotNullOrEmpty $azureSqlDatabaseServerFirewallRule "Firewall Rule - certificate end point cannot be null" +Assert-IsNotNullOrEmpty $azureSqlDatabaseServerFirewallRule.RuleName "Firewall Rule - username end point 'Rule Name' cannot be null" +Assert-AreEqual $true $azureSqlDatabaseServerFirewallRule.IsConfigured diff --git a/Tasks/SqlAzureDacpacDeployment/Tests/L0UtilitySPNDelete.ps1 b/Tasks/SqlAzureDacpacDeployment/Tests/L0UtilitySPNDelete.ps1 new file mode 100644 index 000000000000..734f4354028c --- /dev/null +++ b/Tasks/SqlAzureDacpacDeployment/Tests/L0UtilitySPNDelete.ps1 @@ -0,0 +1,18 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 +. $PSScriptRoot\MockVariable.ps1 + +#path to Utility.ps1 for SqlAzureDacpacDeployment task +. "$PSScriptRoot\..\Utility.ps1" + +Register-Mock Remove-AzureSqlDatabaseServerFirewallRule { throw "Invalid Firewall Rule provided" } -ParametersEvaluator { $firewallRuleName -eq $invalidfirewallRuleName } +Register-Mock Remove-AzureSqlDatabaseServerFirewallRule { } -ParametersEvaluator { $firewallRuleName -eq $spnFirewallRuleName } + +Assert-Throws { + Delete-AzureSqlDatabaseServerFirewallRule -serverName $azureSqlServerName -firewallRuleName $invalidfirewallRuleName -endpoint $spnEndpoint -deleteFireWallRule $true -isFirewallConfigured $true +} -MessagePattern "Invalid Firewall Rule provided" + +#should not throw +Delete-AzureSqlDatabaseServerFirewallRule -serverName $azureSqlServerName -firewallRuleName $spnFirewallRuleName -endpoint $spnEndpoint -deleteFireWallRule $true -isFirewallConfigured $true \ No newline at end of file diff --git a/Tasks/SqlAzureDacpacDeployment/Tests/L0UtilityUsernameCreate.ps1 b/Tasks/SqlAzureDacpacDeployment/Tests/L0UtilityUsernameCreate.ps1 new file mode 100644 index 000000000000..44792652862d --- /dev/null +++ b/Tasks/SqlAzureDacpacDeployment/Tests/L0UtilityUsernameCreate.ps1 @@ -0,0 +1,25 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 +. $PSScriptRoot\MockVariable.ps1 + +#path to Utility.ps1 for SqlAzureDacpacDeployment task +. "$PSScriptRoot\..\Utility.ps1" + +Register-Mock Add-AzureSqlDatabaseServerFirewallRule { throw "IPAddress mentioned is not a valid IPv4 address." } -ParametersEvaluator { $startIPAddress -eq $outOfRangeIPAddress } +Register-Mock Add-AzureSqlDatabaseServerFirewallRule { throw "Sql Database Server: '$invalidAzureSqlServerName' not found."} -ParametersEvaluator { $serverName -eq $invalidAzureSqlServerName } + +Assert-Throws { + Create-AzureSqlDatabaseServerFirewallRule -startIp $outOfRangeIPAddress -endIP $endIP -serverName $azureSqlServerName -endpoint $usernameEndpoint +} -MessagePattern "IPAddress mentioned is not a valid IPv4 address." + +Assert-Throws { + Create-AzureSqlDatabaseServerFirewallRule -startIp $startIP -endIP $endIP -serverName $invalidAzureSqlServerName -endpoint $usernameEndpoint +} -MessagePattern "Sql Database Server: '$invalidAzureSqlServerName' not found." + +$azureSqlDatabaseServerFirewallRule = Create-AzureSqlDatabaseServerFirewallRule -startIp $startIP -endIP $endIP -serverName $azureSqlServerName -endpoint $usernameEndpoint + +Assert-IsNotNullOrEmpty $azureSqlDatabaseServerFirewallRule "Firewall Rule - certificate end point cannot be null" +Assert-IsNotNullOrEmpty $azureSqlDatabaseServerFirewallRule.RuleName "Firewall Rule - username end point 'Rule Name' cannot be null" +Assert-AreEqual $true $azureSqlDatabaseServerFirewallRule.IsConfigured diff --git a/Tasks/SqlAzureDacpacDeployment/Tests/L0UtilityUsernameDelete.ps1 b/Tasks/SqlAzureDacpacDeployment/Tests/L0UtilityUsernameDelete.ps1 new file mode 100644 index 000000000000..e226f82a6d14 --- /dev/null +++ b/Tasks/SqlAzureDacpacDeployment/Tests/L0UtilityUsernameDelete.ps1 @@ -0,0 +1,20 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 +. $PSScriptRoot\MockVariable.ps1 + +#path to Utility.ps1 for SqlAzureDacpacDeployment task +. "$PSScriptRoot\..\Utility.ps1" + +Register-Mock Remove-AzureSqlDatabaseServerFirewallRule { throw "Invalid Firewall Rule provided" } -ParametersEvaluator { $firewallRuleName -eq $invalidfirewallRuleName } +Register-Mock Remove-AzureSqlDatabaseServerFirewallRule { } -ParametersEvaluator { $firewallRuleName -eq $credentialsFirewallRuleName } + +Assert-Throws { + Delete-AzureSqlDatabaseServerFirewallRule -serverName $azureSqlServerName -firewallRuleName $invalidfirewallRuleName ` + -endpoint $certEndpoint -deleteFireWallRule $true -isFirewallConfigured $true +} -MessagePattern "Invalid Firewall Rule provided" + +#should not throw +Delete-AzureSqlDatabaseServerFirewallRule -serverName $azureSqlServerName -firewallRuleName $credentialsFirewallRuleName -endpoint $certEndpoint ` + -deleteFireWallRule $true -isFirewallConfigured $true \ No newline at end of file diff --git a/Tasks/SqlAzureDacpacDeployment/Tests/L0ValidDacpacInput.ps1 b/Tasks/SqlAzureDacpacDeployment/Tests/L0ValidDacpacInput.ps1 new file mode 100644 index 000000000000..09737005a593 --- /dev/null +++ b/Tasks/SqlAzureDacpacDeployment/Tests/L0ValidDacpacInput.ps1 @@ -0,0 +1,52 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 +. $PSScriptRoot\MockVariable.ps1 + +#Mock Vsts-Input +Register-Mock Get-VstsInput { "ConnectedServiceName" } -ParametersEvaluator { $Name -eq "ConnectedServiceNameSelector" } +Register-Mock Get-VstsInput { "DacpacTask" } -ParametersEvaluator { $Name -eq "TaskNameSelector" } +Register-Mock Get-VstsInput { "DacpacFile.dacpac" } -ParametersEvaluator { $Name -eq "DacpacFile" } +Register-Mock Get-VstsInput { "SqlFile.sql" } -ParametersEvaluator { $Name -eq "SqlFile" } +Register-Mock Get-VstsInput { $databaseName } -ParametersEvaluator { $Name -eq "DatabaseName" } +Register-Mock Get-VstsInput { $serverName } -ParametersEvaluator { $Name -eq "ServerName" } +Register-Mock Get-VstsInput { "ConnectedServiceName" } -ParametersEvaluator { $Name -eq "ConnectedServiceName" } +Register-Mock Get-VstsInput { "ConnectedServiceNameARM" } -ParametersEvaluator { $Name -eq "ConnectedServiceNameARM" } +Register-Mock Get-VstsInput { $sqlUsername } -ParametersEvaluator { $Name -eq "SqlUsername" } +Register-Mock Get-VstsInput { $sqlPassword } -ParametersEvaluator { $Name -eq "SqlPassword" } +Register-Mock Get-VstsInput { $publishProfile } -ParametersEvaluator { $Name -eq "PublishProfile" } +Register-Mock Get-VstsInput { "AdditionalArguments" } -ParametersEvaluator { $Name -eq "AdditionalArguments" } +Register-Mock Get-VstsInput { "InlineAdditionalArguments" } -ParametersEvaluator { $Name -eq "InlineAdditionalArguments" } +Register-Mock Get-VstsInput { $ipDetectionMethodRange } -ParametersEvaluator { $Name -eq "IpDetectionMethod" } +Register-Mock Get-VstsInput { $startIPAddress } -ParametersEvaluator { $Name -eq "StartIpAddress" } +Register-Mock Get-VstsInput { $endIPAddress } -ParametersEvaluator { $Name -eq "EndIpAddress" } +Register-Mock Get-VstsInput { $deleteFirewallRuleTrue } -ParametersEvaluator { $Name -eq "DeleteFirewallRule" } + +Register-Mock Find-VstsFiles { "dacpacFile.dacpac" } -ArgumentsEvaluator {$args.count -eq 2 -and $args[0] -like "LegacyPattern" -and $args[1] -like "DacpacFile.dacpac" } +Register-Mock Find-VstsFiles { "PublishProfile.xml" } -ArgumentsEvaluator {$args.count -eq 2 -and $args[0] -like "LegacyPattern" -and $args[1] -like "C:\Test\publish.xml" } + +Register-Mock Get-Endpoint { $usernameEndpoint } -ParametersEvaluator { $connectedServiceName -eq "connectedServiceName"} +Register-Mock Add-AzureSqlDatabaseServerFirewallRule { + $fireWallRule = @{ } + $fireWallRule.RuleName = "Mock File Wall Rule Name" + $fireWallRule.IsConfigured = $true; + return $fireWallRule +} -ParametersEvaluator { $startIp -eq "StartIpAddress" -and $endIPAddress -eq "EndIpAddress" -and $serverName -eq $mockServerFriendlyName -and $endPoint -eq $usernameEndpoint } + +Register-Mock Get-SqlPackageOnTargetMachine { 'path/to/dac/bin/sqlpackage.exe' } + + +Register-Mock Delete-AzureSqlDatabaseServerFirewallRule { } + +Register-Mock Run-Command { 'executed command ! '} -ArgumentsEvaluator { + $args.count -eq 1 -and $args[0] -eq '"path/to/dac/bin/sqlpackage.exe" /SourceFile:"dacpacFile.dacpac" /Action:Publish /TargetServerName:"a0nuel7r2k.database.windows.net" /TargetDatabaseName:"TestDatabase" /TargetUser:"TestUser" /TargetPassword:"TestPassword" /Profile:"PublishProfile.xml" AdditionalArguments /TargetTimeout:120' +} + +Register-Mock Run-Command { throw 'Invalid Command passed !' } -ArgumentsEvaluator { + $args.count -eq 1 -and $args[0] -ne '"path/to/dac/bin/sqlpackage.exe" /SourceFile:"dacpacFile.dacpac" /Action:Publish /TargetServerName:"a0nuel7r2k.database.windows.net" /TargetDatabaseName:"TestDatabase" /TargetUser:"TestUser" /TargetPassword:"TestPassword" /Profile:"PublishProfile.xml" AdditionalArguments /TargetTimeout:120' +} + +& "$PSScriptRoot\..\DeploySqlAzure.ps1" + +Assert-WasCalled Run-Command -Times 1 \ No newline at end of file diff --git a/Tasks/SqlAzureDacpacDeployment/Tests/L0ValidSqlInput.ps1 b/Tasks/SqlAzureDacpacDeployment/Tests/L0ValidSqlInput.ps1 new file mode 100644 index 000000000000..b5a07a812c27 --- /dev/null +++ b/Tasks/SqlAzureDacpacDeployment/Tests/L0ValidSqlInput.ps1 @@ -0,0 +1,53 @@ + +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 +. $PSScriptRoot\MockVariable.ps1 + +#Mock Vsts-Input +Register-Mock Get-VstsInput { "ConnectedServiceName" } -ParametersEvaluator { $Name -eq "ConnectedServiceNameSelector" } +Register-Mock Get-VstsInput { "SqlTask" } -ParametersEvaluator { $Name -eq "TaskNameSelector" } +Register-Mock Get-VstsInput { "DacpacFile.dacpac" } -ParametersEvaluator { $Name -eq "DacpacFile" } +Register-Mock Get-VstsInput { "SqlFile.sql" } -ParametersEvaluator { $Name -eq "SqlFile" } +Register-Mock Get-VstsInput { $databaseName } -ParametersEvaluator { $Name -eq "DatabaseName" } +Register-Mock Get-VstsInput { $serverName } -ParametersEvaluator { $Name -eq "ServerName" } +Register-Mock Get-VstsInput { "ConnectedServiceName" } -ParametersEvaluator { $Name -eq "ConnectedServiceName" } +Register-Mock Get-VstsInput { "ConnectedServiceNameARM" } -ParametersEvaluator { $Name -eq "ConnectedServiceNameARM" } +Register-Mock Get-VstsInput { $sqlUsername } -ParametersEvaluator { $Name -eq "SqlUsername" } +Register-Mock Get-VstsInput { $sqlPassword } -ParametersEvaluator { $Name -eq "SqlPassword" } +Register-Mock Get-VstsInput { $publishProfile } -ParametersEvaluator { $Name -eq "PublishProfile" } +Register-Mock Get-VstsInput { "SqlAdditionalArguments" } -ParametersEvaluator { $Name -eq "SqlAdditionalArguments" } +Register-Mock Get-VstsInput { "InlineAdditionalArguments" } -ParametersEvaluator { $Name -eq "InlineAdditionalArguments" } +Register-Mock Get-VstsInput { $ipDetectionMethodRange } -ParametersEvaluator { $Name -eq "IpDetectionMethod" } +Register-Mock Get-VstsInput { $startIPAddress } -ParametersEvaluator { $Name -eq "StartIpAddress" } +Register-Mock Get-VstsInput { $endIPAddress } -ParametersEvaluator { $Name -eq "EndIpAddress" } +Register-Mock Get-VstsInput { $deleteFirewallRuleTrue } -ParametersEvaluator { $Name -eq "DeleteFirewallRule" } + +Register-Mock Find-VstsFiles { "SqlFile.sql" } -ArgumentsEvaluator {$args.count -eq 2 -and $args[0] -like "LegacyPattern" -and $args[1] -like "SqlFile.sql" } +Register-Mock Find-VstsFiles { "PublishProfile.xml" } -ArgumentsEvaluator {$args.count -eq 2 -and $args[0] -like "LegacyPattern" -and $args[1] -like "C:\Test\publish.xml" } + +Register-Mock Import-SqlPs + +Register-Mock Get-Endpoint { $usernameEndpoint } -ParametersEvaluator { $connectedServiceName -eq "connectedServiceName" } + +Register-Mock Add-AzureSqlDatabaseServerFirewallRule { + $fireWallRule = @{ } + $fireWallRule.RuleName = "Mock File Wall Rule Name" + $fireWallRule.IsConfigured = $true; + return $fireWallRule +} -ParametersEvaluator { $startIp -eq "StartIpAddress" -and $endIPAddress -eq "EndIpAddress" -and $serverName -eq $mockServerFriendlyName -and $endPoint -eq $usernameEndpoint } + +Register-Mock Remove-AzureSqlDatabaseServerFirewallRule { } + +Register-Mock Invoke-Expression { "Executing Command : $args" } -ArgumentsEvaluator { + $args.count -eq 1 -and $args[0] -eq 'Invoke-Sqlcmd -ServerInstance "a0nuel7r2k.database.windows.net" -Database "TestDatabase" -Username "TestUser" -Password "TestPassword" -Inputfile "SqlFile.sql" SqlAdditionalArguments -ConnectionTimeout 120' +} + +Register-Mock Invoke-Expression { throw 'Invalid Argument passed !' } -ArgumentsEvaluator { + $args.count -eq 1 -and $args[0] -ne 'Invoke-Sqlcmd -ServerInstance "a0nuel7r2k.database.windows.net" -Database "TestDatabase" -Username "TestUser" -Password "TestPassword" -Inputfile "SqlFile.sql" SqlAdditionalArguments -ConnectionTimeout 120' +} + +& "$PSScriptRoot\..\DeploySqlAzure.ps1" + +Assert-WasCalled Invoke-Expression -Times 1 \ No newline at end of file diff --git a/Tasks/SqlAzureDacpacDeployment/Tests/MockVariable.ps1 b/Tasks/SqlAzureDacpacDeployment/Tests/MockVariable.ps1 new file mode 100644 index 000000000000..d447fe8276d9 --- /dev/null +++ b/Tasks/SqlAzureDacpacDeployment/Tests/MockVariable.ps1 @@ -0,0 +1,52 @@ +$azureSqlServerName = "d2eu50p1fw" +$invalidAzureSqlServerName = "invalidServerName" +$databaseName = "testDb" +$serverUserName = "dummyUser" +$serverPassword = "dummyPassword" +$startIP="167.220.236.2" +$endIP="167.220.236.2" +$outOfRangeIPAddress = "167.220.236.256" + +$invalidfirewallRuleName = "invalidFirewallRule" +$certificateFirewallRuleName= "certificateFirewallRuleName" +$credentialsFirewallRuleName = "credentialsFirewallRuleName" +$spnFirewallRuleName = "spnFirewallRuleName" + +$certEndpoint=@{} +$usernameEndpoint=@{} +$spnEndpoint=@{} + +$certAuth=@{} +$usernameAuth=@{} +$spnAuth=@{} + +$certAuth.Scheme='Certificate' +$certEndpoint.Auth =$certAuth + +$usernameAuth.Scheme='UserNamePassword' +$usernameEndpoint.Auth =$usernameAuth + +$spnEndpoint.Scheme='ServicePrincipal' +$spnEndpoint.Auth =$spnEndpoint + +$ipDetectionMethod = "IPAddressRange"; + +#### Main File Mock Constants #### + +$validInputConnectedServiceName = "validConnectedServiceName" +$dacpacFile = "C:\Test\Test.ps1" +$serverName = "a0nuel7r2k.database.windows.net" +$serverFriendlyName = "a0nuel7r2k" +$databaseName = "TestDatabase" +$sqlUsername = "TestUser" +$sqlPassword = "TestPassword" +$publishProfile = "C:\Test\publish.xml" +$ipDetectionMethodAuto = "AutoDetect" +$ipDetectionMethodRange = "IPAddressRange" +$deleteFirewallRuleTrue = $true +$deleteFirewallRuleFalse = $false +$startIPAddress = "10.10.10.10" +$endIPAddress = "10.10.10.11" + +$autoIp = "10.10.10.10" +$sqlPackageArguments = "Test Arguments" diff --git a/Tasks/SqlAzureDacpacDeployment/task.json b/Tasks/SqlAzureDacpacDeployment/task.json index 71e8307c462c..496139476f0e 100644 --- a/Tasks/SqlAzureDacpacDeployment/task.json +++ b/Tasks/SqlAzureDacpacDeployment/task.json @@ -17,7 +17,7 @@ "version": { "Major": 1, "Minor": 1, - "Patch": 2 + "Patch": 3 }, "demands": [ "sqlpackage" diff --git a/Tasks/SqlAzureDacpacDeployment/task.loc.json b/Tasks/SqlAzureDacpacDeployment/task.loc.json index fafe8e260646..d45b4261715a 100644 --- a/Tasks/SqlAzureDacpacDeployment/task.loc.json +++ b/Tasks/SqlAzureDacpacDeployment/task.loc.json @@ -17,7 +17,7 @@ "version": { "Major": 1, "Minor": 1, - "Patch": 2 + "Patch": 3 }, "demands": [ "sqlpackage" diff --git a/Tasks/SqlAzureDacpacDeployment/tsconfig.json b/Tasks/SqlAzureDacpacDeployment/tsconfig.json new file mode 100644 index 000000000000..79a868c8d1e3 --- /dev/null +++ b/Tasks/SqlAzureDacpacDeployment/tsconfig.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "target": "ES6", + "module": "commonjs" + }, + "exclude": [ + "node_modules" + ] +} \ No newline at end of file diff --git a/Tasks/SqlDacpacDeploymentOnMachineGroup/Main.ps1 b/Tasks/SqlDacpacDeploymentOnMachineGroup/Main.ps1 new file mode 100644 index 000000000000..b46b8727a6b2 --- /dev/null +++ b/Tasks/SqlDacpacDeploymentOnMachineGroup/Main.ps1 @@ -0,0 +1,66 @@ +Trace-VstsEnteringInvocation $MyInvocation +Import-VstsLocStrings "$PSScriptRoot\Task.json" + +$taskType = Get-VstsInput -Name "TaskType" -Require +$dacpacFile = Get-VstsInput -Name "dacpacFile" +$sqlFile = Get-VstsInput -Name "sqlFile" +$inlineSql = Get-VstsInput -Name "inlineSql" +$targetMethod = Get-VstsInput -Name "targetMethod" +$databaseName = Get-VstsInput -Name "databaseName" -Require +$authscheme = Get-VstsInput -Name "authscheme" -Require +$sqlUsername = Get-VstsInput -Name "sqlUsername" +$sqlPassword = Get-VstsInput -Name "sqlPassword" +$connectionString = Get-VstsInput -Name "connectionString" +$publishProfile = Get-VstsInput -Name "publishProfile" +$additionalArguments = Get-VstsInput -Name "additionalArguments" +$additionalArgumentsSql = Get-VstsInput -Name "additionalArgumentsSql" + +Import-Module $PSScriptRoot\ps_modules\TaskModuleSqlUtility + +Try +{ + $serverName = "localhost" + if ($taskType -ne "dacpac") + { + $additionalArguments = $additionalArgumentsSql + $targetMethod = "server" + } + + if($sqlUsername -and $sqlPassword) + { + $secureAdminPassword = "$sqlPassword" | ConvertTo-SecureString -AsPlainText -Force + $sqlServerCredentials = New-Object System.Management.Automation.PSCredential ("$sqlUserName", $secureAdminPassword) + } + + if ($taskType -eq "dacpac") + { + Execute-DacpacDeployment -dacpacFile $dacpacFile -targetMethod $targetMethod -serverName $serverName -databaseName $databaseName -authscheme $authscheme -sqlServerCredentials $sqlServerCredentials -connectionString $connectionString -publishProfile $publishProfile -additionalArguments $additionalArguments + } + else + { + $connectionString = Escape-SpecialChars -str $connectionString + $sqlPassword = Escape-SpecialChars -str $sqlPassword + $additionalArguments = Escape-SpecialChars -str $additionalArguments + $databaseName = Escape-SpecialChars -str $databaseName + Execute-SqlQueryDeployment -taskType $taskType -sqlFile $sqlFile -inlineSql $inlineSql -serverName $serverName -databaseName $databaseName -authscheme $authscheme -sqlServerCredentials $sqlServerCredentials -additionalArguments $additionalArguments + } + +} +Catch [System.Management.Automation.CommandNotFoundException] +{ + if ($_.Exception.CommandName -ieq "Invoke-Sqlcmd") + { + Write-Error (Get-VstsLocString -Key "SQLPowershellModuleisnotinstalledonyouragentmachine") + Write-Error (Get-VstsLocString -Key "InstallPowershellToolsharedManagementObjectsdependency") + Write-Error (Get-VstsLocString -Key "RestartagentmachineafterinstallingtoolstoregisterModulepathupdates") + Write-Error (Get-VstsLocString -Key "RunImportModuleSQLPSonyouragentPowershellprompt") + } + + Write-Error ($_.Exception|Format-List -Force|Out-String) + throw +} +Catch [Exception] +{ + Write-Error ($_.Exception|Format-List -Force|Out-String) + throw +} diff --git a/Tasks/SqlDacpacDeploymentOnMachineGroup/README.md b/Tasks/SqlDacpacDeploymentOnMachineGroup/README.md new file mode 100644 index 000000000000..26bd53bcf324 --- /dev/null +++ b/Tasks/SqlDacpacDeploymentOnMachineGroup/README.md @@ -0,0 +1,64 @@ +# Deploy SQL Dacpac Machine Group + +## Overview: + +The Deploy SQL Dacpac Machine Group task is used to deploy SQL Server database to an existing SQL Server instance, and the underlying technologies used by the task are [DACPAC](https://msdn.microsoft.com/en-IN/library/ee210546.aspx) and [SqlPackage.exe](https://msdn.microsoft.com/en-us/library/hh550080\(v=vs.103\).aspx). DACPACs and SqlPackage.exe provide fine-grained control over database creation and upgrades, including upgrades for schema, triggers, stored procedures, roles, users, extended properties etc. Using the task, around eighty different properties can be set to ensure that the database is created or upgraded properly like: + +- Ignore Data Loss - If false, upgrade will fail if it results in a data-loss. +- Verify Deployment - If true, the deployment is verified and blocked if can fail. For example, foreign keys have not been specified in the DACPAC but exist in the target database. +- Block on Changes - If true, upgrade is terminated if a schema drift is detected. +- Rollback on Failure - If true, then the upgrade is rolled back if errors are encountered. +- Backup Database Before Changes - If true, a backup of the database is taken prior to applying the changes. + +The task runs on the automation agent machine, and connects to the target machine(s) using [Windows Remote Management][1] (WinRM), and launches a bootstrapping executable program (VisualStudioRemoteDeployer.exe) on the target machine(s), and the bootstrap executable invokes the PowerShell scripts to locate the sqlpackage.exe on the machine, and creates or updates the SQL Server database using sqlpackage.exe. As the execution happens within the target machine(s), it is important to have the pre-requisites described below, installed properly on the target machine(s). + +## Contact Information + +Please contact the alias RM\_Customer\_Queries at microsoft dot com, if you are facing problems in making this task work. Also, share feedback about the task, and the new features that you would like to see in it. + +## Pre-requisites for the task + +The following pre-requisites need to be setup in the target machine(s) for the task to work properly. + +### SQL Server + +There should be a SQL Server instance that is already installed and configured on the pre-existing machines or virtual machines. The task deploys SQL Server database but does not install or configure SQL Server. + +### SqlPackage.exe + +SqlPackage.exe is used to create or upgrade the database and it is installed during the installation of SQL Server 2008 R2/2012/2014/2016. If the SQL Server Database deployment task is targeting these versions of SQL Server, then there is no need to install SqlPackage.exe separately. However, the latest version of SqlPackage.exe ships with SQL Server 2014, and is also available as a web download, and installs when the products listed below are installed on a machine. The latest version of SqlPackage.exe can target database deployments from SQL Server 2005 onwards and it is advisable to install that on the deployment machine. If the deployment of the SQL Server database is happening on the Web Server which is targeting a database on a separate Database Server that is behind firewall in a DMZ zone, then SqlPackage.exe needs to be installed on the Web Server: + +* Install the latest version of sqlpackage.exe by installing the **SQL Server Data-Tier Application Framework (July 2015)** from https://www.microsoft.com/en-us/download/details.aspx?id=48203. On x64 machines, install both the en\x86\DACFramework.msi and the en\x64\DACFramework.msi. +* Install it by using the [Microsoft Web Platform Installer](http://www.microsoft.com/web/gallery/install.aspx?appid=DACFX) (Web PI). Note that the link will open Web PI with the DACFX showing-up ready to install, where the DACFX download represents all the MSIs that need to be installed for SqlPackage.exe. **Note that this is an older version of June 2014 as compared to the link given above for the July 2015 release**. +* [SQL Server Management Studio](https://www.microsoft.com/en-in/download/details.aspx?id=42299) for SQL Server 2014 or SQL Server Express or SQL Server 2012 and SQL Server 2014 and [DAC Framework](http://www.microsoft.com/en-us/download/details.aspx?id=42293) MSIs install SqlPackage.exe at C:\Program Files (x86)\Microsoft SQL Server\120\DAC\bin. **Note that this is an older version as compared to the link given above for the July 2015 release**. +* Visual Studio 2015 installs the SqlPackage.exe at - C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\Extensions\Microsoft\SQLDB\DAC\120. Here the install location of Visual Studio is - C:\Program Files (x86)\Microsoft Visual Studio 14.0. **Note that this is an older version as compared to the link given above for the July 2015 release**. + +The task [PowerShell on Target Machines](https://github.com/Microsoft/vsts-tasks/tree/master/Tasks/PowerShellOnTargetMachines) can be used to deploy SqlPackage.exe to Azure virtual machines or domain-joined/workgroup machines. + +#### Specifying Machine Details in the Task + +Specify the machine details, wiz. the IP Address or the FDQN, administrator's login, password, WimRM HTTP/HTTPS protocol, and Test Certificate in the task itself. The difference between using the domain-joined/workgroup on-premises physical or virtual machines and the Azure virtual machines is that copying files to them is done by separate tasks. The [Windows Machine File Copy](https://github.com/Microsoft/vso-agent-tasks/tree/master/Tasks/WindowsMachineFileCopy) is used for the domain-joined/workgroup machines and the [Azure File Copy](https://github.com/Microsoft/vso-agent-tasks/tree/master/Tasks/AzureFileCopy) is used for the Azure virtual machines. Note that the **WinRM - SQL Server Database Deployment** task expects the web application's package zip files to be available on the target machines or on a UNC path that is accessible by the target machine administrator's login. + +## Parameters of the task: + +The parameters of the task are described in details, including examples, to show how to input the parameters. The parameters listed with a \* are required parameters for the task: + +### Deploy SQL Server Database +This section of the task is used to deploy SQL Server Database to an existing SQL Server using sqlpackage.exe. + + - **DACPAC File\*:** Location of the DACPAC file on the target machine or on a UNC path that is accessible to the administrator credentials of the machine like, \\BudgetIT\Web\Deploy\FabrikamDB.dacpac. Environment variables are also supported like $env:windir, $env:systemroot etc. For example, $env:windir\FabrikamFibre\Web. + - **Specify SQL Using\*:** The task provides for three different ways to provide information to connect to a SQL Server instance. The options are to provide SQL Server instance and database details, or to provide a SQL Server connection string, or to provide the location of the Publish profile XML file on the target machine. + - **Server Name\*:** Provide the SQL Server name like, _machinename_\FabriakmSQL,1433, or localhost, or .\SQL2012R2. Specifying localhost will connect to the Default SQL Server instance on the machine. + - **Database Name\*:** The name of the SQL Server Database like Fabrikan. The Database will be created new if it does not exist, else it will be updated if it already exists. + - **Authentication\*:** Select the authentication mode for connecting to the SQL Server. If the Windows authentication mode is selected, the administrator's account, as specified in the Machine Detail section, will be used to connect to the SQL Server. If the SQL Server Authentication mode is selected, then the SQL login and Password have to be provided in the parameters below. + - **SQL Username** : Provide the SQL Server login. The option is required and only available if SQL Server Authentication mode is selected. + - **SQL Password:** The password for the SQL Server login. The option is required and only available if SQL Server Authentication mode is selected. + - **Connection String\*:** Specify the SQL Server connection string like "Server=localhost;Database=Fabrikam;User ID=sqluser;Password=password;". + - **Publish Profile:** Publish profile provide fine-grained control over SQL Server database creation or upgrades. Specify the path to the Publish profile XML file on the target machine or on a UNC share that is accessible by the machine administrator's credentials. This is an optional parameter. However, if the seletced option for the 'Specify SQL Using' parameter is Publish Profile XML file, then this is a required parameter. + - **Additional SqlPackage.exe Arguments:** Additional SqlPackage.exe arguments that will be applied when creating or updating the SQL Server database like: + + /p:IgnoreAnsiNulls=True /p:IgnoreComments=True + + These arguments will override the settings in the Publish profile XML file (if provided). A full list of the arguments that can provided is listed in the ' **Properties**' sub-section of the ' **Publish Parameters, Properties, and SQLCMD Variables**' in the [SqlPackage.exe](https://msdn.microsoft.com/en-us/library/hh550080\(v=vs.103\).aspx) documentation. The SQLCMD variables can be also specified here. This is an optional parameter. + + diff --git a/Tasks/SqlDacpacDeploymentOnMachineGroup/Strings/resources.resjson/en-US/resources.resjson b/Tasks/SqlDacpacDeploymentOnMachineGroup/Strings/resources.resjson/en-US/resources.resjson new file mode 100644 index 000000000000..513e42f47d03 --- /dev/null +++ b/Tasks/SqlDacpacDeploymentOnMachineGroup/Strings/resources.resjson/en-US/resources.resjson @@ -0,0 +1,36 @@ +{ + "loc.friendlyName": "Deploy SQL Dacpac Machine Group(Preview)", + "loc.helpMarkDown": "[More Information](https://aka.ms/sqldacpacmachinegroupreadme)", + "loc.description": "Deploy DB using sqlpackage.exe or Invoke-Sqlcmd", + "loc.instanceNameFormat": "Deploy using : $(TaskType)", + "loc.input.label.TaskType": "Deploy SQL Using", + "loc.input.help.TaskType": "Specify the way in which you want to deploy DB, either by using Dacpac or by using Sql Script.", + "loc.input.label.DacpacFile": "DACPAC File", + "loc.input.help.DacpacFile": "Location of the DACPAC file on the target machines or on a UNC path like, \\\\\\\\BudgetIT\\Web\\Deploy\\FabrikamDB.dacpac. The UNC path should be accessible to the machine's administrator account. Environment variables are also supported, like $env:windir, $env:systemroot, $env:windir\\FabrikamFibre\\DB.", + "loc.input.label.SqlFile": "Sql File", + "loc.input.help.SqlFile": "Location of the SQL file on the target machines or on a UNC path like, \\\\\\\\BudgetIT\\Web\\Deploy\\FabrikamDB.sql. The UNC path should be accessible to the machine's administrator account. Environment variables are also supported, like $env:windir, $env:systemroot, $env:windir\\FabrikamFibre\\DB.", + "loc.input.label.InlineSql": "Inline Sql", + "loc.input.help.InlineSql": "Sql Queries inline", + "loc.input.label.TargetMethod": "Specify SQL Using", + "loc.input.help.TargetMethod": "Specify the option to connect to the target SQL Server Database. The options are either to provide the SQL Server Database details, or the SQL Server connection string, or the Publish profile XML file.", + "loc.input.label.DatabaseName": "Database Name", + "loc.input.help.DatabaseName": "Provide the name of the SQL Server database.", + "loc.input.label.AuthScheme": "Authentication", + "loc.input.help.AuthScheme": "Select the authentication mode for connecting to the SQL Server. In Windows authentication mode, the administrator's account, as specified in the Machines section, is used to connect to the SQL Server. In SQL Server Authentication mode, the SQL login and Password have to be provided in the parameters below.", + "loc.input.label.SqlUsername": "SQL User name", + "loc.input.help.SqlUsername": "Provide the SQL login to connect to the SQL Server. The option is only available if SQL Server Authentication mode has been selected.", + "loc.input.label.SqlPassword": "SQL Password", + "loc.input.help.SqlPassword": "Provide the Password of the SQL login. The option is only available if SQL Server Authentication mode has been selected.", + "loc.input.label.ConnectionString": "Connection String", + "loc.input.help.ConnectionString": "Specify the SQL Server connection string like \"Server=localhost;Database=Fabrikam;User ID=sqluser;Password=password;\".", + "loc.input.label.PublishProfile": "Publish Profile", + "loc.input.help.PublishProfile": "Publish profile provide fine-grained control over SQL Server database deployments. Specify the path to the Publish profile XML file on the target machine or on a UNC share that is accessible by the machine administrator's credentials.", + "loc.input.label.AdditionalArguments": "Additional Arguments", + "loc.input.help.AdditionalArguments": "Additional SqlPackage.exe arguments that will be applied when deploying the SQL Server database like, /p:IgnoreAnsiNulls=True /p:IgnoreComments=True. These arguments will override the settings in the Publish profile XML file (if provided).", + "loc.input.label.AdditionalArgumentsSql": "Additional Arguments", + "loc.input.help.AdditionalArgumentsSql": "Additional Invoke-Sqlcmd arguments that will be applied when deploying the SQL Server database.", + "loc.messages.SQLPowershellModuleisnotinstalledonyouragentmachine": "SQL Powershell Module is not installed on your agent machine. Please follow steps given below to execute this task", + "loc.messages.InstallPowershellToolsharedManagementObjectsdependency": "1. Install PowershellTools & SharedManagementObjects(dependency), from https://www.microsoft.com/en-us/download/details.aspx?id=52676 (2016)", + "loc.messages.RestartagentmachineafterinstallingtoolstoregisterModulepathupdates": "2. Restart agent machine after installing tools to register Module path updates", + "loc.messages.RunImportModuleSQLPSonyouragentPowershellprompt": "3. Run Import-Module SQLPS on your agent Powershell prompt. (This step is not required on Powershell 3.0 enabled machines)" +} \ No newline at end of file diff --git a/Tasks/SqlServerDacpacDeployment/icon.png b/Tasks/SqlDacpacDeploymentOnMachineGroup/icon.png similarity index 100% rename from Tasks/SqlServerDacpacDeployment/icon.png rename to Tasks/SqlDacpacDeploymentOnMachineGroup/icon.png diff --git a/Tasks/SqlServerDacpacDeployment/icon.svg b/Tasks/SqlDacpacDeploymentOnMachineGroup/icon.svg similarity index 98% rename from Tasks/SqlServerDacpacDeployment/icon.svg rename to Tasks/SqlDacpacDeploymentOnMachineGroup/icon.svg index 5efd4d7dc676..104ae1bfd8e2 100644 --- a/Tasks/SqlServerDacpacDeployment/icon.svg +++ b/Tasks/SqlDacpacDeploymentOnMachineGroup/icon.svg @@ -13,7 +13,7 @@ version="1.1" inkscape:version="0.91 r13725" sodipodi:docname="icon.svg" - inkscape:export-filename="C:\Users\Jamie\Sources\vsts-tasks\Tasks\SqlServerDacpacDeployment\icon.png" + inkscape:export-filename="icon.png" inkscape:export-xdpi="2.8099999" inkscape:export-ydpi="2.8099999"> Beispiel: \"dbserver.fabrikam.com,dbserver_int.fabrikam.com:5986,192.168.12.34:5986\"
Sie können auch die Ausgabevariable anderer Tasks angeben. Beispiel: \"$(variableName)\".", - "loc.input.label.AdminUserName": "Administratoranmeldung", - "loc.input.help.AdminUserName": "Die Administratoranmeldung für die Zielcomputer.", - "loc.input.label.AdminPassword": "Kennwort", - "loc.input.help.AdminPassword": "Das Administratorkennwort für die Zielcomputer.
Es kann die Variable annehmen, die in Build-/Releasedefinitionen als\"$(passwordVariable)\" definiert wird.
Sie können den Variablentyp als \"secret\" markieren, um die Variable zu sichern. ", - "loc.input.label.Protocol": "Protokoll", - "loc.input.help.Protocol": "Wählen Sie das Protokoll aus, das für die WinRM-Verbindung mit dem Computer bzw. den Computern verwendet werden soll. Der Standardwert ist HTTPS.", - "loc.input.label.TestCertificate": "Testzertifikat", - "loc.input.help.TestCertificate": "Wählen Sie die Option aus, um die Überprüfung der Authentizität des Zertifikats des Computers durch eine vertrauenswürdige Zertifizierungsstelle zu überspringen. Der Parameter ist für das WinRM HTTPS-Protokoll erforderlich.", - "loc.input.label.DacpacFile": "DACPAC-Datei", - "loc.input.help.DacpacFile": "Der Speicherort der DACPAC-Datei auf den Zielcomputern oder in einem UNC-Pfad im folgenden Format: \"\\\\\\\\BudgetIT\\Web\\Deploy\\FabrikamDB.dacpac\". Auf den UNC-Pfad sollte über das Administratorkonto des Computers zugegriffen werden können. Umgebungsvariablen werden ebenfalls unterstützt, z. B. \"$env:windir\", \"$env:systemroot\", \"like\", \"$env:windir\\FabrikamFibre\\Web\".", - "loc.input.label.TargetMethod": "SQL angeben mit", - "loc.input.help.TargetMethod": "Wählen Sie die Option zum Herstellen einer Verbindung mit der SQL Server-Zieldatenbank aus. Sie können optional Details zur SQL Server-Datenbank, eine SQL Server-Verbindungszeichenfolge oder eine XML-Veröffentlichungsprofildatei bereitstellen.", - "loc.input.label.ServerName": "Servername", - "loc.input.help.ServerName": "Geben Sie den SQL Server-Namen an, z. B. \"computername\\FabrikamSQL,1433\", \"localhost\" oder \".\\SQL2012R2\". Wenn Sie \"localhost\" angeben, wird eine Verbindung mit der SQL Server-Standardinstanz auf dem Computer hergestellt.", - "loc.input.label.DatabaseName": "Datenbankname", - "loc.input.help.DatabaseName": "Geben Sie den Namen der SQL Server-Datenbank an.", - "loc.input.label.SqlUsername": "SQL-Benutzername", - "loc.input.help.SqlUsername": "Wenn die SQL Server-Anmeldung angegeben wird, wird diese zum Herstellen einer Verbindung mit SQL Server verwendet. Standardmäßig werden integrierte Authentifizierung und die Anmeldeinformationen des Administrators des Computers verwendet.", - "loc.input.label.SqlPassword": "SQL-Kennwort", - "loc.input.help.SqlPassword": "Wenn der SQL Server-Anmeldebenutzername angegeben wird, geben Sie das SQL Server-Kennwort an. Standardmäßig werden integrierte Authentifizierung und die Anmeldeinformationen des Administrators des Computers verwendet.", - "loc.input.label.ConnectionString": "Verbindungszeichenfolge", - "loc.input.help.ConnectionString": "Geben Sie die SQL Server-Verbindungszeichenfolge (Beispiel: \"Server=localhost;Database=Fabrikam;User ID=sqluser;Password=password;\") an.", - "loc.input.label.PublishProfile": "Veröffentlichungsprofil", - "loc.input.help.PublishProfile": "Ein Veröffentlichungsprofil stellt eine detaillierte Steuerung der Erstellung oder eines Upgrades der SQL Server-Datenbank zur Verfügung. Geben Sie den Pfad zur XML-Veröffentlichungsprofildatei auf dem Zielcomputer oder einer UNC-Freigabe an, auf die mit den Anmeldeinformationen des Administrators des Computers zugegriffen werden kann.", - "loc.input.label.AdditionalArguments": "Zusätzliche Argumente", - "loc.input.help.AdditionalArguments": "Zusätzliche SqlPackage.exe-Argumente, die beim Erstellen oder Aktualisieren der SQL Server-Datenbank angewendet werden, z. B. \"/p:IgnoreAnsiNulls=True /p:IgnoreComments=True\". Diese Argumente setzen die Einstellungen in der Veröffentlichungsprofil-XML-Datei außer Kraft (wenn angegeben).", - "loc.input.label.DeployInParallel": "Parallel bereitstellen", - "loc.input.help.DeployInParallel": "Wenn diese Option auf \"true\" festgelegt wird, wird der Datenbankbereitstellungstask parallel auf den Zielcomputern ausgeführt.", - "loc.input.label.ResourceFilteringMethod": "Computer auswählen nach", - "loc.input.help.ResourceFilteringMethod": "Wählen Sie optional eine Teilmenge der Computer durch Angeben von Computernamen oder Tags aus.", - "loc.input.label.MachineFilter": "Auf Computern bereitstellen", - "loc.input.help.MachineFilter": "Diese Eingabe ist nur gültig für Computergruppen und wird noch nicht für flache Listen von Computern oder Ausgabevariablen unterstützt. Geben Sie eine Liste von Computern (z. B. \"dbserver.fabrikam.com\", \"webserver.fabrikam.com\", \"192.168.12.34\") oder Tags (z. B. \"Role:DB\", \"OS:Win8.1\") an. Wenn mehrere Tags angegeben werden, wird der Task auf allen Computern mit den angegebenen Tags ausgeführt. Geben Sie für Azure-Ressourcengruppen den Namen der virtuellen Maschine an, z. B. \"ffweb\" oder \"ffdb\". Standardmäßig wird der Task auf allen Computern ausgeführt." -} \ No newline at end of file diff --git a/Tasks/SqlServerDacpacDeployment/Strings/resources.resjson/en-US/resources.resjson b/Tasks/SqlServerDacpacDeployment/Strings/resources.resjson/en-US/resources.resjson deleted file mode 100644 index d75f299a6f57..000000000000 --- a/Tasks/SqlServerDacpacDeployment/Strings/resources.resjson/en-US/resources.resjson +++ /dev/null @@ -1,43 +0,0 @@ -{ - "loc.friendlyName": "[Deprecated] SQL Server Database Deploy", - "loc.helpMarkDown": "[More Information](https://aka.ms/sqlserverdacpackreadme)", - "loc.description": "Deploy SQL Server Database using DACPAC", - "loc.instanceNameFormat": "[Deprecated] Deploy SQL DACPAC: $(DacpacFile)", - "loc.group.displayName.deployment": "Deployment", - "loc.group.displayName.target": "Target", - "loc.group.displayName.advanced": "Advanced", - "loc.input.label.EnvironmentName": "Machines", - "loc.input.help.EnvironmentName": "Provide a comma separated list of machine IP addresses or FQDNs along with ports. Port is defaulted based on the selected protocol.
Eg: dbserver.fabrikam.com,dbserver_int.fabrikam.com:5986,192.168.12.34:5986
Or provide output variable of other tasks. Eg: $(variableName)", - "loc.input.label.AdminUserName": "Admin Login", - "loc.input.help.AdminUserName": "Administrator login for the target machines.", - "loc.input.label.AdminPassword": "Password", - "loc.input.help.AdminPassword": "Administrator password for the target machines.
It can accept variable defined in Build/Release definitions as '$(passwordVariable)'.
You may mark variable type as 'secret' to secure it. ", - "loc.input.label.Protocol": "Protocol", - "loc.input.help.Protocol": "Select the protocol to use for the WinRM connection with the machine(s). Default is HTTPS.", - "loc.input.label.TestCertificate": "Test Certificate", - "loc.input.help.TestCertificate": "Select the option to skip validating the authenticity of the machine's certificate by a trusted certification authority. The parameter is required for the WinRM HTTPS protocol.", - "loc.input.label.DacpacFile": "DACPAC File", - "loc.input.help.DacpacFile": "Location of the DACPAC file on the target machines or on a UNC path like, \\\\\\\\BudgetIT\\Web\\Deploy\\FabrikamDB.dacpac. The UNC path should be accessible to the machine's administrator account. Environment variables are also supported like $env:windir, $env:systemroot, like, $env:windir\\FabrikamFibre\\Web.", - "loc.input.label.TargetMethod": "Specify SQL Using", - "loc.input.help.TargetMethod": "Select the option to connect to the target SQL Server Database. The options are to provide SQL Server Database details, or a SQL Server connection string, or a Publish profile XML file.", - "loc.input.label.ServerName": "Server Name", - "loc.input.help.ServerName": "Provide the SQL Server name like, machinename\\FabriakmSQL,1433 or localhost or .\\SQL2012R2. Specifying localhost will connect to the Default SQL Server instance on the machine.", - "loc.input.label.DatabaseName": "Database Name", - "loc.input.help.DatabaseName": "Provide the name of the SQL Server database.", - "loc.input.label.SqlUsername": "SQL Username", - "loc.input.help.SqlUsername": "If the SQL Server login is specified, it will be used to connect to the SQL Server. The default is Integrated Authentication and uses the machine administrator's credentials.", - "loc.input.label.SqlPassword": "SQL Password", - "loc.input.help.SqlPassword": "If SQL Server login user name is specified, then provide the SQL Server password. The default is Integrated Authentication and uses the machine administrator's credentials.", - "loc.input.label.ConnectionString": "Connection String", - "loc.input.help.ConnectionString": "Specify the SQL Server connection string like \"Server=localhost;Database=Fabrikam;User ID=sqluser;Password=password;\".", - "loc.input.label.PublishProfile": "Publish Profile", - "loc.input.help.PublishProfile": "Publish profile provide fine-grained control over SQL Server database creation or upgrades. Specify the path to the Publish profile XML file on the target machine or on a UNC share that is accessible by the machine administrator's credentials.", - "loc.input.label.AdditionalArguments": "Additional Arguments", - "loc.input.help.AdditionalArguments": "Additional SqlPackage.exe arguments that will be applied when creating or updating the SQL Server database like, /p:IgnoreAnsiNulls=True /p:IgnoreComments=True. These arguments will override the settings in the Publish profile XML file (if provided).", - "loc.input.label.DeployInParallel": "Deploy in Parallel", - "loc.input.help.DeployInParallel": "Setting it to true will run the database deployment task in-parallel on the target machines.", - "loc.input.label.ResourceFilteringMethod": "Select Machines By", - "loc.input.help.ResourceFilteringMethod": "Optionally, select a subset of machines either by providing machine names or tags.", - "loc.input.label.MachineFilter": "Deploy to Machines", - "loc.input.help.MachineFilter": "This input is valid only for machine groups and is not supported for flat list of machines or output variables yet. Provide a list of machines like, dbserver.fabrikam.com, webserver.fabrikam.com, 192.168.12.34, or tags like, Role:DB; OS:Win8.1. If multiple tags are provided, then the task will run in all the machines with the specified tags. For Azure Resource Groups, provide the virtual machine's name like, ffweb, ffdb. The default is to run the task in all machines." -} \ No newline at end of file diff --git a/Tasks/SqlServerDacpacDeployment/Strings/resources.resjson/es-es/resources.resjson b/Tasks/SqlServerDacpacDeployment/Strings/resources.resjson/es-es/resources.resjson deleted file mode 100644 index 89799b7a016b..000000000000 --- a/Tasks/SqlServerDacpacDeployment/Strings/resources.resjson/es-es/resources.resjson +++ /dev/null @@ -1,43 +0,0 @@ -{ - "loc.friendlyName": "[En desuso] Implementación de la base de datos de SQL Server", - "loc.helpMarkDown": "[More Information](https://aka.ms/sqlserverdacpackreadme)", - "loc.description": "Implementar la base de datos de SQL Server con DACPAC", - "loc.instanceNameFormat": "[En desuso] Implementar el archivo DACPAC de SQL: $(DacpacFile)", - "loc.group.displayName.deployment": "Implementación", - "loc.group.displayName.target": "Destino", - "loc.group.displayName.advanced": "Avanzado", - "loc.input.label.EnvironmentName": "Equipos", - "loc.input.help.EnvironmentName": "Proporcione una lista separada por comas de direcciones IP de equipos o nombres de dominio completos junto con puertos. El puerto se establece de manera predeterminada en función del protocolo seleccionado.
Ejemplo: dbserver.fabrikam.com,dbserver_int.fabrikam.com:5986,192.168.12.34:5986
O bien proporcione la variable de salida de otras tareas. Ejemplo: $(nombreDeVariable)", - "loc.input.label.AdminUserName": "Inicio de sesión del administrador", - "loc.input.help.AdminUserName": "Inicio de sesión del administrador para los equipos de destino.", - "loc.input.label.AdminPassword": "Contraseña", - "loc.input.help.AdminPassword": "Contraseña del administrador para las máquinas de destino.
Admite la variable declarada en las definiciones de compilación o versión como \"$(passwordVariable)\".
Para proteger la variable, puede marcar el tipo como \"secret\". ", - "loc.input.label.Protocol": "Protocolo", - "loc.input.help.Protocol": "Seleccione el protocolo que se usará para la conexión WinRM con los equipos. El valor predeterminado es HTTPS.", - "loc.input.label.TestCertificate": "Certificado de prueba", - "loc.input.help.TestCertificate": "Seleccione la opción para omitir la validación de la autenticidad del certificado del equipo por parte de una entidad de certificación de confianza. El parámetro es obligatorio para el protocolo HTTPS de WinRM.", - "loc.input.label.DacpacFile": "Archivo DACPAC", - "loc.input.help.DacpacFile": "Ubicación del archivo DACPAC en las máquinas de destino o en una ruta de acceso UNC, como \\\\\\\\BudgetIT\\Web\\Deploy\\FabrikamDB.dacpac. La ruta de acceso UNC debe ser accesible para la cuenta del administrador de la máquina. También se admiten variables de entorno, como $env:windir, $env:systemroot, like, $env:windir\\FabrikamFibre\\Web.", - "loc.input.label.TargetMethod": "Especificar el SQL con", - "loc.input.help.TargetMethod": "Seleccione la opción para conectarse a la base de datos de destino de SQL Server. Las opciones son: proporcionar detalles de la base de datos de SQL Server, una cadena de conexión de SQL Server o un archivo XML del perfil de publicación.", - "loc.input.label.ServerName": "Nombre del servidor", - "loc.input.help.ServerName": "Proporcione el nombre de la base de datos de SQL Server, como machinename\\FabriakmSQL,1433, localhost o .\\SQL2012R2. Al especificar localhost, se conectará a la instancia predeterminada de SQL Server en la máquina.", - "loc.input.label.DatabaseName": "Nombre de la base de datos", - "loc.input.help.DatabaseName": "Proporcione el nombre de la base de datos de SQL Server.", - "loc.input.label.SqlUsername": "Nombre de usuario de SQL", - "loc.input.help.SqlUsername": "Si se especifica el inicio de sesión de SQL Server, se usará este para conectarse a SQL Server. El valor predeterminado es Autenticación integrada y usa las credenciales del administrador de la máquina.", - "loc.input.label.SqlPassword": "Contraseña de SQL", - "loc.input.help.SqlPassword": "Si se especifica el nombre de usuario de inicio de sesión de SQL Server, indique la contraseña de SQL Server. El valor predeterminado es Autenticación integrada y usa las credenciales del administrador de la máquina.", - "loc.input.label.ConnectionString": "Cadena de conexión", - "loc.input.help.ConnectionString": "Especifique la cadena de conexión de SQL Server, como \"Server=localhost;Database=Fabrikam;User ID=sqluser;Password=password;\".", - "loc.input.label.PublishProfile": "Perfil de publicación", - "loc.input.help.PublishProfile": "El perfil de publicación proporciona control específico sobre la creación o las actualizaciones de la base de datos de SQL Server. Especifique la ruta de acceso al archivo XML del perfil de publicación en el equipo de destino o en un recurso compartido UNC que sea accesible con las credenciales del administrador del equipo.", - "loc.input.label.AdditionalArguments": "Argumentos adicionales", - "loc.input.help.AdditionalArguments": "Argumentos adicionales de SqlPackage.exe que se aplicarán al crear o actualizar la base de datos de SQL Server, como /p:IgnoreAnsiNulls=True /p:IgnoreComments=True. Estos argumentos reemplazarán la configuración del archivo XML del perfil de publicación (si se proporciona).", - "loc.input.label.DeployInParallel": "Implementar en paralelo", - "loc.input.help.DeployInParallel": "Si se establece en true, la tarea de implementación de la base de datos se ejecutará en paralelo en las máquinas de destino.", - "loc.input.label.ResourceFilteringMethod": "Seleccionar máquinas por", - "loc.input.help.ResourceFilteringMethod": "También puede seleccionar un subconjunto de máquinas especificando nombres de máquina o etiquetas.", - "loc.input.label.MachineFilter": "Implementar en máquinas", - "loc.input.help.MachineFilter": "Esta entrada solo es válida para los grupos de máquinas y no se admite para una lista plana de máquinas o de variables de salida. Proporcione una lista de máquinas (como dbserver.fabrikam.com, webserver.fabrikam.com o 192.168.12.34) o etiquetas (como Role:DB; OS:Win8.1). Si se proporcionan varias etiquetas, la tarea se ejecutará en todas las máquinas que tengan las etiquetas especificadas. Para los grupos de recursos de Azure, proporcione el nombre de la máquina virtual, como ffweb o ffdb. La opción predeterminada es ejecutar la tarea en todas las máquinas." -} \ No newline at end of file diff --git a/Tasks/SqlServerDacpacDeployment/Strings/resources.resjson/fr-fr/resources.resjson b/Tasks/SqlServerDacpacDeployment/Strings/resources.resjson/fr-fr/resources.resjson deleted file mode 100644 index 0b92fe4bd11c..000000000000 --- a/Tasks/SqlServerDacpacDeployment/Strings/resources.resjson/fr-fr/resources.resjson +++ /dev/null @@ -1,43 +0,0 @@ -{ - "loc.friendlyName": "[Déconseillé] Déploiement de base de données SQL Server", - "loc.helpMarkDown": "[More Information](https://aka.ms/sqlserverdacpackreadme)", - "loc.description": "Déployer la base de données SQL Server avec DACPAC", - "loc.instanceNameFormat": "[Déconseillé] Déployer SQL DACPAC : $(DacpacFile)", - "loc.group.displayName.deployment": "Déploiement", - "loc.group.displayName.target": "Cible", - "loc.group.displayName.advanced": "Avancé", - "loc.input.label.EnvironmentName": "Ordinateurs", - "loc.input.help.EnvironmentName": "Indiquez une liste d'adresses IP ou de noms de domaine complets de machines avec les ports séparés par une virgule. Le port par défaut dépend du protocole sélectionné.
Exemple : dbserver.fabrikam.com,dbserver_int.fabrikam.com:5986,192.168.12.34:5986
Ou indiquez une variable de sortie d'autres tâches. Exemple : $(variableName)", - "loc.input.label.AdminUserName": "Informations de connexion d'administrateur", - "loc.input.help.AdminUserName": "Informations de connexion d'administrateur pour les ordinateurs cibles.", - "loc.input.label.AdminPassword": "Mot de passe", - "loc.input.help.AdminPassword": "Mot de passe d'administrateur pour les machines cibles.
Il peut accepter une variable définie dans les définitions Build/Release sous la forme '$(passwordVariable)'.
Vous pouvez marquer le type de variable en tant que 'secret' pour renforcer sa sécurité. ", - "loc.input.label.Protocol": "Protocole", - "loc.input.help.Protocol": "Sélectionnez le protocole à utiliser pour la connexion WinRM avec les machines. La valeur par défaut est HTTPS.", - "loc.input.label.TestCertificate": "Certificat de test", - "loc.input.help.TestCertificate": "Sélectionnez l'option pour ignorer l'étape de validation de l'authenticité du certificat de l'ordinateur par une autorité de certification approuvée. Le paramètre est requis pour le protocole HTTPS WinRM.", - "loc.input.label.DacpacFile": "Fichier DACPAC", - "loc.input.help.DacpacFile": "Emplacement du fichier DACPAC sur les machines cibles ou dans un chemin d'accès UNC, tel que \\\\\\\\BudgetIT\\Web\\Deploy\\FabrikamDB.dacpac. Ce chemin d'accès UNC doit être accessible au compte Administrateur de la machine. Vous pouvez également utiliser des variables d'environnement, telles que $env:windir, $env:systemroot, like, $env:windir\\FabrikamFibre\\Web.", - "loc.input.label.TargetMethod": "Spécifier l'utilisation de SQL", - "loc.input.help.TargetMethod": "Sélectionnez l'option permettant de se connecter à la base de données SQL Server cible. Spécifiez les détails de la base de données SQL Server, une chaîne de connexion SQL Server ou un fichier XML de profil de publication.", - "loc.input.label.ServerName": "Nom du serveur", - "loc.input.help.ServerName": "Spécifiez le nom du serveur SQL Server, tel que machinename\\FabriakmSQL,1433 ou localhost ou .\\SQL2012R2. Utilisez localhost pour une connexion à l'instance SQL Server par défaut sur la machine.", - "loc.input.label.DatabaseName": "Nom de la base de données", - "loc.input.help.DatabaseName": "Spécifiez le nom de la base de données SQL Server.", - "loc.input.label.SqlUsername": "Nom d'utilisateur SQL", - "loc.input.help.SqlUsername": "Si les informations de connexion SQL Server sont spécifiées, elles sont utilisées pour la connexion à SQL Server. Par défaut, l'authentification intégrée est utilisée, avec les informations d'identification de l'administrateur de la machine.", - "loc.input.label.SqlPassword": "Mot de passe SQL", - "loc.input.help.SqlPassword": "Si le nom d'utilisateur de connexion SQL Server est spécifié, spécifiez le mot de passe SQL Server. Par défaut, l'authentification intégrée est utilisée, avec les informations d'identification de l'administrateur de la machine.", - "loc.input.label.ConnectionString": "Chaîne de connexion", - "loc.input.help.ConnectionString": "Spécifiez la chaîne de connexion SQL Server, telle que \"Server=localhost;Database=Fabrikam;User ID=sqluser;Password=password;\".", - "loc.input.label.PublishProfile": "Profil de publication", - "loc.input.help.PublishProfile": "Le profil de publication permet de contrôler précisément les opérations de création ou de mise à niveau de la base de données SQL Server. Spécifiez le chemin d'accès au fichier XML du profil de publication sur la machine cible ou sur un partage UNC accessible au compte Administrateur de la machine.", - "loc.input.label.AdditionalArguments": "Arguments supplémentaires", - "loc.input.help.AdditionalArguments": "Arguments SqlPackage.exe supplémentaires qui seront appliqués à la création ou la mise à jour de la base de données SQL Server, tels que /p:IgnoreAnsiNulls=True /p:IgnoreComments=True. Ces arguments remplaceront les paramètres définis dans le fichier XML du profil de publication (le cas échéant).​", - "loc.input.label.DeployInParallel": "Déployer en parallèle", - "loc.input.help.DeployInParallel": "Si la valeur est true, la tâche de déploiement de la base de données est exécutée en parallèle sur les machines cibles.", - "loc.input.label.ResourceFilteringMethod": "Sélectionner les machines par", - "loc.input.help.ResourceFilteringMethod": "Vous pouvez également sélectionner un sous-ensemble de machines en spécifiant les noms des machines ou les balises associées.", - "loc.input.label.MachineFilter": "Déployer sur les ordinateurs", - "loc.input.help.MachineFilter": "Cette entrée est valide uniquement pour les groupes de machines. Elle n'est pas encore prise en charge pour une liste plate de machines ou de variables de sortie. Indiquez une liste de machines, par exemple dbserver.fabrikam.com, webserver.fabrikam.com, 192.168.12.34, ou utilisez des balises telles que Role:DB; OS:Win8.1. Si plusieurs balises sont indiquées, la tâche s'exécute sur toutes les machines correspondant aux balises spécifiées. Pour les groupes de ressources Azure, indiquez le nom de la machine virtuelle, par exemple ffweb, ffdb. Par défaut, la tâche s'exécute sur toutes les machines." -} \ No newline at end of file diff --git a/Tasks/SqlServerDacpacDeployment/Strings/resources.resjson/it-IT/resources.resjson b/Tasks/SqlServerDacpacDeployment/Strings/resources.resjson/it-IT/resources.resjson deleted file mode 100644 index f31755af70e0..000000000000 --- a/Tasks/SqlServerDacpacDeployment/Strings/resources.resjson/it-IT/resources.resjson +++ /dev/null @@ -1,43 +0,0 @@ -{ - "loc.friendlyName": "[Deprecata] Distribuzione database SQL Server", - "loc.helpMarkDown": "[More Information](https://aka.ms/sqlserverdacpackreadme)", - "loc.description": "Consente di distribuire il database SQL Server con DACPAC", - "loc.instanceNameFormat": "[Deprecata] Distribuisci DACPAC SQL: $(DacpacFile)", - "loc.group.displayName.deployment": "Distribuzione", - "loc.group.displayName.target": "Destinazione", - "loc.group.displayName.advanced": "Avanzate", - "loc.input.label.EnvironmentName": "Computer", - "loc.input.help.EnvironmentName": "Consente di specificare un elenco di indirizzi IP o FQDN separati da virgola unitamente alle porte. Per impostazione predefinita, la porta è basata sul protocollo selezionato.
Esempio: dbserver.fabrikam.com,dbserver_int.fabrikam.com:5986,192.168.12.34:5986
In alternativa, consente di specificare la variabile di output di altre attività. Esempio: $(variableName)", - "loc.input.label.AdminUserName": "Account di accesso amministratore", - "loc.input.help.AdminUserName": "Account di accesso dell'amministratore per i computer di destinazione.", - "loc.input.label.AdminPassword": "Password", - "loc.input.help.AdminPassword": "Password dell'amministratore per i computer di destinazione.
Accetta la variabile definita nelle definizioni di compilazione/versione come '$(passwordVariable)'.
Per proteggerla, è possibile contrassegnare il tipo di variabile come 'secret'. ", - "loc.input.label.Protocol": "Protocollo", - "loc.input.help.Protocol": "Consente di selezionare il protocollo da usare per la connessione WinRM con i computer. Il valore predefinito è HTTPS.", - "loc.input.label.TestCertificate": "Certificato di test", - "loc.input.help.TestCertificate": "Consente di selezionare l'opzione per ignorare la convalida dell'autenticità del certificato del computer da parte di un'Autorità di certificazione attendibile. Il parametro è obbligatorio per il protocollo HTTPS di WinRM.", - "loc.input.label.DacpacFile": "File DACPAC", - "loc.input.help.DacpacFile": "Percorso del file DACPAC nei computer di destinazione o in un percorso UNC, ad esempio \\\\\\\\BudgetIT\\Web\\Deploy\\FabrikamDB.dacpac. Il percorso UNC deve essere accessibile all'account Administrator del computer. Sono supportate anche variabili di ambiente come $env:windir, $env:systemroot, $env:windir\\FabrikamFibre\\Web.", - "loc.input.label.TargetMethod": "Specifica SQL tramite", - "loc.input.help.TargetMethod": "Selezionare l'opzione per la connessione al database SQL Server di destinazione. Le opzioni disponibili consentono di specificare i dettagli relativi al database SQL Server, una stringa di connessione a SQL Server oppure un file XML del profilo di pubblicazione.", - "loc.input.label.ServerName": "Nome server", - "loc.input.help.ServerName": "Consente di specificare il nome dell'istanza di SQL Server, ad esempio nomecomputer\\FabrikamSQL,1433, localhost oppure .\\SQL2012R2. Se si specifica localhost, verrà effettuata la connessione all'istanza predefinita di SQL Server nel computer.", - "loc.input.label.DatabaseName": "Nome database", - "loc.input.help.DatabaseName": "Specificare il nome del database SQL Server.", - "loc.input.label.SqlUsername": "Nome utente SQL", - "loc.input.help.SqlUsername": "Se si specifica l'account di accesso di SQL Server, questo verrà usato per la connessione a SQL Server. Con l'impostazione predefinita, ovvero l'autenticazione integrata, vengono usate le credenziali dell'amministratore del computer.", - "loc.input.label.SqlPassword": "Password SQL", - "loc.input.help.SqlPassword": "Se si specifica il nome utente di accesso di SQL Server, fornire la password di SQL Server. Con l'impostazione predefinita, ovvero l'autenticazione integrata, vengono usate le credenziali dell'amministratore del computer.", - "loc.input.label.ConnectionString": "Stringa di connessione", - "loc.input.help.ConnectionString": "Consente di specificare la stringa di connessione di SQL Server, ad esempio \"Server=localhost;Database=Fabrikam;User ID=sqluser;Password=password;\".", - "loc.input.label.PublishProfile": "Profilo di pubblicazione", - "loc.input.help.PublishProfile": "Il profilo di pubblicazione consente di disporre di un controllo più specifico sulla creazione o sugli aggiornamenti del database SQL Server. Specificare il percorso del file XML del profilo di pubblicazione nel computer di destinazione oppure in una condivisione UNC accessibile con le credenziali dell'amministratore del computer.", - "loc.input.label.AdditionalArguments": "Argomenti aggiuntivi", - "loc.input.help.AdditionalArguments": "Argomenti aggiuntivi di SqlPackage.exe che verranno applicati durante la creazione o l'aggiornamento del database SQL Server, ad esempio /p:IgnoreAnsiNulls=True /p:IgnoreComments=True. Questi argomenti sostituiranno le impostazioni nel file XML del profilo di pubblicazione (se specificato).", - "loc.input.label.DeployInParallel": "Distribuisci in parallelo", - "loc.input.help.DeployInParallel": "Se è impostato su true, l'attività di distribuzione del database verrà eseguita in parallelo nei computer di destinazione.", - "loc.input.label.ResourceFilteringMethod": "Seleziona computer per", - "loc.input.help.ResourceFilteringMethod": "Selezionare, facoltativamente, un sottoinsieme di computer specificando nomi o tag dei computer.", - "loc.input.label.MachineFilter": "Distribuisci in computer", - "loc.input.help.MachineFilter": "Questo input è valido solo per gruppi di computer e non è ancora supportato per elenchi semplici di computer o variabili di output. Consente di specificare un elenco di computer come dbserver.fabrikam.com, webserver.fabrikam.com, 192.168.12.34 o tag come Role:DB; OS:Win8.1. Se vengono specificati più tag, l'attività verrà eseguita in tutti i computer con i tag specificati. Per Gruppo di risorse di Azure specificare il nome della macchina virtuale, ad esempio ffweb o ffdb. Per impostazione predefinita, l'attività viene eseguita in tutti i computer." -} \ No newline at end of file diff --git a/Tasks/SqlServerDacpacDeployment/Strings/resources.resjson/ja-jp/resources.resjson b/Tasks/SqlServerDacpacDeployment/Strings/resources.resjson/ja-jp/resources.resjson deleted file mode 100644 index 8bcf6274f13b..000000000000 --- a/Tasks/SqlServerDacpacDeployment/Strings/resources.resjson/ja-jp/resources.resjson +++ /dev/null @@ -1,43 +0,0 @@ -{ - "loc.friendlyName": "[非推奨] SQL Server データベースの配置", - "loc.helpMarkDown": "[More Information](https://aka.ms/sqlserverdacpackreadme)", - "loc.description": "DACPAC を使用して SQL Server Database を配置します", - "loc.instanceNameFormat": "[非推奨] SQL DACPAC の配置: $(DacpacFile)", - "loc.group.displayName.deployment": "配置", - "loc.group.displayName.target": "ターゲット ", - "loc.group.displayName.advanced": "詳細設定 ", - "loc.input.label.EnvironmentName": "コンピューター", - "loc.input.help.EnvironmentName": "コンピューターの IP アドレスまたは FQDN とポートのコンマ区切り一覧を指定します。ポートは選んだプロトコルに基づいて既定値に設定されます。
例: dbserver.fabrikam.com,dbserver_int.fabrikam.com:5986,192.168.12.34:5986
または他のタスクの出力変数を指定します。例: $(variableName)", - "loc.input.label.AdminUserName": "管理者ログイン", - "loc.input.help.AdminUserName": "ターゲット コンピューターの管理者ログイン。", - "loc.input.label.AdminPassword": "パスワード", - "loc.input.help.AdminPassword": "対象のコンピューターの管理者パスワード。
ビルド/リリース定義で '$(passwordVariable)' として定義された変数を受け入れることができます。
変数タイプを 'シークレット' とマークして保護することもできます。", - "loc.input.label.Protocol": "プロトコル", - "loc.input.help.Protocol": "コンピューターとの WinRM 接続に使用するプロトコルを選びます。既定は HTTPS です。", - "loc.input.label.TestCertificate": "証明書のテスト", - "loc.input.help.TestCertificate": "信頼された証明機関によるコンピューターの証明書の信頼性の検証をスキップするにはこのオプションを選びます。WinRM HTTPS プロトコルにはこのパラメーターが必要です。", - "loc.input.label.DacpacFile": "DACPAC ファイル", - "loc.input.help.DacpacFile": "対象のコンピューターまたは UNC パス上の DACPAC ファイルの場所 (\\\\\\\\BudgetIT\\Web\\Deploy\\FabrikamDB.dacpac など)。この UNC パスはコンピューターの管理者アカウントでアクセスできる必要があります。また、環境変数 ($env:windir、$env:systemroot、$env:windir\\FabrikamFibre\\Web など) もサポートされます。", - "loc.input.label.TargetMethod": "次を使用して、SQL を指定します", - "loc.input.help.TargetMethod": "対象の SQL Server Database に接続するオプションを選択します。このオプションを選ぶと SQL Server Database の詳細か SQL Server 接続文字列、または発行プロファイル XML ファイルが提供されます。", - "loc.input.label.ServerName": "サーバー名 ", - "loc.input.help.ServerName": "SQL Server 名 (machinename\\FabriakmSQL,1433、localhost、\\SQL2012R2 など) を指定します。localhost を 指定すると、コンピューター上の既定の SQL サーバー インスタンスに接続されます。", - "loc.input.label.DatabaseName": "データベース名 ", - "loc.input.help.DatabaseName": "SQL Server データベースの名前を指定します。", - "loc.input.label.SqlUsername": "SQL ユーザー名", - "loc.input.help.SqlUsername": "SQL Server ログインが指定されると、SQL Server への接続に使用されます。既定では統合認証が用いられ、コンピューターの管理者の資格情報が使用されます。", - "loc.input.label.SqlPassword": "SQL パスワード ", - "loc.input.help.SqlPassword": "SQL Server ログイン ユーザー名が指定されると、SQL Server パスワードが求められます。既定では統合認証が用いられ、コンピューターの管理者の資格情報が使用されます。", - "loc.input.label.ConnectionString": "接続文字列 ", - "loc.input.help.ConnectionString": "SQL Server 接続文字列 (\"Server=localhost;Database=Fabrikam;User ID=sqluser;Password=password;\" など) を指定します。", - "loc.input.label.PublishProfile": "発行プロファイル", - "loc.input.help.PublishProfile": "発行プロファイルを使用すると、SQL Server データベースの作成またはアップグレードを詳細に制御できるようになります。コンピューターの管理者資格情報でアクセスできるターゲット コンピューターまたは UNC 共有上で、発行プロファイル XML ファイルへのパスを指定します。", - "loc.input.label.AdditionalArguments": "追加引数 ", - "loc.input.help.AdditionalArguments": "SQL Server database の作成中または更新中に適用される SqlPackage.exe 追加引数 (/p:IgnoreAnsiNulls=True /p:IgnoreComments=True など)。これらの引数は発行プロファイル XML ファイルの設定を上書きします (提供される場合)。", - "loc.input.label.DeployInParallel": "並列で展開", - "loc.input.help.DeployInParallel": "「true」に設定すると、ターゲット コンピューター上でデータベース配置を並列で実行します。", - "loc.input.label.ResourceFilteringMethod": "以下の条件でコンピューターを選択", - "loc.input.help.ResourceFilteringMethod": "必要に応じて、コンピューター名またはタグを指定してコンピューターのサブセットを選びます。", - "loc.input.label.MachineFilter": "コンピューターに展開", - "loc.input.help.MachineFilter": "この入力はコンピューター グループでのみ使用でき、コンピューターまたは出力変数の単純なリストではまだサポートされていません。コンピューターのリスト (dbserver.fabrikam.com, webserver.fabrikam.com, 192.168.12.34 など)、またはタグのリスト (Role:DB; OS:Win8.1) をご指定ください。複数のタグを指定した場合、指定されたタグを持つすべてのコンピューターでタスクが実行されます。Azure リソース グループの場合は、ffweb または ffdb のような仮想マシン名をご指定ください。既定値ではタスクがすべてのコンピューターで実行されます。" -} \ No newline at end of file diff --git a/Tasks/SqlServerDacpacDeployment/Strings/resources.resjson/ko-KR/resources.resjson b/Tasks/SqlServerDacpacDeployment/Strings/resources.resjson/ko-KR/resources.resjson deleted file mode 100644 index 1bb4744c63e6..000000000000 --- a/Tasks/SqlServerDacpacDeployment/Strings/resources.resjson/ko-KR/resources.resjson +++ /dev/null @@ -1,43 +0,0 @@ -{ - "loc.friendlyName": "[사용되지 않음] SQL Server 데이터베이스 배포", - "loc.helpMarkDown": "[More Information](https://aka.ms/sqlserverdacpackreadme)", - "loc.description": "DACPAC를 사용하여 SQL Server 데이터베이스 배포", - "loc.instanceNameFormat": "[사용되지 않음] SQL DACPAC 배포: $(DacpacFile)", - "loc.group.displayName.deployment": "배포", - "loc.group.displayName.target": "대상", - "loc.group.displayName.advanced": "고급", - "loc.input.label.EnvironmentName": "컴퓨터", - "loc.input.help.EnvironmentName": "포트와 함께 쉼표로 구분된 컴퓨터 IP 주소 또는 FQDN 목록을 제공하세요. 포트의 기본값이 선택된 프로토콜을 기준으로 설정되었습니다.
예: dbserver.fabrikam.com,dbserver_int.fabrikam.com:5986,192.168.12.34:5986
또는 다른 작업의 출력 변수를 제공하세요. 예: $(variableName)", - "loc.input.label.AdminUserName": "관리자 로그인", - "loc.input.help.AdminUserName": "대상 컴퓨터에 대한 관리자 로그인입니다.", - "loc.input.label.AdminPassword": "암호", - "loc.input.help.AdminPassword": "대상 컴퓨터에 대한 관리자 암호입니다.
빌드/릴리스 정의에 '$(passwordVariable)'(으)로 정의된 변수를 사용할 수 있습니다.
보호하기 위해 변수 형식을 'secret'으로 표시할 수 있습니다.", - "loc.input.label.Protocol": "프로토콜", - "loc.input.help.Protocol": "컴퓨터와의 WinRM 연결에 사용할 프로토콜을 선택하세요. 기본값은 HTTPS입니다.", - "loc.input.label.TestCertificate": "테스트 인증서", - "loc.input.help.TestCertificate": "신뢰할 수 있는 인증 기관의 컴퓨터 인증서 신뢰성 확인을 건너뛰려면 이 옵션을 선택하세요. WinRM HTTPS 프로토콜에는 매개 변수가 필요합니다.", - "loc.input.label.DacpacFile": "DACPAC 파일", - "loc.input.help.DacpacFile": "대상 컴퓨터 또는 UNC 경로의 DACPAC 파일 위치입니다(예: \\\\\\\\BudgetIT\\Web\\Deploy\\FabrikamDB.dacpac). UNC 경로는 컴퓨터의 관리자 계정이 액세스할 수 있어야 합니다. 환경 변수(예: $env:windir, $env:systemroot, $env:windir\\FabrikamFibre\\Web)도 지원됩니다.", - "loc.input.label.TargetMethod": "SQL 지정 방법", - "loc.input.help.TargetMethod": "대상 SQL Server 데이터베이스에 연결하는 옵션을 선택합니다. 옵션은 SQL Server 데이터베이스 정보, SQL Server 연결 문자열 또는 게시 프로필 XML 파일을 제공하는 것입니다.", - "loc.input.label.ServerName": "서버 이름", - "loc.input.help.ServerName": "SQL Server 이름(예: machinename\\FabriakmSQL,1433 또는 localhost 또는 .\\SQL2012R2)을 제공합니다. localhost를 지정하면 컴퓨터의 기본 SQL Server 인스턴스에 연결됩니다.", - "loc.input.label.DatabaseName": "데이터베이스 이름", - "loc.input.help.DatabaseName": "SQL Server 데이터베이스의 이름을 제공합니다.", - "loc.input.label.SqlUsername": "SQL 사용자 이름", - "loc.input.help.SqlUsername": "SQL Server 로그인이 지정된 경우 SQL Server에 연결하는 데 사용됩니다. 기본값은 통합 인증이며 컴퓨터 관리자의 자격 증명을 사용합니다.", - "loc.input.label.SqlPassword": "SQL 암호", - "loc.input.help.SqlPassword": "SQL Server 로그인 사용자 이름이 지정된 경우 SQL Server 암호를 제공합니다. 기본값은 통합 인증이며 컴퓨터 관리자의 자격 증명을 사용합니다.", - "loc.input.label.ConnectionString": "연결 문자열", - "loc.input.help.ConnectionString": "SQL Server 연결 문자열(예: \"Server=localhost;Database=Fabrikam;User ID=sqluser;Password=password;\")을 지정합니다.", - "loc.input.label.PublishProfile": "게시 프로필", - "loc.input.help.PublishProfile": "게시 프로필은 SQL Server 데이터베이스 생성 또는 업그레이드에 대한 세분화된 제어를 제공합니다. 대상 컴퓨터 또는 컴퓨터 관리자의 자격 증명으로 액세스할 수 있는 UNC 공유의 게시 프로필 XML 파일에 대한 경로를 지정하세요.", - "loc.input.label.AdditionalArguments": "추가 인수", - "loc.input.help.AdditionalArguments": "SQL Server 데이터베이스를 만들거나 업데이트할 때 적용될 추가 SqlPackage.exe 인수입니다(예: /p:IgnoreAnsiNulls=True /p:IgnoreComments=True). 이러한 인수는 게시 프로필 XML 파일(제공된 경우)의 설정을 재정의합니다.", - "loc.input.label.DeployInParallel": "동시 배포", - "loc.input.help.DeployInParallel": "true로 설정하면 대상 컴퓨터에서 데이터베이스 배포 작업이 동시에 실행됩니다.", - "loc.input.label.ResourceFilteringMethod": "컴퓨터 선택 기준", - "loc.input.help.ResourceFilteringMethod": "필요한 경우 컴퓨터 이름 또는 태그를 제공하여 컴퓨터의 하위 집합을 선택합니다.", - "loc.input.label.MachineFilter": "컴퓨터에 배포", - "loc.input.help.MachineFilter": "이 입력은 컴퓨터 그룹에만 유효하며 컴퓨터 또는 변수의 단순 목록에는 아직 지원되지 않습니다. dbserver.fabrikam.com, webserver.fabrikam.com, 192.168.12.34 등과 같은 컴퓨터나 Role:DB; OS:Win8.1 등과 같은 태그 목록을 지정하세요 여러 태그를 지정하는 경우 지정된 태그가 포함된 모든 컴퓨터에서 작업이 실행됩니다. Azure 리소스 그룹의 경우 ffweb, ffdb 등과 같은 가상 컴퓨터 이름을 지정하세요. 기본값은 모든 컴퓨터에서 실행하는 것입니다." -} \ No newline at end of file diff --git a/Tasks/SqlServerDacpacDeployment/Strings/resources.resjson/ru-RU/resources.resjson b/Tasks/SqlServerDacpacDeployment/Strings/resources.resjson/ru-RU/resources.resjson deleted file mode 100644 index 2c7a1844ec96..000000000000 --- a/Tasks/SqlServerDacpacDeployment/Strings/resources.resjson/ru-RU/resources.resjson +++ /dev/null @@ -1,43 +0,0 @@ -{ - "loc.friendlyName": "[Не рекомендуется] Развертывание базы данных SQL Server", - "loc.helpMarkDown": "[More Information](https://aka.ms/sqlserverdacpackreadme)", - "loc.description": "Развертывание базы данных SQL Server с помощью DACPAC", - "loc.instanceNameFormat": "[Не рекомендуется] Развертывание DACPAC-файла SQL: $(DacpacFile)", - "loc.group.displayName.deployment": "Развертывание", - "loc.group.displayName.target": "Целевой объект", - "loc.group.displayName.advanced": "Дополнительно", - "loc.input.label.EnvironmentName": "Компьютеры", - "loc.input.help.EnvironmentName": "Укажите разделенный запятыми список IP-адресов компьютеров или полных доменных имен вместе с портами. Порт по умолчанию выбирается исходя из используемого протокола.
Например: dbserver.fabrikam.com,dbserver_int.fabrikam.com:5986,192.168.12.34:5986
Или укажите выходную переменную из других задач. Например: $(variableName)", - "loc.input.label.AdminUserName": "Имя для входа администратора", - "loc.input.help.AdminUserName": "Имя для входа администратора для целевых компьютеров.", - "loc.input.label.AdminPassword": "Пароль", - "loc.input.help.AdminPassword": "Пароль администратора для целевых компьютеров.
Он может принять переменную, заданную в определениях сборки или выпуска в качестве \"$(passwordVariable)\".
Вы можете отметить тип переменной как \"secret\", чтобы защитить ее. ", - "loc.input.label.Protocol": "Протокол", - "loc.input.help.Protocol": "Выберите протокол, используемый в WinRM-подключениях к компьютерам. Значение по умолчанию — HTTPS.", - "loc.input.label.TestCertificate": "Тестовый сертификат", - "loc.input.help.TestCertificate": "Выберите этот параметр, чтобы пропустить проверку достоверности сертификата компьютера доверенным центром сертификации. Параметр обязателен для протокола WinRM HTTPS.", - "loc.input.label.DacpacFile": "DACPAC-файл", - "loc.input.help.DacpacFile": "Расположение DACPAC-файла на целевых машинах или по UNC-пути, например \\\\\\\\BudgetIT\\Web\\Deploy\\FabrikamDB.dacpac. UNC-путь должен быть доступен для учетной записи администратора машины. Также можно использовать переменные среды, например $env:windir\\FabrikamFibre\\Web.", - "loc.input.label.TargetMethod": "Указать SQL с помощью", - "loc.input.help.TargetMethod": "Выберите вариант подключения к целевой базе данных SQL Server. Доступные варианты: указать сведения о базе данных SQL Server, строку подключения SQL Server или файл профиля публикации.", - "loc.input.label.ServerName": "Имя сервера", - "loc.input.help.ServerName": "Укажите имя SQL Server, например machinename\\FabriakmSQL,1433 или localhost или .\\SQL2012R2. Если указать localhost, то будет выполнено подключение к экземпляру SQL Server по умолчанию на машине.", - "loc.input.label.DatabaseName": "Имя базы данных", - "loc.input.help.DatabaseName": "Укажите имя базы данных SQL Server.", - "loc.input.label.SqlUsername": "Имя пользователя SQL", - "loc.input.help.SqlUsername": "Если указано имя для входа SQL Server, то оно будет использоваться для подключения к SQL Server. Значение по умолчанию — встроенная проверка подлинности с использованием учетных данных администратора машины.", - "loc.input.label.SqlPassword": "Пароль SQL", - "loc.input.help.SqlPassword": "Если указано имя для входа пользователя SQL Server, укажите пароль SQL Server. Значение по умолчанию — встроенная проверка подлинности с использованием учетных данных администратора компьютера.", - "loc.input.label.ConnectionString": "Строка подключения", - "loc.input.help.ConnectionString": "Укажите строку подключения SQL Server, например \"Server=localhost;Database=Fabrikam;User ID=sqluser;Password=password;\".", - "loc.input.label.PublishProfile": "Профиль публикации", - "loc.input.help.PublishProfile": "Профиль публикации обеспечивает точное управление созданием и обновлением базы данных SQL Server. Укажите путь к XML-файлу профиля публикации на целевом компьютере или в общем ресурсе UNC, доступный с помощью учетных данных администратора компьютера.", - "loc.input.label.AdditionalArguments": "Дополнительные аргументы", - "loc.input.help.AdditionalArguments": "Дополнительные аргументы SqlPackage.exe, которые будут применены при создании или обновлении базы данных SQL Server, например /p:IgnoreAnsiNulls=True /p:IgnoreComments=True. Эти аргументы имеют приоритет над параметрами в XML-файле профиля публикации (если он указан).", - "loc.input.label.DeployInParallel": "Параллельное развертывание", - "loc.input.help.DeployInParallel": "Если задано значение \"True\", будут одновременно запущены задачи развертывания баз данных на целевых машинах.", - "loc.input.label.ResourceFilteringMethod": "Выбор компьютеров по", - "loc.input.help.ResourceFilteringMethod": "Как вариант, выберите подмножество компьютеров, указав их имена или теги.", - "loc.input.label.MachineFilter": "Развертывание на компьютерах", - "loc.input.help.MachineFilter": "Входные данные допустимы только для групп компьютеров и пока не поддерживаются для плоского списка компьютеров или выходных переменных. Укажите список компьютеров, например, dbserver.fabrikam.com, webserver.fabrikam.com, 192.168.12.34 или теги, такие как Role:DB; OS:Win8.1. Если указано несколько тегов, задача будет выполняться на всех компьютерах с указанными тегами. Для групп ресурсов Azure укажите имя виртуальной машины (например, ffweb, ffdb). Поведение по умолчанию — запуск задачи на всех компьютерах." -} \ No newline at end of file diff --git a/Tasks/SqlServerDacpacDeployment/Strings/resources.resjson/zh-CN/resources.resjson b/Tasks/SqlServerDacpacDeployment/Strings/resources.resjson/zh-CN/resources.resjson deleted file mode 100644 index ef56f6c8613b..000000000000 --- a/Tasks/SqlServerDacpacDeployment/Strings/resources.resjson/zh-CN/resources.resjson +++ /dev/null @@ -1,43 +0,0 @@ -{ - "loc.friendlyName": "[已弃用] SQL Server 数据库部署", - "loc.helpMarkDown": "[More Information](https://aka.ms/sqlserverdacpackreadme)", - "loc.description": "使用 DACPAC 部署 SQL Server 数据库", - "loc.instanceNameFormat": "[已弃用]部署 SQL DACPAC: $(DacpacFile)", - "loc.group.displayName.deployment": "部署", - "loc.group.displayName.target": "目标", - "loc.group.displayName.advanced": "高级", - "loc.input.label.EnvironmentName": "计算机", - "loc.input.help.EnvironmentName": "提供以逗号分隔的计算机 IP 地址或 FQDN 以及端口列表。端口默认基于选定的协议。
例如: dbserver.fabrikam.com,dbserver_int.fabrikam.com:5986,192.168.12.34:5986
或者提供其他任务的输出变量。例如: $(variableName)", - "loc.input.label.AdminUserName": "管理员登录名", - "loc.input.help.AdminUserName": "目标计算机的管理员登录名。", - "loc.input.label.AdminPassword": "密码", - "loc.input.help.AdminPassword": "目标计算机的管理员密码。
可接受“生成/发布”定义中定义为 \"$(passwordVariable)\" 的变量。
你可将变量类型标记为“机密”来进行保护。", - "loc.input.label.Protocol": "协议", - "loc.input.help.Protocol": "选择与计算机进行 WinRM 连接时使用的协议。默认为 HTTPS.", - "loc.input.label.TestCertificate": "测试证书", - "loc.input.help.TestCertificate": "选择跳过验证计算机的证书是否真正由受信任的证书颁发机构签署的选项。WinRM HTTPS 协议需要该参数。", - "loc.input.label.DacpacFile": "DACPAC 文件", - "loc.input.help.DacpacFile": "目标计算机上或 UNC 路径上 DACPAC 文件的位置,如 \\\\\\\\BudgetIT\\Web\\Deploy\\FabrikamDB.dacpac。计算机的管理员帐户应可访问 UNC 路径。还支持环境变量,如 $env:windir、$env:systemroot 和 $env:windir\\FabrikamFibre\\Web。", - "loc.input.label.TargetMethod": "使用以下方法指定 SQL:", - "loc.input.help.TargetMethod": "选择该选项可连接到目标 SQL Server 数据库。相关选项用于提供 SQL Server 数据库详细信息、SQL Server 连接字符串或发布配置文件 XML 文件。", - "loc.input.label.ServerName": "服务器名", - "loc.input.help.ServerName": "提供 SQL Server 名称,如 machinename\\FabriakmSQL,1433、localhost 或 .\\SQL2012R2。指定 localhost 将会连接到计算机上的默认 SQL Server 实例。", - "loc.input.label.DatabaseName": "数据库名", - "loc.input.help.DatabaseName": "提供 SQL Server 数据库的名称。", - "loc.input.label.SqlUsername": "SQL 用户名", - "loc.input.help.SqlUsername": "如果指定了 SQL Server 登录名,则该登录名将用于连接到 SQL Server。默认为集成身份验证,并使用计算机管理员的凭据。", - "loc.input.label.SqlPassword": "SQL 密码", - "loc.input.help.SqlPassword": "如果指定了 SQL Server 登录用户名,则请提供 SQL Server 密码。默认为集成身份验证,并使用计算机管理员的凭据。", - "loc.input.label.ConnectionString": "连接字符串", - "loc.input.help.ConnectionString": "指定 SQL Server 连接字符串,如 \"Server=localhost;Database=Fabrikam;User ID=sqluser;Password=password;\"。", - "loc.input.label.PublishProfile": "发布配置文件", - "loc.input.help.PublishProfile": "发布配置文件提供对 SQL Server 数据库创建或升级的细化控制。指定目标计算机上或可通过计算机管理员的凭据访问的 UNC 共享上的发布配置文件 XML 文件的路径。", - "loc.input.label.AdditionalArguments": "其他参数", - "loc.input.help.AdditionalArguments": "创建或更新 SQL Server 数据库时将应用的其他 SqlPackage.exe 参数,如 /p:IgnoreAnsiNulls=True /p:IgnoreComments=True。这些参数将替代发布配置文件 XML 文件(如果提供)中的设置。", - "loc.input.label.DeployInParallel": "并行部署", - "loc.input.help.DeployInParallel": "将其设置为 true 会在目标计算机上并行运行数据库部署任务。", - "loc.input.label.ResourceFilteringMethod": "计算机选择依据", - "loc.input.help.ResourceFilteringMethod": "(可选)通过提供计算机名或标记来选择计算机的子集。", - "loc.input.label.MachineFilter": "部署到计算机", - "loc.input.help.MachineFilter": "此输入仅对计算机组有效,且尚不支持计算机或输出变量的简单列表。提供计算机列表(如 dbserver.fabrikam.com, webserver.fabrikam.com, 192.168.12.34)或标记列表(如 Role:DB; OS:Win8.1)。如果提供了多个标记,则任务将在具有指定标记的所有计算机中运行。对于 Azure 资源组,提供虚拟机的名称,如 ffweb、ffdb。默认为在所有计算机中运行任务。" -} \ No newline at end of file diff --git a/Tasks/SqlServerDacpacDeployment/Strings/resources.resjson/zh-TW/resources.resjson b/Tasks/SqlServerDacpacDeployment/Strings/resources.resjson/zh-TW/resources.resjson deleted file mode 100644 index 77d59bd646e9..000000000000 --- a/Tasks/SqlServerDacpacDeployment/Strings/resources.resjson/zh-TW/resources.resjson +++ /dev/null @@ -1,43 +0,0 @@ -{ - "loc.friendlyName": "[已取代] SQL Server Database 部署", - "loc.helpMarkDown": "[More Information](https://aka.ms/sqlserverdacpackreadme)", - "loc.description": "使用 DACPAC 部署 SQL Server 資料庫", - "loc.instanceNameFormat": "[已取代] 部署 SQL DACPAC: $(DacpacFile)", - "loc.group.displayName.deployment": "部署", - "loc.group.displayName.target": "目標", - "loc.group.displayName.advanced": "進階", - "loc.input.label.EnvironmentName": "電腦", - "loc.input.help.EnvironmentName": "提供以逗號分隔,包含電腦 IP 位址或 FQDN 與連接埠的清單。連接埠的預設值隨所選的通訊協定而定。
例如: dbserver.fabrikam.com,dbserver_int.fabrikam.com:5986,192.168.12.34:5986
或提供其他作業的輸出變數。例如: $(variableName)", - "loc.input.label.AdminUserName": "系統管理員登入", - "loc.input.help.AdminUserName": "目標電腦的系統管理員登入。", - "loc.input.label.AdminPassword": "密碼", - "loc.input.help.AdminPassword": "目標電腦的系統管理員密碼。
其可接受組建/發行定義中 '$(passwordVariable)' 這類形式的變數。
您可以將變數類型標示為 'secret' 加以保護。", - "loc.input.label.Protocol": "通訊協定", - "loc.input.help.Protocol": "選取 WinRM 與電腦連線時所囡使用的通訊協定。預設值為 HTTPS。", - "loc.input.label.TestCertificate": "測試憑證", - "loc.input.help.TestCertificate": "選取此選項可略過驗證電腦憑證是否確實經由信任的憑證授權單位簽署。WinRM HTTPS 通訊協定需要此參數。", - "loc.input.label.DacpacFile": "DACPAC 檔案", - "loc.input.help.DacpacFile": "目標電腦或 UNC 路徑上的 DACPAC 檔案位置,例如 \\\\\\\\BudgetIT\\Web\\Deploy\\FabrikamDB.dacpac。電腦的系統管理員帳戶必須可以存取 UNC 路徑,並同時支援環境變數,例如 $env:windir、$env:systemroot、$env:windir\\FabrikamFibre\\Web。", - "loc.input.label.TargetMethod": "使用下列項目指定 SQL:", - "loc.input.help.TargetMethod": "選取此選項可連接至目標 SQL Server Database。此選項會提供 SQL Server Database 詳細資料,或 SQL Server 連接字串,或發行設定檔 XML 檔。", - "loc.input.label.ServerName": "伺服器名稱", - "loc.input.help.ServerName": "提供 SQL Server 名稱,例如: 電腦名稱\\FabriakmSQL,1433 或 localhost 或 .\\SQL2012R2。若指定 localhost,則會連接至電腦上的預設 SQL Server 執行個體。", - "loc.input.label.DatabaseName": "資料庫名稱", - "loc.input.help.DatabaseName": "提供 SQL Server 資料庫的名稱。", - "loc.input.label.SqlUsername": "SQL 使用者名稱", - "loc.input.help.SqlUsername": "如果指定了 SQL Server 登入,其將用以連接至 SQL Server。預設為整合式驗證,並使用電腦系統管理員的認證。", - "loc.input.label.SqlPassword": "SQL 密碼", - "loc.input.help.SqlPassword": "如果指定了 SQL Server 登入使用者名稱,則請提供 SQL Server 密碼。預設為整合式驗證,並使用電腦系統管理員的認證。", - "loc.input.label.ConnectionString": "連接字串", - "loc.input.help.ConnectionString": "指定 SQL Server 連接字串,例如 \"Server=localhost;Database=Fabrikam;User ID=sqluser;Password=password;\"。", - "loc.input.label.PublishProfile": "發行設定檔", - "loc.input.help.PublishProfile": "發行設定檔可讓您更進一步控制 SQL Server 資料庫的建立或更新。請指定目標電腦或電腦系統管理員認證所能存取之通用命名慣例 (UNC) 共用上發行設定檔 XML 檔案的路徑。", - "loc.input.label.AdditionalArguments": "其他引數", - "loc.input.help.AdditionalArguments": "其他會在建立或更新 SQL Server 資料庫時套用的 SqlPackage.exe 引數,例如 /p:IgnoreAnsiNulls=True /p:IgnoreComments=True。這些引數會覆寫發行設定檔 XML 檔 (若有提供) 中的設定。", - "loc.input.label.DeployInParallel": "平行部署", - "loc.input.help.DeployInParallel": "設定為 true 即會以平行方式在目標電腦上執行資料庫部署工作。", - "loc.input.label.ResourceFilteringMethod": "選取電腦依據 ", - "loc.input.help.ResourceFilteringMethod": "選擇性地提供電腦名稱或標記來選取電腦的子集。", - "loc.input.label.MachineFilter": "部署至電腦", - "loc.input.help.MachineFilter": "此輸入只對電腦群組有效,電腦的簡單列表或輸出變數目前尚無法支援。請以 dbserver.fabrikam.com、webserver.fabrikam.com、192.168.12.34 等形式提供電腦清單,或以 Role:DB; OS:Win8.1 等提供標記清單。若提供多個標記,工作會在所有具有指定標記的電腦上執行。若為 Azure 資源群組,請提供虛擬機器的名稱 (例如 ffweb、ffdb)。預設會在所有電腦上執行此工作。" -} \ No newline at end of file diff --git a/Tasks/SqlServerDacpacDeployment/task.json b/Tasks/SqlServerDacpacDeployment/task.json deleted file mode 100644 index 439eac8b383c..000000000000 --- a/Tasks/SqlServerDacpacDeployment/task.json +++ /dev/null @@ -1,215 +0,0 @@ -{ - "id": "70A3A82D-4A3C-4A09-8D30-A793739DC94F", - "name": "SqlServerDacpacDeployment", - "friendlyName": "[Deprecated] SQL Server Database Deploy", - "description": "Deploy SQL Server Database using DACPAC", - "helpMarkDown": "[More Information](https://aka.ms/sqlserverdacpackreadme)", - "category": "Deploy", - "visibility": [ - "Preview", - "Build", - "Release" - ], - "author": "Microsoft Corporation", - "version": { - "Major": 1, - "Minor": 0, - "Patch": 16 - }, - "demands": [], - "minimumAgentVersion": "1.96.2", - "groups": [ - { - "name": "deployment", - "displayName": "Deployment", - "isExpanded": true - }, - { - "name": "target", - "displayName": "Target", - "isExpanded": true - }, - { - "name": "advanced", - "displayName": "Advanced", - "isExpanded": false - } - ], - "inputs": [ - { - "name": "EnvironmentName", - "type": "multiLine", - "label": "Machines", - "defaultValue": "", - "required": true, - "helpMarkDown": "Provide a comma separated list of machine IP addresses or FQDNs along with ports. Port is defaulted based on the selected protocol.
Eg: dbserver.fabrikam.com,dbserver_int.fabrikam.com:5986,192.168.12.34:5986
Or provide output variable of other tasks. Eg: $(variableName)" - }, - { - "name": "AdminUserName", - "type": "string", - "label": "Admin Login", - "defaultValue": "", - "required": false, - "helpMarkDown": "Administrator login for the target machines." - }, - { - "name": "AdminPassword", - "type": "string", - "label": "Password", - "defaultValue": "", - "required": false, - "helpMarkDown": "Administrator password for the target machines.
It can accept variable defined in Build/Release definitions as '$(passwordVariable)'.
You may mark variable type as 'secret' to secure it. " - }, - { - "name": "Protocol", - "type": "radio", - "label": "Protocol", - "required": false, - "defaultValue": "", - "options": { - "Http": "HTTP", - "Https": "HTTPS" - }, - "helpMarkDown": "Select the protocol to use for the WinRM connection with the machine(s). Default is HTTPS." - }, - { - "name": "TestCertificate", - "type": "boolean", - "label": "Test Certificate", - "defaultValue": "true", - "visibleRule": "Protocol = Https", - "required": false, - "helpMarkDown": "Select the option to skip validating the authenticity of the machine's certificate by a trusted certification authority. The parameter is required for the WinRM HTTPS protocol." - }, - { - "name": "DacpacFile", - "type": "filePath", - "label": "DACPAC File", - "required": true, - "groupName": "deployment", - "defaultValue": "", - "helpMarkDown": "Location of the DACPAC file on the target machines or on a UNC path like, \\\\\\\\BudgetIT\\Web\\Deploy\\FabrikamDB.dacpac. The UNC path should be accessible to the machine's administrator account. Environment variables are also supported like $env:windir, $env:systemroot, like, $env:windir\\FabrikamFibre\\Web." - }, - { - "name": "TargetMethod", - "type": "pickList", - "label": "Specify SQL Using", - "required": true, - "groupName": "target", - "defaultValue": "server", - "options": { - "server": "Server", - "connectionString": "Connection String", - "publishProfile": "Publish Profile" - }, - "helpMarkDown": "Select the option to connect to the target SQL Server Database. The options are to provide SQL Server Database details, or a SQL Server connection string, or a Publish profile XML file." - }, - { - "name": "ServerName", - "type": "string", - "label": "Server Name", - "required": true, - "groupName": "target", - "defaultValue": "localhost", - "visibleRule": "TargetMethod = server", - "helpMarkDown": "Provide the SQL Server name like, machinename\\FabriakmSQL,1433 or localhost or .\\SQL2012R2. Specifying localhost will connect to the Default SQL Server instance on the machine." - }, - { - "name": "DatabaseName", - "type": "string", - "label": "Database Name", - "required": true, - "groupName": "target", - "defaultValue": "", - "visibleRule": "TargetMethod = server", - "helpMarkDown": "Provide the name of the SQL Server database." - }, - { - "name": "SqlUsername", - "type": "string", - "label": "SQL Username", - "required": false, - "groupName": "target", - "defaultValue": "", - "visibleRule": "TargetMethod = server", - "helpMarkDown": "If the SQL Server login is specified, it will be used to connect to the SQL Server. The default is Integrated Authentication and uses the machine administrator's credentials." - }, - { - "name": "SqlPassword", - "type": "string", - "label": "SQL Password", - "required": false, - "groupName": "target", - "defaultValue": "", - "visibleRule": "TargetMethod = server", - "helpMarkDown": "If SQL Server login user name is specified, then provide the SQL Server password. The default is Integrated Authentication and uses the machine administrator's credentials." - }, - { - "name": "ConnectionString", - "type": "multiLine", - "label": "Connection String", - "required": true, - "groupName": "target", - "defaultValue": "", - "visibleRule": "TargetMethod = connectionString", - "helpMarkDown": "Specify the SQL Server connection string like \"Server=localhost;Database=Fabrikam;User ID=sqluser;Password=password;\"." - }, - { - "name": "PublishProfile", - "type": "filePath", - "label": "Publish Profile", - "required": false, - "groupName": "target", - "defaultValue": "", - "helpMarkDown": "Publish profile provide fine-grained control over SQL Server database creation or upgrades. Specify the path to the Publish profile XML file on the target machine or on a UNC share that is accessible by the machine administrator's credentials." - }, - { - "name": "AdditionalArguments", - "type": "multiLine", - "label": "Additional Arguments", - "required": false, - "groupName": "target", - "defaultValue": "", - "helpMarkDown": "Additional SqlPackage.exe arguments that will be applied when creating or updating the SQL Server database like, /p:IgnoreAnsiNulls=True /p:IgnoreComments=True. These arguments will override the settings in the Publish profile XML file (if provided)." - }, - { - "name": "DeployInParallel", - "type": "boolean", - "label": "Deploy in Parallel", - "defaultValue": "true", - "required": false, - "groupName": "advanced", - "helpMarkDown": "Setting it to true will run the database deployment task in-parallel on the target machines." - }, - { - "name": "ResourceFilteringMethod", - "type": "radio", - "label": "Select Machines By", - "required": false, - "defaultValue": "machineNames", - "options": { - "machineNames": "Machine Names", - "tags": "Tags" - }, - "groupName": "advanced", - "helpMarkDown": "Optionally, select a subset of machines either by providing machine names or tags." - }, - { - "name": "MachineFilter", - "type": "string", - "label": "Deploy to Machines", - "required": false, - "defaultValue": "", - "groupName": "advanced", - "helpMarkDown": "This input is valid only for machine groups and is not supported for flat list of machines or output variables yet. Provide a list of machines like, dbserver.fabrikam.com, webserver.fabrikam.com, 192.168.12.34, or tags like, Role:DB; OS:Win8.1. If multiple tags are provided, then the task will run in all the machines with the specified tags. For Azure Resource Groups, provide the virtual machine's name like, ffweb, ffdb. The default is to run the task in all machines." - } - ], - "instanceNameFormat": "[Deprecated] Deploy SQL DACPAC: $(DacpacFile)", - "execution": { - "PowerShell": { - "target": "$(currentDirectory)\\DeployToSqlServer.ps1", - "argumentFormat": "", - "workingDirectory": "$(currentDirectory)" - } - } -} \ No newline at end of file diff --git a/Tasks/SqlServerDacpacDeployment/task.loc.json b/Tasks/SqlServerDacpacDeployment/task.loc.json deleted file mode 100644 index 2a2bc5577b34..000000000000 --- a/Tasks/SqlServerDacpacDeployment/task.loc.json +++ /dev/null @@ -1,215 +0,0 @@ -{ - "id": "70A3A82D-4A3C-4A09-8D30-A793739DC94F", - "name": "SqlServerDacpacDeployment", - "friendlyName": "ms-resource:loc.friendlyName", - "description": "ms-resource:loc.description", - "helpMarkDown": "ms-resource:loc.helpMarkDown", - "category": "Deploy", - "visibility": [ - "Preview", - "Build", - "Release" - ], - "author": "Microsoft Corporation", - "version": { - "Major": 1, - "Minor": 0, - "Patch": 16 - }, - "demands": [], - "minimumAgentVersion": "1.96.2", - "groups": [ - { - "name": "deployment", - "displayName": "ms-resource:loc.group.displayName.deployment", - "isExpanded": true - }, - { - "name": "target", - "displayName": "ms-resource:loc.group.displayName.target", - "isExpanded": true - }, - { - "name": "advanced", - "displayName": "ms-resource:loc.group.displayName.advanced", - "isExpanded": false - } - ], - "inputs": [ - { - "name": "EnvironmentName", - "type": "multiLine", - "label": "ms-resource:loc.input.label.EnvironmentName", - "defaultValue": "", - "required": true, - "helpMarkDown": "ms-resource:loc.input.help.EnvironmentName" - }, - { - "name": "AdminUserName", - "type": "string", - "label": "ms-resource:loc.input.label.AdminUserName", - "defaultValue": "", - "required": false, - "helpMarkDown": "ms-resource:loc.input.help.AdminUserName" - }, - { - "name": "AdminPassword", - "type": "string", - "label": "ms-resource:loc.input.label.AdminPassword", - "defaultValue": "", - "required": false, - "helpMarkDown": "ms-resource:loc.input.help.AdminPassword" - }, - { - "name": "Protocol", - "type": "radio", - "label": "ms-resource:loc.input.label.Protocol", - "required": false, - "defaultValue": "", - "options": { - "Http": "HTTP", - "Https": "HTTPS" - }, - "helpMarkDown": "ms-resource:loc.input.help.Protocol" - }, - { - "name": "TestCertificate", - "type": "boolean", - "label": "ms-resource:loc.input.label.TestCertificate", - "defaultValue": "true", - "visibleRule": "Protocol = Https", - "required": false, - "helpMarkDown": "ms-resource:loc.input.help.TestCertificate" - }, - { - "name": "DacpacFile", - "type": "filePath", - "label": "ms-resource:loc.input.label.DacpacFile", - "required": true, - "groupName": "deployment", - "defaultValue": "", - "helpMarkDown": "ms-resource:loc.input.help.DacpacFile" - }, - { - "name": "TargetMethod", - "type": "pickList", - "label": "ms-resource:loc.input.label.TargetMethod", - "required": true, - "groupName": "target", - "defaultValue": "server", - "options": { - "server": "Server", - "connectionString": "Connection String", - "publishProfile": "Publish Profile" - }, - "helpMarkDown": "ms-resource:loc.input.help.TargetMethod" - }, - { - "name": "ServerName", - "type": "string", - "label": "ms-resource:loc.input.label.ServerName", - "required": true, - "groupName": "target", - "defaultValue": "localhost", - "visibleRule": "TargetMethod = server", - "helpMarkDown": "ms-resource:loc.input.help.ServerName" - }, - { - "name": "DatabaseName", - "type": "string", - "label": "ms-resource:loc.input.label.DatabaseName", - "required": true, - "groupName": "target", - "defaultValue": "", - "visibleRule": "TargetMethod = server", - "helpMarkDown": "ms-resource:loc.input.help.DatabaseName" - }, - { - "name": "SqlUsername", - "type": "string", - "label": "ms-resource:loc.input.label.SqlUsername", - "required": false, - "groupName": "target", - "defaultValue": "", - "visibleRule": "TargetMethod = server", - "helpMarkDown": "ms-resource:loc.input.help.SqlUsername" - }, - { - "name": "SqlPassword", - "type": "string", - "label": "ms-resource:loc.input.label.SqlPassword", - "required": false, - "groupName": "target", - "defaultValue": "", - "visibleRule": "TargetMethod = server", - "helpMarkDown": "ms-resource:loc.input.help.SqlPassword" - }, - { - "name": "ConnectionString", - "type": "multiLine", - "label": "ms-resource:loc.input.label.ConnectionString", - "required": true, - "groupName": "target", - "defaultValue": "", - "visibleRule": "TargetMethod = connectionString", - "helpMarkDown": "ms-resource:loc.input.help.ConnectionString" - }, - { - "name": "PublishProfile", - "type": "filePath", - "label": "ms-resource:loc.input.label.PublishProfile", - "required": false, - "groupName": "target", - "defaultValue": "", - "helpMarkDown": "ms-resource:loc.input.help.PublishProfile" - }, - { - "name": "AdditionalArguments", - "type": "multiLine", - "label": "ms-resource:loc.input.label.AdditionalArguments", - "required": false, - "groupName": "target", - "defaultValue": "", - "helpMarkDown": "ms-resource:loc.input.help.AdditionalArguments" - }, - { - "name": "DeployInParallel", - "type": "boolean", - "label": "ms-resource:loc.input.label.DeployInParallel", - "defaultValue": "true", - "required": false, - "groupName": "advanced", - "helpMarkDown": "ms-resource:loc.input.help.DeployInParallel" - }, - { - "name": "ResourceFilteringMethod", - "type": "radio", - "label": "ms-resource:loc.input.label.ResourceFilteringMethod", - "required": false, - "defaultValue": "machineNames", - "options": { - "machineNames": "Machine Names", - "tags": "Tags" - }, - "groupName": "advanced", - "helpMarkDown": "ms-resource:loc.input.help.ResourceFilteringMethod" - }, - { - "name": "MachineFilter", - "type": "string", - "label": "ms-resource:loc.input.label.MachineFilter", - "required": false, - "defaultValue": "", - "groupName": "advanced", - "helpMarkDown": "ms-resource:loc.input.help.MachineFilter" - } - ], - "instanceNameFormat": "ms-resource:loc.instanceNameFormat", - "execution": { - "PowerShell": { - "target": "$(currentDirectory)\\DeployToSqlServer.ps1", - "argumentFormat": "", - "workingDirectory": "$(currentDirectory)" - } - } -} \ No newline at end of file diff --git a/Tasks/VsTest/Strings/resources.resjson/en-US/resources.resjson b/Tasks/VsTest/Strings/resources.resjson/en-US/resources.resjson index 29042cabd269..6951f28e70d3 100644 --- a/Tasks/VsTest/Strings/resources.resjson/en-US/resources.resjson +++ b/Tasks/VsTest/Strings/resources.resjson/en-US/resources.resjson @@ -1,14 +1,16 @@ { "loc.friendlyName": "Visual Studio Test", - "loc.helpMarkDown": "[More Information](https://go.microsoft.com/fwlink/?LinkId=624539)", + "loc.helpMarkDown": "[More Information](https://go.microsoft.com/fwlink/?LinkId=835764)", "loc.description": "Run tests with Visual Studio test runner", - "loc.instanceNameFormat": "Test Assemblies $(testAssembly)", + "loc.instanceNameFormat": "Test Assemblies", "loc.group.displayName.executionOptions": "Execution Options", "loc.group.displayName.tiaOptions": "Test Impact Analysis", "loc.group.displayName.advancedExecutionOptions": "Advanced Execution Options", "loc.group.displayName.reportingOptions": "Reporting Options", - "loc.input.label.testAssembly": "Test Assembly", - "loc.input.help.testAssembly": "Test binaries to run tests on. Wildcards can be used. For example, `**\\*test*.dll;-:**\\obj\\**` for all dlls with test in name while excluding files in any sub-directory named obj.", + "loc.input.label.testAssemblyVer2": "Test Assembly", + "loc.input.help.testAssemblyVer2": "Run tests from the specified files. The file paths are relative to the search folder. Supports multiple lines of minimatch patterns. [More Information](https://go.microsoft.com/fwlink/?LinkId=835764)", + "loc.input.label.searchFolder": "Search Folder", + "loc.input.help.searchFolder": "Folder to search for the test assemblies. Defaults to $(System.DefaultWorkingDirectory).", "loc.input.label.testFiltercriteria": "Test Filter criteria", "loc.input.help.testFiltercriteria": "Additional criteria to filter tests from Test assemblies. For example: `Priority=1|Name=MyTestMethod`", "loc.input.label.runSettingsFile": "Run Settings File", @@ -65,5 +67,6 @@ "loc.messages.ErrorReadingVstestVersion": "Error reading the version of vstest.console.exe.", "loc.messages.UnexpectedVersionString": "Unexpected version string detected for vstest.console.exe: %s.", "loc.messages.UnexpectedVersionNumber": "Unexpected version number detected for vstest.console.exe: %s.", - "loc.messages.VstestDiagNotSupported": "vstest.console.exe version does not support the /diag flag. Enable diagnositics via the exe.config files" + "loc.messages.VstestDiagNotSupported": "vstest.console.exe version does not support the /diag flag. Enable diagnositics via the exe.config files", + "loc.messages.NoIncludePatternFound": "No include pattern found. Specify atleast one include pattern to search test assemblies." } \ No newline at end of file diff --git a/Tasks/VsTest/make.json b/Tasks/VsTest/make.json index 016378d6a93a..7334783b67d5 100644 --- a/Tasks/VsTest/make.json +++ b/Tasks/VsTest/make.json @@ -1,25 +1,10 @@ { - "common": [ - { - "module": "../Common/find-files-legacy", - "type": "node", - "compile": true - } - ], "externals": { "archivePackages": [ { - "url": "https://testselector.blob.core.windows.net/testselector/3391437/TestSelector.zip", + "url": "https://testselector.blob.core.windows.net/testselector/3433874/TestSelector.zip", "dest": "./" } ] - }, - "rm": [ - { - "items": [ - "node_modules/find-files-legacy/node_modules/vsts-task-lib" - ], - "options": "-Rf" - } - ] + } } \ No newline at end of file diff --git a/Tasks/VsTest/package.json b/Tasks/VsTest/package.json index 615400f06ed3..017bf3935c78 100644 --- a/Tasks/VsTest/package.json +++ b/Tasks/VsTest/package.json @@ -1,27 +1,26 @@ { - "name": "vsts-tasks-vstest", - "version": "1.0.0", - "description": "VSTS VSTEST Task", - "main": "VSTest.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/Microsoft/vsts-tasks.git" - }, - "author": "Microsoft Corporation", - "license": "MIT", - "bugs": { - "url": "https://github.com/Microsoft/vsts-tasks/issues" - }, - "homepage": "https://github.com/Microsoft/vsts-tasks#readme", - "dependencies": { - "xml2js": "0.4.16", - "vsts-task-lib": "^0.8.3", - "performance-now": "0.2.0" - }, - "optionalDependencies": { - "regedit": "2.2.6" - } + "name": "vsts-tasks-vstest", + "description": "VSTS VSTEST Task", + "main": "VSTest.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/Microsoft/vsts-tasks.git" + }, + "author": "Microsoft Corporation", + "license": "MIT", + "bugs": { + "url": "https://github.com/Microsoft/vsts-tasks/issues" + }, + "homepage": "https://github.com/Microsoft/vsts-tasks#readme", + "dependencies": { + "performance-now": "0.2.0", + "vsts-task-lib": "^2.0.0-preview", + "xml2js": "0.4.16" + }, + "optionalDependencies": { + "regedit": "2.2.6" + } } \ No newline at end of file diff --git a/Tasks/VsTest/task.json b/Tasks/VsTest/task.json index e54455beaae7..6c9591f184e5 100644 --- a/Tasks/VsTest/task.json +++ b/Tasks/VsTest/task.json @@ -3,21 +3,27 @@ "name": "VSTest", "friendlyName": "Visual Studio Test", "description": "Run tests with Visual Studio test runner", - "helpMarkDown": "[More Information](https://go.microsoft.com/fwlink/?LinkId=624539)", + "helpMarkDown": "[More Information](https://go.microsoft.com/fwlink/?LinkId=835764)", "category": "Test", "visibility": [ "Build", "Release" + ], + "runsOn": [ + "Agent", + "MachineGroup" ], "author": "Microsoft Corporation", "version": { - "Major": 1, + "Major": 2, "Minor": 0, - "Patch": 80 + "Patch": 0 }, "demands": [ "vstest" ], + "preview": "true", + "releaseNotes" : "Test Impact and support for minimatch patterns.", "minimumAgentVersion": "1.89.0", "groups": [ { @@ -46,12 +52,25 @@ ], "inputs": [ { - "name": "testAssembly", - "type": "string", + "name": "testAssemblyVer2", + "type": "multiLine", "label": "Test Assembly", - "defaultValue": "**\\*test*.dll;-:**\\obj\\**", + "defaultValue": "**\\*test*.dll\n!**\\obj\\**", "required": true, - "helpMarkDown": "Test binaries to run tests on. Wildcards can be used. For example, `**\\*test*.dll;-:**\\obj\\**` for all dlls with test in name while excluding files in any sub-directory named obj.", + "helpMarkDown": "Run tests from the specified files. The file paths are relative to the search folder. Supports multiple lines of minimatch patterns. [More Information](https://go.microsoft.com/fwlink/?LinkId=835764)", + "groupName": "executionOptions", + "properties": { + "rows": "3", + "resizable": "true" + } + }, + { + "name": "searchFolder", + "type": "string", + "label": "Search Folder", + "defaultValue": "", + "required": false, + "helpMarkDown": "Folder to search for the test assemblies. Defaults to $(System.DefaultWorkingDirectory).", "groupName": "executionOptions" }, { @@ -209,16 +228,8 @@ "groupName": "reportingOptions" } ], - "instanceNameFormat": "Test Assemblies $(testAssembly)", + "instanceNameFormat": "Test Assemblies", "execution": { - "PowerShell": { - "target": "$(currentDirectory)\\VSTest.ps1", - "argumentFormat": "", - "workingDirectory": "$(currentDirectory)", - "platforms": [ - "windows" - ] - }, "Node": { "target": "vstest.js" } @@ -249,6 +260,7 @@ "ErrorReadingVstestVersion": "Error reading the version of vstest.console.exe.", "UnexpectedVersionString": "Unexpected version string detected for vstest.console.exe: %s.", "UnexpectedVersionNumber": "Unexpected version number detected for vstest.console.exe: %s.", - "VstestDiagNotSupported": "vstest.console.exe version does not support the /diag flag. Enable diagnositics via the exe.config files" + "VstestDiagNotSupported": "vstest.console.exe version does not support the /diag flag. Enable diagnositics via the exe.config files", + "NoIncludePatternFound": "No include pattern found. Specify atleast one include pattern to search test assemblies." } } \ No newline at end of file diff --git a/Tasks/VsTest/task.loc.json b/Tasks/VsTest/task.loc.json index 4fe3d943afe9..7a4a7e9ea4b4 100644 --- a/Tasks/VsTest/task.loc.json +++ b/Tasks/VsTest/task.loc.json @@ -9,15 +9,21 @@ "Build", "Release" ], + "runsOn": [ + "Agent", + "MachineGroup" + ], "author": "Microsoft Corporation", "version": { - "Major": 1, + "Major": 2, "Minor": 0, - "Patch": 80 + "Patch": 0 }, "demands": [ "vstest" ], + "preview": "true", + "releaseNotes": "Test Impact and support for minimatch patterns.", "minimumAgentVersion": "1.89.0", "groups": [ { @@ -46,12 +52,25 @@ ], "inputs": [ { - "name": "testAssembly", - "type": "string", - "label": "ms-resource:loc.input.label.testAssembly", - "defaultValue": "**\\*test*.dll;-:**\\obj\\**", + "name": "testAssemblyVer2", + "type": "multiLine", + "label": "ms-resource:loc.input.label.testAssemblyVer2", + "defaultValue": "**\\*test*.dll\n!**\\obj\\**", "required": true, - "helpMarkDown": "ms-resource:loc.input.help.testAssembly", + "helpMarkDown": "ms-resource:loc.input.help.testAssemblyVer2", + "groupName": "executionOptions", + "properties": { + "rows": "3", + "resizable": "true" + } + }, + { + "name": "searchFolder", + "type": "string", + "label": "ms-resource:loc.input.label.searchFolder", + "defaultValue": "", + "required": false, + "helpMarkDown": "ms-resource:loc.input.help.searchFolder", "groupName": "executionOptions" }, { @@ -211,14 +230,6 @@ ], "instanceNameFormat": "ms-resource:loc.instanceNameFormat", "execution": { - "PowerShell": { - "target": "$(currentDirectory)\\VSTest.ps1", - "argumentFormat": "", - "workingDirectory": "$(currentDirectory)", - "platforms": [ - "windows" - ] - }, "Node": { "target": "vstest.js" } @@ -249,6 +260,7 @@ "ErrorReadingVstestVersion": "ms-resource:loc.messages.ErrorReadingVstestVersion", "UnexpectedVersionString": "ms-resource:loc.messages.UnexpectedVersionString", "UnexpectedVersionNumber": "ms-resource:loc.messages.UnexpectedVersionNumber", - "VstestDiagNotSupported": "ms-resource:loc.messages.VstestDiagNotSupported" + "VstestDiagNotSupported": "ms-resource:loc.messages.VstestDiagNotSupported", + "NoIncludePatternFound": "ms-resource:loc.messages.NoIncludePatternFound" } } \ No newline at end of file diff --git a/Tasks/VsTest/typings/index.d.ts b/Tasks/VsTest/typings/index.d.ts index ed0373e4db67..14240edd45f2 100644 --- a/Tasks/VsTest/typings/index.d.ts +++ b/Tasks/VsTest/typings/index.d.ts @@ -1,4 +1,2 @@ /// -/// -// TODO: remove after moving to latest task lib -/// +/// \ No newline at end of file diff --git a/Tasks/VsTest/typings/vsts-task-lib.d.ts b/Tasks/VsTest/typings/vsts-task-lib.d.ts deleted file mode 100644 index bfa38b71031a..000000000000 --- a/Tasks/VsTest/typings/vsts-task-lib.d.ts +++ /dev/null @@ -1,579 +0,0 @@ -declare module 'vsts-task-lib/taskcommand' { - export class TaskCommand { - constructor(command: any, properties: any, message: any); - command: string; - message: string; - properties: { - [key: string]: string; - }; - toString(): string; - } - export function commandFromString(commandLine: any): TaskCommand; - -} -declare module 'vsts-task-lib/toolrunner' { - import Q = require('q'); - import events = require('events'); - import stream = require('stream'); - /** - * Interface for exec options - * - * @param cwd optional working directory. defaults to current - * @param env optional envvar dictionary. defaults to current processes env - * @param silent optional. defaults to false - * @param failOnStdErr optional. whether to fail if output to stderr. defaults to false - * @param ignoreReturnCode optional. defaults to failing on non zero. ignore will not fail leaving it up to the caller - */ - export interface IExecOptions { - cwd?: string; - env?: { - [key: string]: string; - }; - silent?: boolean; - failOnStdErr?: boolean; - ignoreReturnCode?: boolean; - outStream?: stream.Writable; - errStream?: stream.Writable; - } - /** - * Interface for exec results returned from synchronous exec functions - * - * @param stdout standard output - * @param stderr error output - * @param code return code - * @param error Error on failure - */ - export interface IExecResult { - stdout: string; - stderr: string; - code: number; - error: Error; - } - export function debug(message: any): void; - export class ToolRunner extends events.EventEmitter { - constructor(toolPath: any); - toolPath: string; - args: string[]; - silent: boolean; - private _debug(message); - private _argStringToArray(argString); - /** - * Add argument - * Append an argument or an array of arguments - * - * @param val string cmdline or array of strings - * @returns void - */ - arg(val: string | string[]): void; - /** - * Append argument command line string - * e.g. '"arg one" two -z' would append args[]=['arg one', 'two', '-z'] - * - * @param val string cmdline - * @returns void - */ - argString(val: string): void; - /** - * Append argument command line string - * e.g. '"arg one" two -z' would append args[]=['arg one', 'two', '-z'] - * returns ToolRunner for chaining - * - * @param val string cmdline - * @returns ToolRunner - */ - line(val: string): void; - /** - * Append argument command line string - * e.g. '"arg one" two -z' would append args[]=['arg one', 'two', '-z'] - * returns ToolRunner for chaining - * - * @param val string cmdline - * @returns ToolRunner - */ - line(val: string): ToolRunner; - /** - * Add path argument - * Add path string to argument, path string should not contain double quoted - * This will call arg(val, literal?) with literal equal 'true' - * - * @param val path argument string - * @returns void - */ - pathArg(val: string): void; - /** - * Add argument(s) if a condition is met - * Wraps arg(). See arg for details - * - * @param condition boolean condition - * @param val string cmdline or array of strings - * @returns void - */ - argIf(condition: any, val: any): void; - /** - * Pipe output of exec() to another tool - * @param tool - * @returns {ToolRunner} - */ - public pipeExecOutputToTool(tool: ToolRunner) : ToolRunner; - /** - * Exec a tool. - * Output will be streamed to the live console. - * Returns promise with return code - * - * @param tool path to tool to exec - * @param options optional exec options. See IExecOptions - * @returns number - */ - exec(options?: IExecOptions): Q.Promise; - /** - * Exec a tool synchronously. - * Output will be *not* be streamed to the live console. It will be returned after execution is complete. - * Appropriate for short running tools - * Returns IExecResult with output and return code - * - * @param tool path to tool to exec - * @param options optionalexec options. See IExecOptions - * @returns IExecResult - */ - execSync(options?: IExecOptions): IExecResult; - } - -} -declare module 'vsts-task-lib/vault' { - export class Vault { - constructor(); - private _keyFile; - private _store; - initialize(): void; - storeSecret(name: string, data: string): boolean; - retrieveSecret(name: string): string; - private getKey(); - private genKey(); - } - -} -declare module 'vsts-task-lib/task' { - /// - import Q = require('q'); - import fs = require('fs'); - import trm = require('vsts-task-lib/toolrunner'); - export enum TaskResult { - Succeeded = 0, - Failed = 1, - } - export var _outStream: any; - export var _errStream: any; - export function _writeError(str: string): void; - export function _writeLine(str: string): void; - export function setStdStream(stdStream: any): void; - export function setErrStream(errStream: any): void; - /** - * Sets the result of the task. - * If the result is Failed (1), then execution will halt. - * - * @param result TaskResult enum of Success or Failed. If the result is Failed (1), then execution will halt. - * @param messages A message which will be logged and added as an issue if an failed - * @returns void - */ - export function setResult(result: TaskResult, message: string): void; - export function handlerError(errMsg: string, continueOnError: boolean): void; - export function exitOnCodeIf(code: number, condition: boolean): void; - export function exit(code: number): void; - /** - * Sets the location of the resources json. This is typically the task.json file. - * Call once at the beginning of the script before any calls to loc. - * - * @param path Full path to the json. - * @returns void - */ - export function setResourcePath(path: string): void; - /** - * Gets the localized string from the json resource file. Optionally formats with additional params. - * - * @param key key of the resources string in the resource file - * @param param additional params for formatting the string - * @returns string - */ - export function loc(key: string, ...param: any[]): string; - /** - * Gets a variables value which is defined on the build definition or set at runtime. - * - * @param name name of the variable to get - * @returns string - */ - export function getVariable(name: string): string; - /** - * Sets a variables which will be available to subsequent tasks as well. - * - * @param name name of the variable to set - * @param val value to set - * @returns void - */ - export function setVariable(name: string, val: string): void; - /** - * Gets the value of an input. The value is also trimmed. - * If required is true and the value is not set, the task will fail with an error. Execution halts. - * - * @param name name of the input to get - * @param required whether input is required. optional, defaults to false - * @returns string - */ - export function getInput(name: string, required?: boolean): string; - /** - * Gets the value of an input and converts to a bool. Convenience. - * If required is true and the value is not set, the task will fail with an error. Execution halts. - * - * @param name name of the bool input to get - * @param required whether input is required. optional, defaults to false - * @returns string - */ - export function getBoolInput(name: string, required?: boolean): boolean; - export function setEnvVar(name: string, val: string): void; - /** - * Gets the value of an input and splits the values by a delimiter (space, comma, etc...) - * Useful for splitting an input with simple list of items like targets - * IMPORTANT: Do not use for splitting additional args! Instead use arg() - it will split and handle - * If required is true and the value is not set, the task will fail with an error. Execution halts. - * - * @param name name of the input to get - * @param delim delimiter to split on - * @param required whether input is required. optional, defaults to false - * @returns string[] - */ - export function getDelimitedInput(name: string, delim: string, required?: boolean): string[]; - /** - * Checks whether a path inputs value was supplied by the user - * File paths are relative with a picker, so an empty path is the root of the repo. - * Useful if you need to condition work (like append an arg) if a value was supplied - * - * @param name name of the path input to check - * @returns boolean - */ - export function filePathSupplied(name: string): boolean; - /** - * Gets the value of a path input - * It will be quoted for you if it isn't already and contains spaces - * If required is true and the value is not set, the task will fail with an error. Execution halts. - * If check is true and the path does not exist, the task will fail with an error. Execution halts. - * - * @param name name of the input to get - * @param required whether input is required. optional, defaults to false - * @param check whether path is checked. optional, defaults to false - * @returns string - */ - export function getPathInput(name: string, required?: boolean, check?: boolean): string; - /** - * Gets the url for a service endpoint - * If the url was not set and is not optional, the task will fail with an error message. Execution will halt. - * - * @param id name of the service endpoint - * @param optional whether the url is optional - * @returns string - */ - export function getEndpointUrl(id: string, optional: boolean): string; - export function getEndpointDataParameter(id: string, key: string, optional: boolean): string; - /** - * Gets the endpoint authorization scheme for a service endpoint - * If the endpoint authorization scheme is not set and is not optional, the task will fail with an error message. Execution will halt. - * - * @param id name of the service endpoint - * @param optional whether the endpoint authorization scheme is optional - * @returns {string} value of the endpoint authorization scheme - */ - export function getEndpointAuthorizationScheme(id: string, optional: boolean): string; - /** - * Gets the endpoint authorization parameter value for a service endpoint with specified key - * If the endpoint authorization parameter is not set and is not optional, the task will fail with an error message. Execution will halt. - * - * @param id name of the service endpoint - * @param key key to find the endpoint authorization parameter - * @param optional optional whether the endpoint authorization scheme is optional - * @returns {string} value of the endpoint authorization parameter value - */ - export function getEndpointAuthorizationParameter(id: string, key: string, optional: boolean): string; - /** - * Interface for EndpointAuthorization - * Contains a schema and a string/string dictionary of auth data - * - * @param parameters string string dictionary of auth data - * @param scheme auth scheme such as OAuth or username/password etc... - */ - export interface EndpointAuthorization { - parameters: { - [key: string]: string; - }; - scheme: string; - } - /** - * Gets the authorization details for a service endpoint - * If the authorization was not set and is not optional, the task will fail with an error message. Execution will halt. - * - * @param id name of the service endpoint - * @param optional whether the url is optional - * @returns string - */ - export function getEndpointAuthorization(id: string, optional: boolean): EndpointAuthorization; - /* - * Gets the endpoint data parameter value with specified key for a service endpoint - * If the endpoint data parameter was not set and is not optional, the task will fail with an error message. Execution will halt. - * - * @param id name of the service endpoint - * @param key of the parameter - * @param optional whether the endpoint data is optional - * @returns {string} value of the endpoint data parameter - */ - export function getEndpointDataParameter(id: string, key: string, optional: boolean): string; - /** - * Gets the endpoint authorization scheme for a service endpoint - * If the endpoint authorization scheme is not set and is not optional, the task will fail with an error message. Execution will halt. - * - * @param id name of the service endpoint - * @param optional whether the endpoint authorization scheme is optional - * @returns {string} value of the endpoint authorization scheme - */ - export function getEndpointAuthorizationScheme(id: string, optional: boolean): string; - /** - * Gets the endpoint authorization parameter value for a service endpoint with specified key - * If the endpoint authorization parameter is not set and is not optional, the task will fail with an error message. Execution will halt. - * - * @param id name of the service endpoint - * @param key key to find the endpoint authorization parameter - * @param optional optional whether the endpoint authorization scheme is optional - * @returns {string} value of the endpoint authorization parameter value - */ - export function getEndpointAuthorizationParameter(id: string, key: string, optional: boolean): string; - export function command(command: string, properties: any, message: string): void; - export function warning(message: string): void; - export function error(message: string): void; - export function debug(message: string): void; - export interface FsStats extends fs.Stats { - } - - /** - * Get's stat on a path. - * Useful for checking whether a file or directory. Also getting created, modified and accessed time. - * see [fs.stat](https://nodejs.org/api/fs.html#fs_class_fs_stats) - * - * @param path path to check - * @returns fsStat - */ - export function stats(path: string): FsStats; - /** - * Returns whether a path exists. - * - * @param path path to check - * @returns boolean - */ - export function exist(path: string): boolean; - - /** - * Interface to wrap file options - */ - export interface FsOptions {} - - /** - * Synchronously writes data to a file, replacing the file if it already exists. - * @param file - * @param data - * @param options - */ - export function writeFile(file: string, data:string|Buffer, options?:string|FsOptions); - /** - * Useful for determining the host operating system. - * see [os.type](https://nodejs.org/api/os.html#os_os_type) - * - * @return the name of the operating system - */ - export function osType(): string; - /** - * Returns the process's current working directory. - * see [process.cwd](https://nodejs.org/api/process.html#process_process_cwd) - * - * @return the path to the current working directory of the process - */ - export function cwd(): string; - /** - * Checks whether a path exists. - * If the path does not exist, the task will fail with an error message. Execution will halt. - * - * @param p path to check - * @param name name only used in error message to identify the path - * @returns void - */ - export function checkPath(p: string, name: string): void; - /** - * Change working directory. - * - * @param path new working directory path - * @returns void - */ - export function cd(path: string): void; - /** - * Change working directory and push it on the stack - * - * @param path new working directory path - * @returns void - */ - export function pushd(path: string): void; - /** - * Change working directory back to previously pushed directory - * - * @returns void - */ - export function popd(): void; - /** - * Resolves a sequence of paths or path segments into an absolute path. - * Calls node.js path.resolve() - * Allows L0 testing with consistent path formats on Mac/Linux and Windows in the mock implementation - * @param pathSegments - * @returns {string} - */ - export function resolve(...pathSegments: any[]): string; - /** - * Make a directory. Creates the full path with folders in between - * Returns whether it was successful or not - * - * @param p path to create - * @returns boolean - */ - export function mkdirP(p: any): boolean; - /** - * Returns path of a tool had the tool actually been invoked. Resolves via paths. - * If you check and the tool does not exist, the task will fail with an error message and halt execution. - * - * @param tool name of the tool - * @param check whether to check if tool exists - * @returns string - */ - export function which(tool: string, check?: boolean): string; - /** - * Returns array of files in the given path, or in current directory if no path provided. See shelljs.ls - * @param {string} options Available options: -R (recursive), -A (all files, include files beginning with ., except for . and ..) - * @param {string[]} paths Paths to search. - * @return {string[]} An array of files in the given path(s). - */ - export function ls(options: string, paths: string[]): string[]; - /** - * Returns path of a tool had the tool actually been invoked. Resolves via paths. - * If you check and the tool does not exist, the task will fail with an error message and halt execution. - * Returns whether the copy was successful - * - * @param options string -r, -f or -rf for recursive and force - * @param source source path - * @param dest destination path - * @param continueOnError optional. whether to continue on error - * @returns boolean - */ - export function cp(options: any, source: string, dest: string, continueOnError?: boolean): boolean; - /** - * Moves a path. - * Returns whether the copy was successful - * - * @param source source path - * @param dest destination path - * @param force whether to force and overwrite - * @param continueOnError optional. whether to continue on error - * @returns boolean - */ - export function mv(source: string, dest: string, force: boolean, continueOnError?: boolean): boolean; - /** - * Interface for FindOptions - * Contains properties to control whether to follow symlinks - * - * @param followSpecifiedSymbolicLink Equivalent to the -H command line option. Indicates whether to traverse descendants if the specified path is a symbolic link directory. Does not cause nested symbolic link directories to be traversed. - * @param followSymbolicLinks Equivalent to the -L command line option. Indicates whether to traverse descendants of symbolic link directories. - */ - export interface FindOptions { - /** - * Equivalent to the -H command line option. Indicates whether to traverse descendants if - * the specified path is a symbolic link directory. Does not cause nested symbolic link - * directories to be traversed. - */ - followSpecifiedSymbolicLink: boolean; - - /** - * Equivalent to the -L command line option. Indicates whether to traverse descendants of - * symbolic link directories. - */ - followSymbolicLinks: boolean; - } - /** - * Find all files under a give path - * Returns an array of full paths - * - * @param findPath path to find files under - * @returns string[] - */ - export function find(findPath: string, options?: FindOptions): string[]; - /** - * Remove a path recursively with force - * Returns whether it succeeds - * - * @param path path to remove - * @param continueOnError optional. whether to continue on error - * @returns string[] - */ - export function rmRF(path: string, continueOnError?: boolean): boolean; - export function glob(pattern: string): string[]; - export function globFirst(pattern: string): string; - /** - * Exec a tool. Convenience wrapper over ToolRunner to exec with args in one call. - * Output will be streamed to the live console. - * Returns promise with return code - * - * @param tool path to tool to exec - * @param args an arg string or array of args - * @param options optional exec options. See IExecOptions - * @returns number - */ - export function exec(tool: string, args: any, options?: trm.IExecOptions): Q.Promise; - /** - * Exec a tool synchronously. Convenience wrapper over ToolRunner to execSync with args in one call. - * Output will be *not* be streamed to the live console. It will be returned after execution is complete. - * Appropriate for short running tools - * Returns IExecResult with output and return code - * - * @param tool path to tool to exec - * @param args an arg string or array of args - * @param options optionalexec options. See IExecOptions - * @returns IExecResult - */ - export function execSync(tool: string, args: string | string[], options?: trm.IExecOptions): trm.IExecResult; - /** - * Convenience factory to create a ToolRunner. - * - * @param tool path to tool to exec - * @returns ToolRunner - */ - export function createToolRunner(tool: string): trm.ToolRunner; - - /** - * Convenience factory to create a ToolRunner. - * - * @param tool path to tool to exec - * @returns ToolRunner - */ - export function tool(tool: string) : trm.ToolRunner; - - export function match(list: any, pattern: any, options: any): string[]; - export function filter(pattern: any, options: any): (element: string, indexed: number, array: string[]) => boolean; - export class TestPublisher { - constructor(testRunner: any); - testRunner: string; - publish(resultFiles: any, mergeResults: any, platform: any, config: any, runTitle: any, publishRunAttachments: any): void; - } - export class CodeCoveragePublisher { - constructor(); - publish(codeCoverageTool: any, summaryFileLocation: any, reportDirectory: any, additionalCodeCoverageFiles: any): void; - } - export class CodeCoverageEnabler { - private buildTool; - private ccTool; - constructor(buildTool: string, ccTool: string); - enableCodeCoverage(buildProps: { - [key: string]: string; - }): void; - } - export function _loadData(): void; - -} diff --git a/Tasks/VsTest/vstest.ts b/Tasks/VsTest/vstest.ts index 5c46e26207ce..c05051b04f86 100644 --- a/Tasks/VsTest/vstest.ts +++ b/Tasks/VsTest/vstest.ts @@ -1,14 +1,15 @@ import tl = require('vsts-task-lib/task'); +import tr = require('vsts-task-lib/toolrunner'); import path = require('path'); import Q = require('q'); -import ffl = require('find-files-legacy/findfiles.legacy'); var os = require('os'); var regedit = require('regedit'); var uuid = require('node-uuid'); var fs = require('fs'); var xml2js = require('xml2js'); -var perf = require("performance-now") +var perf = require("performance-now"); +var process = require('process'); const runSettingsExt = ".runsettings"; const testSettingsExt = ".testsettings"; @@ -24,7 +25,7 @@ try { var vsTestVersion: string = tl.getInput('vsTestVersion'); var vstestLocationMethod: string = tl.getInput('vstestLocationMethod'); var vstestLocation: string = tl.getPathInput('vsTestLocation'); - var testAssembly: string = tl.getInput('testAssembly', true); + var testAssembly: string[] = tl.getDelimitedInput('testAssemblyVer2', '\n', true); var testFiltercriteria: string = tl.getInput('testFiltercriteria'); var runSettingsFile: string = tl.getPathInput('runSettingsFile'); var codeCoverageEnabled: boolean = tl.getBoolInput('codeCoverageEnabled'); @@ -37,8 +38,10 @@ try { var publishRunAttachments: string = tl.getInput('publishRunAttachments'); var runInParallel: boolean = tl.getBoolInput('runInParallel'); var tiaEnabled: boolean = tl.getBoolInput('runOnlyImpactedTests'); - var fileLevel = tl.getVariable('tia.filelevel'); var tiaRebaseLimit: string = tl.getInput('runAllTestsAfterXBuilds'); + var searchFolder: string = tl.getInput('searchFolder'); + + var fileLevel = tl.getVariable('tia.filelevel'); var sourcesDir = tl.getVariable('build.sourcesdirectory'); var runIdFile = path.join(os.tmpdir(), uuid.v1() + ".txt"); var baseLineBuildIdFile = path.join(os.tmpdir(), uuid.v1() + ".txt"); @@ -48,26 +51,24 @@ try { var vsTestVersionForTIA: number[] = null; var useNewCollector = false; - if (useNewCollectorFlag && useNewCollectorFlag.toUpperCase() == "TRUE") { + if (useNewCollectorFlag && useNewCollectorFlag.toUpperCase() === "TRUE") { useNewCollector = true; } - + var releaseuri = tl.getVariable("release.releaseUri") - var context = "CI"; - if(releaseuri) - { - context = "CD"; - } + var context = "CI"; + if (releaseuri) { + context = "CD"; + } var systemDefaultWorkingDirectory = tl.getVariable('System.DefaultWorkingDirectory'); - var artifactsDirectory = tl.getVariable('System.ArtifactsDirectory'); var testAssemblyFiles = getTestAssemblies(); - if (testAssemblyFiles && testAssemblyFiles.size != 0) { - var workingDirectory = sourcesDir && sourcesDir != '' ? systemDefaultWorkingDirectory : artifactsDirectory; - getTestResultsDirectory(runSettingsFile, path.join(workingDirectory, 'TestResults')).then(function (resultsDirectory) { + if (testAssemblyFiles && testAssemblyFiles.length != 0) { + var workingDirectory = systemDefaultWorkingDirectory; + getTestResultsDirectory(runSettingsFile, path.join(workingDirectory, 'TestResults')).then(function(resultsDirectory) { invokeVSTest(resultsDirectory) - .then(function (code) { + .then(function(code) { try { if (!isTiaAllowed()) { publishTestResults(resultsDirectory); @@ -81,7 +82,7 @@ try { throw error; } }) - .fail(function (err) { + .fail(function(err) { deleteVstestDiagFile(); tl._writeLine("##vso[task.logissue type=error;code=" + err + ";TaskName=VSTest]"); throw err; @@ -100,30 +101,18 @@ catch (error) { throw error; } -function getResolvedPattern(pattern: string): string { - if (path.isAbsolute(pattern)) { - return pattern; - } - else { - return path.join(systemDefaultWorkingDirectory, pattern); +function getTestAssemblies(): string[] { + if (isNullOrWhitespace(searchFolder)) { + searchFolder = systemDefaultWorkingDirectory; + tl.debug("Search directory empty, defaulting to " + searchFolder); } -} - -function getPatternWithoutIncludeExclude(pattern: string): string { - return pattern.startsWith('-:') || pattern.startsWith('+:') ? pattern.substr(2) : pattern; -} - -function getFilteredFilesFromPattern(pattern: string, hasQuantifier: boolean, allFiles: string[]): string[] { - return hasQuantifier ? getFilteredFiles(pattern, allFiles) : [pattern]; -} - -function getTestAssemblies(): Set { - return new Set(ffl.findFiles(testAssembly, false, systemDefaultWorkingDirectory)); + tl.debug("Searching for test assemblies in: " + searchFolder); + return tl.findMatch(searchFolder, testAssembly); } function getVsTestVersion(): number[] { let vstestLocationEscaped = vstestLocation.replace(/\\/g, "\\\\"); - let wmicTool = tl.createToolRunner("wmic"); + let wmicTool = tl.tool("wmic"); let wmicArgs = ["datafile", "where", "name='".concat(vstestLocationEscaped, "'"), "get", "Version", "/Value"]; wmicTool.arg(wmicArgs); let output = wmicTool.execSync(); @@ -150,12 +139,12 @@ function getVsTestVersion(): number[] { return null; } - return vsVersion; + return vsVersion; } function getVstestArguments(settingsFile: string, tiaEnabled: boolean): string[] { var argsArray: string[] = []; - testAssemblyFiles.forEach(function (testAssembly) { + testAssemblyFiles.forEach(function(testAssembly) { var testAssemblyPath = testAssembly; //To maintain parity with the behaviour when test assembly was filepath, try to expand it relative to build sources directory. if (systemDefaultWorkingDirectory && !pathExistsAsFile(testAssembly)) { @@ -164,7 +153,7 @@ function getVstestArguments(settingsFile: string, tiaEnabled: boolean): string[] testAssemblyPath = expandedPath; } } - argsArray.push(testAssemblyPath); + argsArray.push(testAssemblyPath); }); if (testFiltercriteria) { if (!tiaEnabled) { @@ -199,31 +188,31 @@ function getVstestArguments(settingsFile: string, tiaEnabled: boolean): string[] let sysDebug = tl.getVariable("System.Debug"); if (sysDebug !== undefined && sysDebug.toLowerCase() === "true") { - if (vsTestVersionForTIA !== null && (vsTestVersionForTIA[0] > 15 || (vsTestVersionForTIA[0] == 15 && (vsTestVersionForTIA[1] > 0 || vsTestVersionForTIA[2] > 25428)))) { + if (vsTestVersionForTIA !== null && (vsTestVersionForTIA[0] > 15 || (vsTestVersionForTIA[0] === 15 && (vsTestVersionForTIA[1] > 0 || vsTestVersionForTIA[2] > 25428)))) { argsArray.push("/diag:" + vstestDiagFile); } else { tl.warning(tl.loc("VstestDiagNotSupported")); } } - + return argsArray; } function addVstestArgs(argsArray: string[], vstest: any) { - argsArray.forEach(function (arr) { + argsArray.forEach(function(arr) { vstest.arg(arr); }); } function updateResponseFile(argsArray: string[], responseFile: string): Q.Promise { var defer = Q.defer(); - argsArray.forEach(function (arr, i) { + argsArray.forEach(function(arr, i) { if (!arr.startsWith('/')) { argsArray[i] = "\"" + arr + "\""; } - }); - fs.appendFile(responseFile, os.EOL + argsArray.join(os.EOL), function (err) { + }); + fs.appendFile(responseFile, os.EOL + argsArray.join(os.EOL), function(err) { if (err) { defer.reject(err); } @@ -247,34 +236,31 @@ function uploadTestResults(testResultsDirectory: string): Q.Promise { var defer = Q.defer(); var allFilesInResultsDirectory; var resultFiles; - if (testResultsDirectory && testResultsDirectory !== "") - { - allFilesInResultsDirectory = tl.find(testResultsDirectory); - resultFiles = tl.match(allFilesInResultsDirectory, path.join(testResultsDirectory, "*.trx"), { matchBase: true }); + if (!isNullOrWhitespace(testResultsDirectory)) { + resultFiles = tl.findMatch(testResultsDirectory, path.join(testResultsDirectory, "*.trx")); } - var selectortool = tl.createToolRunner(getTestSelectorLocation()); + var selectortool = tl.tool(getTestSelectorLocation()); selectortool.arg("UpdateTestResults"); selectortool.arg("/TfsTeamProjectCollection:" + tl.getVariable("System.TeamFoundationCollectionUri")); selectortool.arg("/ProjectId:" + tl.getVariable("System.TeamProject")); selectortool.arg("/buildid:" + tl.getVariable("Build.BuildId")); selectortool.arg("/token:" + tl.getEndpointAuthorizationParameter("SystemVssConnection", "AccessToken", false)); - if (resultFiles && resultFiles[0]) - { + if (resultFiles && resultFiles[0]) { selectortool.arg("/ResultFile:" + resultFiles[0]); } selectortool.arg("/runidfile:" + runIdFile); selectortool.arg("/Context:" + context); selectortool.exec() - .then(function (code) { + .then(function(code) { endTime = perf(); elapsedTime = endTime - startTime; tl._writeLine("##vso[task.logissue type=warning;SubTaskName=UploadTestResults;SubTaskDuration=" + elapsedTime + "]"); tl.debug(tl.loc("UploadTestResultsPerfTime", elapsedTime)); defer.resolve(String(code)); }) - .fail(function (err) { + .fail(function(err) { defer.reject(err); }); return defer.promise; @@ -288,24 +274,21 @@ function generateResponseFile(discoveredTests: string): Q.Promise { var respFile = path.join(os.tmpdir(), uuid.v1() + ".txt"); tl.debug("Response file will be generated at " + respFile); tl.debug("RunId file will be generated at " + runIdFile); - var selectortool = tl.createToolRunner(getTestSelectorLocation()); + var selectortool = tl.tool(getTestSelectorLocation()); selectortool.arg("GetImpactedtests"); selectortool.arg("/TfsTeamProjectCollection:" + tl.getVariable("System.TeamFoundationCollectionUri")); selectortool.arg("/ProjectId:" + tl.getVariable("System.TeamProject")); - if(context == "CD") - { + if (context === "CD") { // Release context. Passing Release Id. selectortool.arg("/buildid:" + tl.getVariable("Release.ReleaseId")); selectortool.arg("/releaseuri:" + tl.getVariable("release.releaseUri")); - selectortool.arg("/releaseenvuri:" + tl.getVariable("release.environmentUri")); - } - else - { + selectortool.arg("/releaseenvuri:" + tl.getVariable("release.environmentUri")); + } else { // Build context. Passing build id. selectortool.arg("/buildid:" + tl.getVariable("Build.BuildId")); - } - + } + selectortool.arg("/token:" + tl.getEndpointAuthorizationParameter("SystemVssConnection", "AccessToken", false)); selectortool.arg("/responsefile:" + respFile); selectortool.arg("/DiscoveredTests:" + discoveredTests); @@ -313,17 +296,17 @@ function generateResponseFile(discoveredTests: string): Q.Promise { selectortool.arg("/testruntitle:" + testRunTitle); selectortool.arg("/BaseLineFile:" + baseLineBuildIdFile); selectortool.arg("/platform:" + platform); - selectortool.arg("/configuration:" + configuration); - selectortool.arg("/Context:" + context); + selectortool.arg("/configuration:" + configuration); + selectortool.arg("/Context:" + context); selectortool.exec() - .then(function (code) { + .then(function(code) { endTime = perf(); elapsedTime = endTime - startTime; tl.debug(tl.loc("GenerateResponseFilePerfTime", elapsedTime)); defer.resolve(respFile); }) - .fail(function (err) { + .fail(function(err) { defer.reject(err); }); @@ -337,35 +320,31 @@ function publishCodeChanges(): Q.Promise { var defer = Q.defer(); var newprovider = "true"; - if (getTIALevel() == 'method') { + if (getTIALevel() === 'method') { newprovider = "false"; } - var selectortool = tl.createToolRunner(getTestSelectorLocation()); + var selectortool = tl.tool(getTestSelectorLocation()); selectortool.arg("PublishCodeChanges"); selectortool.arg("/TfsTeamProjectCollection:" + tl.getVariable("System.TeamFoundationCollectionUri")); selectortool.arg("/ProjectId:" + tl.getVariable("System.TeamProject")); - if(context == "CD") - { + if (context === "CD") { // Release context. Passing Release Id. - selectortool.arg("/buildid:" + tl.getVariable("Release.ReleaseId")); + selectortool.arg("/buildid:" + tl.getVariable("Release.ReleaseId")); selectortool.arg("/Definitionid:" + tl.getVariable("release.DefinitionId")); - } - else - { + } else { // Build context. Passing build id. selectortool.arg("/buildid:" + tl.getVariable("Build.BuildId")); selectortool.arg("/Definitionid:" + tl.getVariable("System.DefinitionId")); - } + } - selectortool.arg("/token:" + tl.getEndpointAuthorizationParameter("SystemVssConnection", "AccessToken", false)); selectortool.arg("/SourcesDir:" + sourcesDir); selectortool.arg("/newprovider:" + newprovider); selectortool.arg("/BaseLineFile:" + baseLineBuildIdFile); - if (isPrFlow && isPrFlow.toUpperCase() == "TRUE") { + if (isPrFlow && isPrFlow.toUpperCase() === "TRUE") { selectortool.arg("/IsPrFlow:" + "true"); } @@ -373,15 +352,15 @@ function publishCodeChanges(): Q.Promise { selectortool.arg("/RebaseLimit:" + tiaRebaseLimit); } selectortool.arg("/Context:" + context); - + selectortool.exec() - .then(function (code) { + .then(function(code) { endTime = perf(); elapsedTime = endTime - startTime; tl.debug(tl.loc("PublishCodeChangesPerfTime", elapsedTime)); defer.resolve(String(code)); }) - .fail(function (err) { + .fail(function(err) { defer.reject(err); }); @@ -411,18 +390,18 @@ function getVSTestLocation(vsVersion: number): string { function executeVstest(testResultsDirectory: string, parallelRunSettingsFile: string, vsVersion: number, argsArray: string[]): Q.Promise { var defer = Q.defer(); - var vstest = tl.createToolRunner(vstestLocation); + var vstest = tl.tool(vstestLocation); addVstestArgs(argsArray, vstest); tl.rmRF(testResultsDirectory, true); tl.mkdirP(testResultsDirectory); tl.cd(workingDirectory); - vstest.exec({ failOnStdErr: true }) - .then(function (code) { + vstest.exec({ failOnStdErr: true }) + .then(function(code) { cleanUp(parallelRunSettingsFile); defer.resolve(code); }) - .fail(function (err) { + .fail(function(err) { cleanUp(parallelRunSettingsFile); tl.warning(tl.loc('VstestFailed')); tl.error(err); @@ -437,7 +416,7 @@ function getVstestTestsList(vsVersion: number): Q.Promise { tl.debug("Discovered tests listed at: " + tempFile); var argsArray: string[] = []; - testAssemblyFiles.forEach(function (testAssembly) { + testAssemblyFiles.forEach(function(testAssembly) { var testAssemblyPath = testAssembly; if (systemDefaultWorkingDirectory && !pathExistsAsFile(testAssembly)) { var expandedPath = path.join(systemDefaultWorkingDirectory, testAssembly); @@ -471,15 +450,15 @@ function getVstestTestsList(vsVersion: number): Q.Promise { argsArray.push("/UseVsixExtensions:true"); } - var vstest = tl.createToolRunner(vstestLocation); + let vstest = tl.tool(vstestLocation); addVstestArgs(argsArray, vstest); tl.cd(workingDirectory); - vstest.exec({ failOnStdErr: true }) - .then(function (code) { + vstest.exec({ failOnStdErr: true }) + .then(function(code) { defer.resolve(tempFile); }) - .fail(function (err) { + .fail(function(err) { tl.debug("Listing tests from VsTest failed."); tl.error(err); defer.resolve(err); @@ -507,17 +486,17 @@ function runVStest(testResultsDirectory: string, settingsFile: string, vsVersion var defer = Q.defer(); if (isTiaAllowed()) { publishCodeChanges() - .then(function (status) { + .then(function(status) { getVstestTestsList(vsVersion) - .then(function (listFile) { + .then(function(listFile) { generateResponseFile(listFile) - .then(function (responseFile) { + .then(function(responseFile) { if (isEmptyResponseFile(responseFile)) { tl.debug("Empty response file detected. All tests will be executed."); executeVstest(testResultsDirectory, settingsFile, vsVersion, getVstestArguments(settingsFile, false)) - .then(function (vscode) { + .then(function(vscode) { uploadTestResults(testResultsDirectory) - .then(function (code) { + .then(function(code) { if (!isNaN(+code) && +code != 0) { defer.resolve(+code); } @@ -527,52 +506,52 @@ function runVStest(testResultsDirectory: string, settingsFile: string, vsVersion defer.resolve(0); }) - .fail(function (code) { + .fail(function(code) { tl.debug("Test Run Updation failed!"); defer.resolve(1); }) - .finally(function () { + .finally(function() { cleanFiles(responseFile, listFile); tl.debug("Deleting the run id file" + runIdFile); tl.rmRF(runIdFile, true); }); }) - .fail(function (code) { + .fail(function(code) { defer.resolve(code); }) - .finally(function () { + .finally(function() { cleanFiles(responseFile, listFile); }); } else { responseContainsNoTests(responseFile) - .then(function (noTestsAvailable) { - if (noTestsAvailable) { + .then(function(noTestsAvailable) { + if (noTestsAvailable) { tl.debug("No tests impacted. Not running any tests."); uploadTestResults("") - .then(function (code) { + .then(function(code) { if (!isNaN(+code) && +code != 0) { defer.resolve(+code); - } + } defer.resolve(0); }) - .fail(function (code) { + .fail(function(code) { tl.debug("Test Run Updation failed!"); defer.resolve(1); }) - .finally(function () { + .finally(function() { cleanFiles(responseFile, listFile); tl.debug("Deleting the run id file" + runIdFile); tl.rmRF(runIdFile, true); }); - } + } else { updateResponseFile(getVstestArguments(settingsFile, true), responseFile) - .then(function (updatedFile) { + .then(function(updatedFile) { executeVstest(testResultsDirectory, settingsFile, vsVersion, ["@" + updatedFile]) - .then(function (vscode) { + .then(function(vscode) { uploadTestResults(testResultsDirectory) - .then(function (code) { + .then(function(code) { if (!isNaN(+code) && +code != 0) { defer.resolve(+code); } @@ -582,30 +561,30 @@ function runVStest(testResultsDirectory: string, settingsFile: string, vsVersion defer.resolve(0); }) - .fail(function (code) { + .fail(function(code) { tl.debug("Test Run Updation failed!"); defer.resolve(1); }) - .finally(function () { + .finally(function() { cleanFiles(responseFile, listFile); tl.debug("Deleting the run id file" + runIdFile); tl.rmRF(runIdFile, true); }); }) - .fail(function (code) { + .fail(function(code) { defer.resolve(code); }) - .finally(function () { + .finally(function() { cleanFiles(responseFile, listFile); }); }) - .fail(function (err) { + .fail(function(err) { tl.error(err); tl.warning(tl.loc('ErrorWhileUpdatingResponseFile', responseFile)); executeVstest(testResultsDirectory, settingsFile, vsVersion, getVstestArguments(settingsFile, false)) - .then(function (vscode) { + .then(function(vscode) { uploadTestResults(testResultsDirectory) - .then(function (code) { + .then(function(code) { if (!isNaN(+code) && +code != 0) { defer.resolve(+code); } @@ -615,19 +594,19 @@ function runVStest(testResultsDirectory: string, settingsFile: string, vsVersion defer.resolve(0); }) - .fail(function (code) { + .fail(function(code) { tl.debug("Test Run Updation failed!"); defer.resolve(1); }) - .finally(function () { + .finally(function() { cleanFiles(responseFile, listFile); tl.debug("Deleting the run id file" + runIdFile); tl.rmRF(runIdFile, true); }); }) - .fail(function (code) { + .fail(function(code) { defer.resolve(code); - }).finally(function () { + }).finally(function() { cleanFiles(responseFile, listFile); }); }); @@ -635,13 +614,13 @@ function runVStest(testResultsDirectory: string, settingsFile: string, vsVersion }); } }) - .fail(function (err) { + .fail(function(err) { tl.error(err); tl.warning(tl.loc('ErrorWhileCreatingResponseFile')); executeVstest(testResultsDirectory, settingsFile, vsVersion, getVstestArguments(settingsFile, false)) - .then(function (vscode) { + .then(function(vscode) { uploadTestResults(testResultsDirectory) - .then(function (code) { + .then(function(code) { if (!isNaN(+code) && +code != 0) { defer.resolve(+code); } @@ -651,35 +630,35 @@ function runVStest(testResultsDirectory: string, settingsFile: string, vsVersion defer.resolve(0); }) - .fail(function (code) { + .fail(function(code) { tl.debug("Test Run Updation failed!"); defer.resolve(1); }) - .finally(function () { + .finally(function() { tl.debug("Deleting the discovered tests file" + listFile); tl.rmRF(listFile, true); }); }) - .fail(function (code) { + .fail(function(code) { defer.resolve(code); }); }); }) - .fail(function (err) { + .fail(function(err) { tl.error(err); tl.warning(tl.loc('ErrorWhileListingDiscoveredTests')); defer.resolve(1); }); }) - .fail(function (err) { + .fail(function(err) { tl.error(err); tl.warning(tl.loc('ErrorWhilePublishingCodeChanges')); executeVstest(testResultsDirectory, settingsFile, vsVersion, getVstestArguments(settingsFile, false)) - .then(function (code) { + .then(function(code) { publishTestResults(testResultsDirectory); defer.resolve(code); }) - .fail(function (code) { + .fail(function(code) { defer.resolve(code); }); }); @@ -687,10 +666,10 @@ function runVStest(testResultsDirectory: string, settingsFile: string, vsVersion else { tl.debug("Non TIA mode of test execution"); executeVstest(testResultsDirectory, settingsFile, vsVersion, getVstestArguments(settingsFile, false)) - .then(function (code) { + .then(function(code) { defer.resolve(code); }) - .fail(function (code) { + .fail(function(code) { defer.resolve(code); }); } @@ -699,13 +678,13 @@ function runVStest(testResultsDirectory: string, settingsFile: string, vsVersion function invokeVSTest(testResultsDirectory: string): Q.Promise { var defer = Q.defer(); - if (vsTestVersion.toLowerCase() == "latest") { + if (vsTestVersion.toLowerCase() === "latest") { vsTestVersion = null; } overrideTestRunParametersIfRequired(runSettingsFile) - .then(function (overriddenSettingsFile) { + .then(function(overriddenSettingsFile) { locateVSVersion() - .then(function (vsVersion) { + .then(function(vsVersion) { try { vstestLocation = getVSTestLocation(vsVersion); let disableTIA = tl.getVariable("DisableTestImpactAnalysis"); @@ -716,45 +695,45 @@ function invokeVSTest(testResultsDirectory: string): Q.Promise { if ((sysDebug !== undefined && sysDebug.toLowerCase() === "true") || tiaEnabled) { vsTestVersionForTIA = getVsTestVersion(); - if (tiaEnabled && (vsTestVersionForTIA == null || (vsTestVersionForTIA[0] < 15 || (vsTestVersionForTIA[0] == 15 && vsTestVersionForTIA[1] == 0 && vsTestVersionForTIA[2] < 25727)))) { + if (tiaEnabled && (vsTestVersionForTIA === null || (vsTestVersionForTIA[0] < 15 || (vsTestVersionForTIA[0] === 15 && vsTestVersionForTIA[1] === 0 && vsTestVersionForTIA[2] < 25727)))) { tl.warning(tl.loc("VstestTIANotSupported")); tiaEnabled = false; } - } + } } catch (e) { tl.error(e.message); defer.resolve(1); return defer.promise; } setupSettingsFileForTestImpact(vsVersion, overriddenSettingsFile) - .then(function (runSettingswithTestImpact) { + .then(function(runSettingswithTestImpact) { setRunInParallellIfApplicable(vsVersion); setupRunSettingsFileForParallel(runInParallel, runSettingswithTestImpact) - .then(function (parallelRunSettingsFile) { + .then(function(parallelRunSettingsFile) { runVStest(testResultsDirectory, parallelRunSettingsFile, vsVersion) - .then(function (code) { + .then(function(code) { defer.resolve(code); }) - .fail(function (code) { + .fail(function(code) { defer.resolve(code); }); }) - .fail(function (err) { + .fail(function(err) { tl.error(err); defer.resolve(1); }); }) - .fail(function (err) { + .fail(function(err) { tl.error(err); defer.resolve(1); }); }) - .fail(function (err) { + .fail(function(err) { tl.error(err); defer.resolve(1); }); }) - .fail(function (err) { + .fail(function(err) { tl.error(err); defer.resolve(1); }); @@ -764,8 +743,8 @@ function invokeVSTest(testResultsDirectory: string): Q.Promise { function publishTestResults(testResultsDirectory: string) { if (testResultsDirectory) { - var allFilesInResultsDirectory = tl.find(testResultsDirectory); - var resultFiles = tl.match(allFilesInResultsDirectory, path.join(testResultsDirectory, "*.trx"), { matchBase: true }); + let resultFiles = tl.findMatch(testResultsDirectory, path.join(testResultsDirectory, "*.trx")); + if (resultFiles && resultFiles.length != 0) { var tp = new tl.TestPublisher("VSTest"); tp.publish(resultFiles, "false", platform, configuration, testRunTitle, publishRunAttachments); @@ -777,15 +756,6 @@ function publishTestResults(testResultsDirectory: string) { } } -function getFilteredFiles(filesFilter: string, allFiles: string[]): string[] { - if (os.type().match(/^Win/)) { - return tl.match(allFiles, filesFilter, { matchBase: true, nocase: true }); - } - else { - return tl.match(allFiles, filesFilter, { matchBase: true }); - } -} - function cleanUp(temporarySettingsFile: string) { //cleanup the runsettings file if (temporarySettingsFile && runSettingsFile != temporarySettingsFile) { @@ -800,7 +770,7 @@ function cleanUp(temporarySettingsFile: string) { function overrideTestRunParametersIfRequired(settingsFile: string): Q.Promise { var defer = Q.defer(); - if (!settingsFile || !pathExistsAsFile(settingsFile) || !overrideTestrunParameters || overrideTestrunParameters.trim().length == 0) { + if (!settingsFile || !pathExistsAsFile(settingsFile) || !overrideTestrunParameters || overrideTestrunParameters.trim().length === 0) { defer.resolve(settingsFile); return defer.promise; } @@ -809,9 +779,9 @@ function overrideTestRunParametersIfRequired(settingsFile: string): Q.Promise 0) { var resultDirectory = result.RunSettings.RunConfiguration[0].ResultsDirectory[0]; @@ -914,7 +884,7 @@ function getTestResultsDirectory(settingsFile: string, defaultResultsDirectory: } }); }) - .fail(function (err) { + .fail(function(err) { tl.debug("Error occured while reading test result directory from run settings. Continuing...") tl.warning(err); defer.resolve(defaultResultsDirectory); @@ -967,38 +937,28 @@ function pushImpactLevelAndRootPathIfNotFound(dataCollectorArray): void { dataCollectorArray[i] = { Configuration: {} }; } if (dataCollectorArray[i].Configuration.TestImpact && !dataCollectorArray[i].Configuration.RootPath) { - if (context && context == "CD") - { + if (context && context === "CD") { dataCollectorArray[i].Configuration = { RootPath: "" }; - } - else{ + } else { dataCollectorArray[i].Configuration = { RootPath: sourcesDir }; } - } - else if (!dataCollectorArray[i].Configuration.TestImpact && dataCollectorArray[i].Configuration.RootPath) { - if (getTIALevel() == 'file') { + } else if (!dataCollectorArray[i].Configuration.TestImpact && dataCollectorArray[i].Configuration.RootPath) { + if (getTIALevel() === 'file') { dataCollectorArray[i].Configuration = { ImpactLevel: getTIALevel(), LogFilePath: 'true' }; - } - else { + } else { dataCollectorArray[i].Configuration = { ImpactLevel: getTIALevel() }; } - } - else if (dataCollectorArray[i].Configuration && !dataCollectorArray[i].Configuration.TestImpact && !dataCollectorArray[i].Configuration.RootPath) { - if (context && context == "CD") - { - if (getTIALevel() == 'file') { + } else if (dataCollectorArray[i].Configuration && !dataCollectorArray[i].Configuration.TestImpact && !dataCollectorArray[i].Configuration.RootPath) { + if (context && context === "CD") { + if (getTIALevel() === 'file') { dataCollectorArray[i].Configuration = { ImpactLevel: getTIALevel(), LogFilePath: 'true', RootPath: "" }; - } - else { + } else { dataCollectorArray[i].Configuration = { ImpactLevel: getTIALevel(), RootPath: "" }; - } - } - else - { - if (getTIALevel() == 'file') { - dataCollectorArray[i].Configuration = { ImpactLevel: getTIALevel(), LogFilePath: 'true', RootPath: sourcesDir }; } - else { + } else { + if (getTIALevel() === 'file') { + dataCollectorArray[i].Configuration = { ImpactLevel: getTIALevel(), LogFilePath: 'true', RootPath: sourcesDir }; + } else { dataCollectorArray[i].Configuration = { ImpactLevel: getTIALevel(), RootPath: sourcesDir }; } } @@ -1015,15 +975,11 @@ function pushImpactLevelAndRootPathIfNotFound(dataCollectorArray): void { } } -function roothPathGenerator() : any -{ - if (context) - { - if (context == "CD") - { +function roothPathGenerator(): any { + if (context) { + if (context === "CD") { return { ImpactLevel: getTIALevel(), RootPath: "" }; - } - else{ + } else { return { ImpactLevel: getTIALevel(), RootPath: sourcesDir }; } } @@ -1033,7 +989,7 @@ function updateRunSettings(result: any, vsVersion: number) { var dataCollectorNode = null; if (!result.RunSettings) { tl.debug("Updating runsettings file from RunSettings node"); - result.RunSettings = { DataCollectionRunSettings: { DataCollectors: { DataCollector: { Configuration: roothPathGenerator()} } } }; + result.RunSettings = { DataCollectionRunSettings: { DataCollectors: { DataCollector: { Configuration: roothPathGenerator() } } } }; dataCollectorNode = result.RunSettings.DataCollectionRunSettings.DataCollectors.DataCollector; } else if (!result.RunSettings.DataCollectionRunSettings) { @@ -1079,9 +1035,9 @@ function updateRunSettingsFileForTestImpact(vsVersion: number, settingsFile: str var defer = Q.defer(); tl.debug("Adding test impact data collector element to runsettings file provided."); readFileContents(settingsFile, "utf-8") - .then(function (xmlContents) { + .then(function(xmlContents) { var parser = new xml2js.Parser(); - parser.parseString(xmlContents, function (err, result) { + parser.parseString(xmlContents, function(err, result) { if (err) { tl.warning(tl.loc('ErrorWhileReadingRunSettings', err)); tl.debug(exitErrorMessage); @@ -1095,13 +1051,13 @@ function updateRunSettingsFileForTestImpact(vsVersion: number, settingsFile: str } updateRunSettings(result, vsVersion); writeXmlFile(result, settingsFile, runSettingsExt, exitErrorMessage) - .then(function (filename) { + .then(function(filename) { defer.resolve(filename); return defer.promise; }); }); }) - .fail(function (err) { + .fail(function(err) { tl.warning(err); tl.debug(exitErrorMessage); defer.resolve(settingsFile); @@ -1169,12 +1125,12 @@ function writeXmlFile(result: any, settingsFile: string, fileExt: string, exitEr var builder = new xml2js.Builder(); var runSettingsForTestImpact = builder.buildObject(result); saveToFile(runSettingsForTestImpact, fileExt) - .then(function (fileName) { + .then(function(fileName) { cleanUp(settingsFile); defer.resolve(fileName); return defer.promise; }) - .fail(function (err) { + .fail(function(err) { tl.debug(exitErrorMessage); tl.warning(err); defer.resolve(settingsFile); @@ -1186,9 +1142,9 @@ function updateTestSettingsFileForTestImpact(vsVersion: number, settingsFile: st var defer = Q.defer(); tl.debug("Adding test impact data collector element to testsettings file provided."); readFileContents(settingsFile, "utf-8") - .then(function (xmlContents) { + .then(function(xmlContents) { var parser = new xml2js.Parser(); - parser.parseString(xmlContents, function (err, result) { + parser.parseString(xmlContents, function(err, result) { if (err) { tl.warning(tl.loc('ErrorWhileReadingTestSettings', err)); tl.debug(exitErrorMessage); @@ -1202,13 +1158,13 @@ function updateTestSettingsFileForTestImpact(vsVersion: number, settingsFile: st } updatTestSettings(result, vsVersion); writeXmlFile(result, settingsFile, testSettingsExt, exitErrorMessage) - .then(function (filename) { + .then(function(filename) { defer.resolve(filename); return defer.promise; }); }); }) - .fail(function (err) { + .fail(function(err) { tl.warning(err); tl.debug(exitErrorMessage); defer.resolve(settingsFile); @@ -1235,22 +1191,22 @@ function createRunSettingsForTestImpact(vsVersion: number, settingsFile: string, '' + '' + getTIALevel() + ''; - if (getTIALevel() == 'file') { + if (getTIALevel() === 'file') { runSettingsForTIA = runSettingsForTIA + '' + 'true' + ''; } runSettingsForTIA = runSettingsForTIA + - '' + (context == "CD" ? "" : sourcesDir) + '' + + '' + (context === "CD" ? "" : sourcesDir) + '' + '' + '' + ''; saveToFile(runSettingsForTIA, runSettingsExt) - .then(function (fileName) { + .then(function(fileName) { defer.resolve(fileName); return defer.promise; }) - .fail(function (err) { + .fail(function(err) { tl.debug(exitErrorMessage); tl.warning(err); defer.resolve(settingsFile); @@ -1262,23 +1218,23 @@ function setupSettingsFileForTestImpact(vsVersion: number, settingsFile: string) var defer = Q.defer(); var exitErrorMessage = "Error occured while setting in test impact data collector. Continuing..."; if (isTiaAllowed()) { - if (settingsFile && settingsFile.split('.').pop().toLowerCase() == "testsettings") { + if (settingsFile && settingsFile.split('.').pop().toLowerCase() === "testsettings") { updateTestSettingsFileForTestImpact(vsVersion, settingsFile, exitErrorMessage) - .then(function (updatedFile) { + .then(function(updatedFile) { defer.resolve(updatedFile); return defer.promise; }); } else if (!settingsFile || settingsFile.split('.').pop().toLowerCase() != "runsettings" || !pathExistsAsFile(settingsFile)) { createRunSettingsForTestImpact(vsVersion, settingsFile, exitErrorMessage) - .then(function (updatedFile) { + .then(function(updatedFile) { defer.resolve(updatedFile); return defer.promise; }); } else { updateRunSettingsFileForTestImpact(vsVersion, settingsFile, exitErrorMessage) - .then(function (updatedFile) { + .then(function(updatedFile) { defer.resolve(updatedFile); return defer.promise; }); @@ -1295,7 +1251,7 @@ function setupRunSettingsFileForParallel(runInParallel: boolean, settingsFile: s var defer = Q.defer(); var exitErrorMessage = "Error occured while setting run in parallel. Continuing..."; if (runInParallel) { - if (settingsFile && settingsFile.split('.').pop().toLowerCase() == "testsettings") { + if (settingsFile && settingsFile.split('.').pop().toLowerCase() === "testsettings") { tl.warning(tl.loc('RunInParallelNotSupported')); defer.resolve(settingsFile); return defer.promise; @@ -1305,11 +1261,11 @@ function setupRunSettingsFileForParallel(runInParallel: boolean, settingsFile: s tl.debug("No settings file provided or the provided settings file does not exist."); var runSettingsForParallel = '0'; saveToFile(runSettingsForParallel, runSettingsExt) - .then(function (fileName) { + .then(function(fileName) { defer.resolve(fileName); return defer.promise; }) - .fail(function (err) { + .fail(function(err) { tl.debug(exitErrorMessage); tl.warning(err); defer.resolve(settingsFile); @@ -1318,9 +1274,9 @@ function setupRunSettingsFileForParallel(runInParallel: boolean, settingsFile: s else { tl.debug("Adding maxcpucount element to runsettings file provided."); readFileContents(settingsFile, "utf-8") - .then(function (xmlContents) { + .then(function(xmlContents) { var parser = new xml2js.Parser(); - parser.parseString(xmlContents, function (err, result) { + parser.parseString(xmlContents, function(err, result) { if (err) { tl.warning(tl.loc('ErrorWhileReadingRunSettings', err)); tl.debug(exitErrorMessage); @@ -1348,19 +1304,19 @@ function setupRunSettingsFileForParallel(runInParallel: boolean, settingsFile: s var builder = new xml2js.Builder(); var runSettingsForParallel = builder.buildObject(result); saveToFile(runSettingsForParallel, runSettingsExt) - .then(function (fileName) { + .then(function(fileName) { cleanUp(settingsFile); defer.resolve(fileName); return defer.promise; }) - .fail(function (err) { + .fail(function(err) { tl.debug(exitErrorMessage); tl.warning(err); defer.resolve(settingsFile); }); }); }) - .fail(function (err) { + .fail(function(err) { tl.warning(err); tl.debug(exitErrorMessage); defer.resolve(settingsFile); @@ -1377,7 +1333,7 @@ function setupRunSettingsFileForParallel(runInParallel: boolean, settingsFile: s function saveToFile(fileContents: string, extension: string): Q.Promise { var defer = Q.defer(); var tempFile = path.join(os.tmpdir(), uuid.v1() + extension); - fs.writeFile(tempFile, fileContents, function (err) { + fs.writeFile(tempFile, fileContents, function(err) { if (err) { defer.reject(err); } @@ -1427,7 +1383,7 @@ function locateVSVersion(): Q.Promise { return defer.promise; } var regPath = "HKLM\\SOFTWARE\\Microsoft\\VisualStudio"; - regedit.list(regPath).on('data', function (entry) { + regedit.list(regPath).on('data', function(entry) { if (entry && entry.data && entry.data.keys) { var subkeys = entry.data.keys; var versions = getFloatsFromStringArray(subkeys); @@ -1458,7 +1414,7 @@ function getFloatsFromStringArray(inputArray: string[]): number[] { function setRegistryKeyForParallelExecution(vsVersion: number) { var regKey = "HKCU\\SOFTWARE\\Microsoft\\VisualStudio\\" + vsVersion.toFixed(1) + "_Config\\FeatureFlags\\TestingTools\\UnitTesting\\Taef"; - regedit.createKey(regKey, function (err) { + regedit.createKey(regKey, function(err) { if (!err) { var values = { [regKey]: { @@ -1468,7 +1424,7 @@ function setRegistryKeyForParallelExecution(vsVersion: number) { } } }; - regedit.putValue(values, function (err) { + regedit.putValue(values, function(err) { if (err) { tl.warning(tl.loc('ErrorOccuredWhileSettingRegistry', err)); } @@ -1517,15 +1473,15 @@ function isTiaAllowed(): boolean { } function getTIALevel() { - if (fileLevel && fileLevel.toUpperCase() == "FALSE") { + if (fileLevel && fileLevel.toUpperCase() === "FALSE") { return "method"; } return "file"; } function responseContainsNoTests(filePath: string): Q.Promise { - return readFileContents(filePath, "utf-8").then(function (resp) { - if (resp == "/Tests:") { + return readFileContents(filePath, "utf-8").then(function(resp) { + if (resp === "/Tests:") { return true; } else { @@ -1533,3 +1489,10 @@ function responseContainsNoTests(filePath: string): Q.Promise { } }); } + +function isNullOrWhitespace(input) { + if (typeof input === 'undefined' || input === null) { + return true; + } + return input.replace(/\s/g, '').length < 1; +} \ No newline at end of file diff --git a/Tasks/WindowsMachineFileCopy/Tests/L0.ts b/Tasks/WindowsMachineFileCopy/Tests/L0.ts new file mode 100644 index 000000000000..ec0c44136cf0 --- /dev/null +++ b/Tasks/WindowsMachineFileCopy/Tests/L0.ts @@ -0,0 +1,66 @@ +/// +/// +/// + + +import Q = require('q'); +import assert = require('assert'); +import path = require('path'); + +var psm = require('../../../Tests/lib/psRunner'); +var shell = require('shelljs'); +var ps = shell.which('powershell.exe'); +var psr = null; + +describe('WindowsMachineFileCopy Suite', function () { + this.timeout(20000); + + before((done) => { + if (ps) { + psr = new psm.PSRunner(); + psr.start(); + } + + done(); + }); + + after(function () { + psr.kill(); + }); + + if(ps) { + it('Throw error if Source Path is invalid or empty', (done) => { + psr.run(path.join(__dirname, 'L0ValidateSourcePath.ps1'), done); + }); + it('Throw error if Destination Path is invalid or empty', (done) => { + psr.run(path.join(__dirname, 'L0ValidateDestinationPath.ps1'), done); + }); + it('Should copy on local machine when no machine name is given', (done) => { + psr.run(path.join(__dirname, 'L0ShouldCopyOnLocalMachine.ps1'), done); + }); + it('Validate Get-ResourcesProperties Utility', (done) => { + psr.run(path.join(__dirname, 'L0GetResourcesProperties.ps1'), done); + }); + it('Validate Get-ResourceConnectionDetails Utility', (done) => { + psr.run(path.join(__dirname, 'L0GetResourceConnectionDetails.ps1'), done); + }); + it('Throw Error for invalid machine names', (done) => { + psr.run(path.join(__dirname, 'L0InvalidEnvironmentResource.ps1'), done); + }); + it('Throw Error if Copy Files To Target Machine fails', (done) => { + psr.run(path.join(__dirname, 'L0SequentialCopyFail.ps1'), done); + }); + it('Performs Sequential copy on all machines and works correctly for valid input', (done) => { + psr.run(path.join(__dirname, 'L0ValidInputSequentialCopy.ps1'), done); + }); + it('Performs Parallel copy on all machines and works correctly for valid input', (done) => { + psr.run(path.join(__dirname, 'L0ValidInputParallelCopy.ps1'), done); + }); + it('Throw error if job fails for resource in Parallel Copy', (done) => { + psr.run(path.join(__dirname, 'L0ParallelCopyFail.ps1'), done); + }); + } + else { + console.warn('Cannot run tests for WindowsMachineFileCopy on Non-Windows Platform'); + } +}); \ No newline at end of file diff --git a/Tasks/WindowsMachineFileCopy/Tests/L0GetResourceConnectionDetails.ps1 b/Tasks/WindowsMachineFileCopy/Tests/L0GetResourceConnectionDetails.ps1 new file mode 100644 index 000000000000..8ea85d718211 --- /dev/null +++ b/Tasks/WindowsMachineFileCopy/Tests/L0GetResourceConnectionDetails.ps1 @@ -0,0 +1,26 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 +. $PSScriptRoot\MockVariable.ps1 -Force + +. $PSScriptRoot\..\Utility.ps1 + +Register-Mock Get-ResourceCredentials { } + +Register-Mock Get-EnvironmentProperty { throw "No property invalidResourcePropertyKeyName found." } -ParametersEvaluator{$ResourceId -eq $machineIdForNoResouceProperty} + +Assert-Throws { + Get-ResourceConnectionDetails -envName "envName" -resource $resourceFailForNoProperty +} -MessagePattern "No property invalidResourcePropertyKeyName found." +Assert-WasCalled Get-EnvironmentProperty -Times 1 + +Register-Mock Get-EnvironmentProperty { return $validMachineName1 } -ParametersEvaluator {$Key -eq $resourceFQDNKeyName -and $ResourceId -eq $validMachineId1} + +Get-ResourceConnectionDetails -envName "envName" -resource $validResource1 +Assert-WasCalled Get-EnvironmentProperty -Times 1 -ParametersEvaluator {$Key -eq $resourceFQDNKeyName -and $ResourceId -eq $validMachineId1} + +Register-Mock Get-EnvironmentProperty { return $validMachineName2 } -ParametersEvaluator {$Key -eq $resourceFQDNKeyName -and $ResourceId -eq $validMachineId2} + +Get-ResourceConnectionDetails -envName "envName" -resource $validResource2 +Assert-WasCalled Get-EnvironmentProperty -Times 1 -ParametersEvaluator {$Key -eq $resourceFQDNKeyName -and $ResourceId -eq $validMachineId2} diff --git a/Tasks/WindowsMachineFileCopy/Tests/L0GetResourcesProperties.ps1 b/Tasks/WindowsMachineFileCopy/Tests/L0GetResourcesProperties.ps1 new file mode 100644 index 000000000000..5363781bbb9b --- /dev/null +++ b/Tasks/WindowsMachineFileCopy/Tests/L0GetResourcesProperties.ps1 @@ -0,0 +1,18 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 +. $PSScriptRoot\MockVariable.ps1 -Force + +. $PSScriptRoot\..\Utility.ps1 + +Register-Mock Get-ResourceCredentials { } + +Register-Mock Get-EnvironmentProperty { return $validMachineName2 } -ParametersEvaluator {$Key -eq $resourceFQDNKeyName -and $ResourceId -eq $validMachineId2} +Register-Mock Get-EnvironmentProperty { return $validMachineName1 } -ParametersEvaluator {$Key -eq $resourceFQDNKeyName -and $ResourceId -eq $validMachineId1} + +Get-ResourcesProperties -envName "envName" -resources $validResources + +Assert-WasCalled Get-EnvironmentProperty -Times 2 +Assert-WasCalled Get-EnvironmentProperty -Times 1 -ParametersEvaluator {$Key -eq $resourceFQDNKeyName -and $ResourceId -eq $validMachineId1} +Assert-WasCalled Get-EnvironmentProperty -Times 1 -ParametersEvaluator {$Key -eq $resourceFQDNKeyName -and $ResourceId -eq $validMachineId2} \ No newline at end of file diff --git a/Tasks/WindowsMachineFileCopy/Tests/L0InvalidEnvironmentResource.ps1 b/Tasks/WindowsMachineFileCopy/Tests/L0InvalidEnvironmentResource.ps1 new file mode 100644 index 000000000000..fe54db697967 --- /dev/null +++ b/Tasks/WindowsMachineFileCopy/Tests/L0InvalidEnvironmentResource.ps1 @@ -0,0 +1,29 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 +. $PSScriptRoot\MockVariable.ps1 -Force +. $PSScriptRoot\MockHelper.ps1 -Force + +$invalidEnvironmentWithNoResource = "invalidEnvironmentWithNoResource" + +#TODO : Mocked Modules - Move to Common Test Folder + +Unregister-Mock Get-EnvironmentProperty +Register-Mock Get-EnvironmentProperty { } + +Register-Mock Get-EnvironmentResources { throw "No resources found" } -ParametersEvaluator{$EnvironmentName -eq $invalidEnvironmentWithNoResource} +Register-Mock Register-Environment { return GetEnvironmentWithStandardProvider $invalidEnvironmentWithNoResource } -ParametersEvaluator{$EnvironmentName -eq $invalidEnvironmentWithNoResource} + +Assert-Throws { + & "$copyFilesToMachinesPath" -environmentName $invalidEnvironmentWithNoResource -machineNames $invalidInputMachineNames -sourcePath $validSourcePackage -targetPath $validApplicationPath -cleanTargetBeforeCopy $true -copyFilesInParallel $false +} -MessagePattern "No resources found" + +Assert-WasCalled Get-EnvironmentProperty -Times 0 + +Unregister-Mock Get-EnvironmentResources +Register-Mock Get-EnvironmentResources { return $validResources } -ParametersEvaluator {$EnvironmentName -eq $validEnvironmentName} + +& "$copyFilesToMachinesPath" -environmentName $validEnvironmentName -resourceFilteringMethod "tags" -machineNames "" -sourcePath $validSourcePackage -targetPath $validApplicationPath -cleanTargetBeforeCopy $true -copyFilesInParallel $false + +Assert-WasCalled Get-EnvironmentResources -Times 1 -ParametersEvaluator {$validEnvironmentName -eq $validEnvironmentName} \ No newline at end of file diff --git a/Tasks/WindowsMachineFileCopy/Tests/L0ParallelCopyFail.ps1 b/Tasks/WindowsMachineFileCopy/Tests/L0ParallelCopyFail.ps1 new file mode 100644 index 000000000000..82682cd4b024 --- /dev/null +++ b/Tasks/WindowsMachineFileCopy/Tests/L0ParallelCopyFail.ps1 @@ -0,0 +1,37 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 +. $PSScriptRoot\MockVariable.ps1 -Force +. $PSScriptRoot\MockHelper.ps1 -Force + +Register-Mock Get-EnvironmentResources { return $validResources } -ParametersEvaluator{$EnvironmentName -eq $EnvironmentNameForFailedJob} + +Register-Mock Get-EnvironmentProperty { return $validMachineName1 } -ParametersEvaluator {$Key -eq $resourceFQDNKeyName -and $ResourceId -eq $validMachineId1} +Register-Mock Get-EnvironmentProperty { return $validMachineName2 } -ParametersEvaluator {$Key -eq $resourceFQDNKeyName -and $ResourceId -eq $validMachineId2} + +Register-Mock Receive-Job { } -ParametersEvaluator { $Id -eq 1 } +Register-Mock Receive-Job { throw "Copy to one or more machines failed." } -ParametersEvaluator { $Id -eq 2 } + +#Start-Job Register-Mocks +Register-Mock Start-Job { $testJobs.Add($Job1); return $job1} -ParametersEvaluator{$ArgumentList -contains $validResource1.Name } +Register-Mock Start-Job { $testJobs.Add($Job2); return $job2} -ParametersEvaluator{$ArgumentList -contains $validResource1Duplicate.Name -and $ArgumentList -contains $environmentWinRMHttpPortForDuplicateResource } +Register-Mock Start-Job { $testJobs.Add($Job2); return $job2} -ParametersEvaluator{$ArgumentList -contains $validResource2.Name } + +#Get-Job Register-Mocks +Register-Mock Get-Job { return $testJobs } + +#Start-Sleep Register-Mocks +Register-Mock Start-Sleep { } + +#Remove-Job Register-Mocks +Register-Mock Remove-Job { $testJobs.RemoveAt(0) } + +Register-Mock Register-Environment { return GetEnvironmentWithStandardProvider $EnvironmentNameForFailedJob } -ParametersEvaluator{$EnvironmentName -eq $EnvironmentNameForFailedJob} + +#Import-Module Register-Mocks +Register-Mock Import-Module { } + +Assert-Throws { + & "$copyFilesToMachinesPath" -environmentName $EnvironmentNameForFailedJob -machineNames $validMachineNames -sourcePath $validSourcePackage -targetPath $validApplicationPath -cleanTargetBeforeCopy $false -copyFilesInParallel $true +} -MessagePattern "Copy to one or more machines failed." diff --git a/Tasks/WindowsMachineFileCopy/Tests/L0SequentialCopyFail.ps1 b/Tasks/WindowsMachineFileCopy/Tests/L0SequentialCopyFail.ps1 new file mode 100644 index 000000000000..58c512278f6d --- /dev/null +++ b/Tasks/WindowsMachineFileCopy/Tests/L0SequentialCopyFail.ps1 @@ -0,0 +1,21 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 +. $PSScriptRoot\MockVariable.ps1 -Force +. $PSScriptRoot\MockHelper.ps1 -Force + + +$invalidEnvironmentWithNoResource = "invalidEnvironmentWithNoResource" + +Register-Mock Get-EnvironmentProperty { return $validResources } -ParametersEvaluator {$EnvironmentName -eq $invalidEnvironmentNameForFailCopy} +Register-Mock Get-EnvironmentResources { return $resourceFailForCopy } -ParametersEvaluator {$EnvironmentName -eq $invalidEnvironmentNameForFailCopy} + +Unregister-Mock Invoke-Command +Register-Mock Invoke-Command { throw "$FailedCopyError" } + +Register-Mock Register-Environment { return GetEnvironmentWithStandardProvider $invalidEnvironmentNameForFailCopy } -ParametersEvaluator{$EnvironmentName -eq $invalidEnvironmentNameForFailCopy} + +Assert-Throws { + & "$copyFilesToMachinesPath" -environmentName $invalidEnvironmentNameForFailCopy -machineNames $validMachineNames -sourcePath $validSourcePackage -targetPath $validApplicationPath -cleanTargetBeforeCopy $true -copyFilesInParallel $false +} -MessagePattern "$FailedCopyError" diff --git a/Tasks/WindowsMachineFileCopy/Tests/L0ShouldCopyOnLocalMachine.ps1 b/Tasks/WindowsMachineFileCopy/Tests/L0ShouldCopyOnLocalMachine.ps1 new file mode 100644 index 000000000000..ac6a298c7aff --- /dev/null +++ b/Tasks/WindowsMachineFileCopy/Tests/L0ShouldCopyOnLocalMachine.ps1 @@ -0,0 +1,18 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 +. $PSScriptRoot\MockVariable.ps1 -Force + +. $PSScriptRoot\..\Utility.ps1 +. $PSScriptRoot\..\WindowsMachineFileCopyJob.ps1 + +Register-Mock Invoke-Command { } + +Copy-OnLocalMachine -sourcePath $validSourcePackage -targetPath $validApplicationPath -adminUserName $userName -adminPassword $password ` + -cleanTargetBeforeCopy $true -additionalArguments "" + +Assert-WasCalled Invoke-Command -Times 1 -ParametersEvaluator { + $ScriptBlock -eq $CopyJob -and $ArgumentList -contains $validSourcePackage -and $ArgumentList -contains $validApplicationPath -and ` + $ArgumentList -contains $true +} \ No newline at end of file diff --git a/Tasks/WindowsMachineFileCopy/Tests/L0ValidInputParallelCopy.ps1 b/Tasks/WindowsMachineFileCopy/Tests/L0ValidInputParallelCopy.ps1 new file mode 100644 index 000000000000..2fb6dc1e188a --- /dev/null +++ b/Tasks/WindowsMachineFileCopy/Tests/L0ValidInputParallelCopy.ps1 @@ -0,0 +1,36 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 +. $PSScriptRoot\MockVariable.ps1 -Force +. $PSScriptRoot\MockHelper.ps1 -Force + +Register-Mock Get-EnvironmentResources { return $validResources } -ParametersEvaluator {$EnvironmentName -eq $validEnvironmentName} + +Register-Mock Register-Environment { return GetEnvironmentWithStandardProvider $validEnvironmentName } -ParametersEvaluator{$EnvironmentName -eq $validEnvironmentName} + + +Register-Mock Get-EnvironmentProperty { return $validMachineName1 } -ParametersEvaluator {$Key -eq $resourceFQDNKeyName -and $ResourceId -eq $validMachineId1} +Register-Mock Get-EnvironmentProperty { return $validMachineName2 } -ParametersEvaluator {$Key -eq $resourceFQDNKeyName -and $ResourceId -eq $validMachineId2} + +#Start-Job Register-Mocks +Register-Mock Start-Job { $testJobs.Add($Job1); return $job1} -ParametersEvaluator{$ArgumentList -contains $validResource1.Name } +Register-Mock Start-Job { $testJobs.Add($Job2); return $job2} -ParametersEvaluator{$ArgumentList -contains $validResource2.Name } + +#Get-Job Register-Mocks +Register-Mock Get-Job { return $testJobs } + +#Start-Sleep Register-Mocks +Register-Mock Start-Sleep { } + +#Receive-Job Register-Mocks +Register-Mock Receive-Job { return $JobPassResponse} + +#Remove-Job Register-Mocks +Register-Mock Remove-Job { $testJobs.RemoveAt(0) } + +#Import-Module Register-Mocks +Register-Mock Import-Module { } + +#should not throw error +& "$copyFilesToMachinesPath" -environmentName $validEnvironmentName -machineNames $validMachineNames -sourcePath $validSourcePackage -targetPath $validApplicationPath -cleanTargetBeforeCopy $true -copyFilesInParallel $true \ No newline at end of file diff --git a/Tasks/WindowsMachineFileCopy/Tests/L0ValidInputSequentialCopy.ps1 b/Tasks/WindowsMachineFileCopy/Tests/L0ValidInputSequentialCopy.ps1 new file mode 100644 index 000000000000..5c0ef0f9b0a3 --- /dev/null +++ b/Tasks/WindowsMachineFileCopy/Tests/L0ValidInputSequentialCopy.ps1 @@ -0,0 +1,14 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 +. $PSScriptRoot\MockVariable.ps1 -Force +. $PSScriptRoot\MockHelper.ps1 -Force + +Register-Mock Register-Environment { return GetEnvironmentWithStandardProvider $validEnvironmentName } -ParametersEvaluator {$EnvironmentName -eq $validEnvironmentName} +Register-Mock Get-EnvironmentResources { return $validResources } -ParametersEvaluator {$EnvironmentName -eq $validEnvironmentName} +Register-Mock Get-EnvironmentProperty { return $validResources } -ParametersEvaluator {$EnvironmentName -eq $validEnvironmentName} + +& "$copyFilesToMachinesPath" -environmentName $validEnvironmentName -machineNames $validMachineNames -sourcePath $validSourcePackage -targetPath $validApplicationPath -cleanTargetBeforeCopy $true -copyFilesInParallel $false + +Assert-WasCalled Invoke-Command -Times 2 \ No newline at end of file diff --git a/Tasks/WindowsMachineFileCopy/Tests/L0ValidateDestinationPath.ps1 b/Tasks/WindowsMachineFileCopy/Tests/L0ValidateDestinationPath.ps1 new file mode 100644 index 000000000000..8923c3146e73 --- /dev/null +++ b/Tasks/WindowsMachineFileCopy/Tests/L0ValidateDestinationPath.ps1 @@ -0,0 +1,17 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 +. $PSScriptRoot\MockVariable.ps1 -Force + +. $PSScriptRoot\..\Utility.ps1 + +Register-Mock Get-ResourceFQDNTagKey { return $validResourceFQDNKeyName } + +Assert-Throws { + Validate-DestinationPath -value "" -environmentName $validEnvironmentName +} -Message "Parameter 'targetPath' cannot be null or empty." + +Assert-Throws { + Validate-DestinationPath -value $invalidTargetPath -environmentName $validEnvironmentName +} -Message "Remote destination path '$invalidTargetPath' cannot contain environment variables." diff --git a/Tasks/WindowsMachineFileCopy/Tests/L0ValidateSourcePath.ps1 b/Tasks/WindowsMachineFileCopy/Tests/L0ValidateSourcePath.ps1 new file mode 100644 index 000000000000..cc9b11981aa1 --- /dev/null +++ b/Tasks/WindowsMachineFileCopy/Tests/L0ValidateSourcePath.ps1 @@ -0,0 +1,16 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1 +. $PSScriptRoot\..\Utility.ps1 + +$invalidSourcePath = "Invalid" +Register-Mock Test-Path { return $false } -ParametersEvaluator { $LiteralPath -eq $invalidSourcePath } + +Assert-Throws { + Validate-SourcePath -value "" +} -MessagePattern "Parameter 'sourcePath' cannot be null or empty." + +Assert-Throws { + Validate-SourcePath -value "$invalidSourcePath" +} -MessagePattern "Source path '$invalidSourcePath' does not exist." \ No newline at end of file diff --git a/Tasks/WindowsMachineFileCopy/Tests/MockHelper.ps1 b/Tasks/WindowsMachineFileCopy/Tests/MockHelper.ps1 new file mode 100644 index 000000000000..06185773b3ce --- /dev/null +++ b/Tasks/WindowsMachineFileCopy/Tests/MockHelper.ps1 @@ -0,0 +1,13 @@ +function GetEnvironmentWithStandardProvider( + [string]$environmentName) +{ + return @{ "Name" = $environmentName } +} + +Register-Mock Test-Path { return $true } -ParametersEvaluator{ $LiteralPath -eq $validSourcePackage } +Register-Mock Test-Path { return $false } -ParametersEvaluator { $LiteralPath -eq $invalidSourcePath } +Register-Mock Get-ResourceFQDNTagKey { return $validResourceFQDNKeyName } +Register-Mock Get-VssConnection { return $null } + +Register-Mock Invoke-Command { } +Register-Mock Get-ResourceCredentials { } diff --git a/Tasks/WindowsMachineFileCopy/Tests/MockVariable.ps1 b/Tasks/WindowsMachineFileCopy/Tests/MockVariable.ps1 new file mode 100644 index 000000000000..3d3c27eaa2ca --- /dev/null +++ b/Tasks/WindowsMachineFileCopy/Tests/MockVariable.ps1 @@ -0,0 +1,126 @@ +# Input Parameters +$validResourceFQDNKeyName = 'Microsoft-Vslabs-MG-Resource-FQDN' +$validResourceWinRMHttpPortKeyName = 'WinRM_Http' +$validResourceWinRMHttpsPortKeyName = 'WinRM_Https' +$validSkipCACheckKeyName = 'Microsoft-Vslabs-MG-SkipCACheck' + +$validEnvironmentName = "Test" +$validEnvironmentNameWithNoVm = "validEnvironmentNameWithNoVm" +$validEnvironmentNameWithDuplicateResourceName = "validEnvironmentNameWithDuplicateVmName" +$invalidEnvironmentWithNoResource = "invalidEnvironmentWithNoResource" + +$validMachineName1 = "Test1" +$validMachineName2 = "Test2" +$validMachineId1 = "18" +$validMachineId2 = "19" +$validMachineId1Duplicate = "23" +$emptyInputMachineName = "" +$validMachineNames = $validMachineName1 + ", " + $validMachineName2 +$testPath = Join-Path $env:windir "Test" +$powershellScriptPath = Join-Path $testPath 'powershell.ps1' +$validScriptPath = $powershellScriptPath +$validInitializationScriptPath = $powershellScriptPath +$assembly = New-Object System.Collections.Generic.List``1[System.Object] +$testJobs = New-Object System.Collections.Generic.List``1[System.Object] +$userName = "UserName" +$password = "Password" +$winRmProtocol = "HTTPS" + +#Invalid Input Parameters +$invalidInputEnvironmentName = "Invalid" +$invalidEnvironmentNameForFailCopy = "CopyFail" +$invalidEnvironmentNameForFailDeploy = "DeployFail" +$invalidEnvironmentNameWithNoUsername = "UsernameFail" +$invalidEnvironmentNameForNoResourceProperty = "CopyFailWithNoResourceProperty" +$environmentWithSkipCASet = "envWithSkipCAEnabled" +$environmentWithSkipCANotSet = "envWithSkipCADisabled" +$envWithBothProtocalsNotSet = "envWithBothProtocalsNotSet" +$EnvironmentNameForFailedJob = "JobFail" + +$machineNamesForFailCopy = "Test3" +$machineNamesForFailDeploy = "Test4" +$machineNamesForNoResouceProperty = "Test5" +$invalidInputMachineNames = "Invalid1" + +$machineIdForFailCopy = "20" +$machineIdForFailDeploy = "21" +$machineIdForNoResouceProperty = "22" + +# Environment Properties +$environmentWinRMHttpPort = '5985' +$environmentWinRMHttpPortForDuplicateResource = '5987' +$environmentWinRMHttpsPort = '5986' +$environmentUsername = "fareast\test" +$environmentPassword = "Password~1" + +# Environment / Resource operations +$environmentOperationId = [guid]::NewGuid().ToString() +$operationIdForResource1 = [guid]::NewGuid().ToString() +$operationIdForResource2 = [guid]::NewGuid().ToString() +$operationIdForResource3 = [guid]::NewGuid().ToString() +$operationIdForResource4 = [guid]::NewGuid().ToString() + +# Response Status +$FailedStatus = "Failed" +$PassedStatus = "Passed" + +# Response Logs +$SuccessLog = "Success Logs" +$FailedLog = "Failed Logs" +$FailedCopyLog = "Failed Copy Operation." +$FailedDeployLog = "Failed Deployment Operation." + + +# Response Error +$FailedError = "Operation Failed" +$FailedCopyError = $FailedCopyLog +$FailedDeployError = $FailedDeployLog + +# Resources +$emptyResourceList = @{} +$validResource1 = @{"Id" = $validMachineId1; "Name" = $validMachineName1; "Type" = $null; "Username" = $environmentUsername; "Password" = $environmentPassword; "PropertyBag" = @{"Bag" = @{ "Microsoft-Vslabs-MG-Resource-FQDN" = @{"IsSecure" = $false; "Data" = $validMachineName1}; "Username" = @{"IsSecure" = $false; "Data" = $environmentUsername}; "Password" = @{"IsSecure" = $false; "Data" = $environmentPassword}}}} +$validResource2 = @{"Id" = $validMachineId2; "Name" = $validMachineName2; "Type" = $null; "Username" = $environmentUsername; "Password" = $environmentPassword; "PropertyBag" = @{"Bag" = @{ "Microsoft-Vslabs-MG-Resource-FQDN" = @{"IsSecure" = $false; "Data" = $validMachineName1}; "Username" = @{"IsSecure" = $false; "Data" = $environmentUsername}; "Password" = @{"IsSecure" = $false; "Data" = $environmentPassword}}}} +$resourceFailForCopy = @{"Id" = $machineIdForFailCopy; "Name" = $machineNamesForFailCopy; "Type" = $null; "Username" = $environmentUsername; "Password" = $environmentPassword; "PropertyBag" = @{"Bag" = @{ "Microsoft-Vslabs-MG-Resource-FQDN" = @{"IsSecure" = $false; "Data" = $validMachineName1}; "Username" = @{"IsSecure" = $false; "Data" = $environmentUsername}; "Password" = @{"IsSecure" = $false; "Data" = $environmentPassword}}}} +$resourceFailForDeploy = @{"Id" = $machineIdForFailDeploy; "Name" = $machineNamesForFailDeploy; "Type" = $null; "Username" = $environmentUsername; "Password" = $environmentPassword; "PropertyBag" = @{"Bag" = @{ "Microsoft-Vslabs-MG-Resource-FQDN" = @{"IsSecure" = $false; "Data" = $validMachineName1}; "Username" = @{"IsSecure" = $false; "Data" = $environmentUsername}; "Password" = @{"IsSecure" = $false; "Data" = $environmentPassword}}}} +$resourceFailForNoProperty = @{"Id" = $machineIdForNoResouceProperty; "Name" = $machineNamesForNoResouceProperty; "Type" = $null; "Username" = $environmentUsername; "Password" = $environmentPassword; "PropertyBag" = @{"Bag" = @{ "Microsoft-Vslabs-MG-Resource-FQDN" = @{"IsSecure" = $false; "Data" = $validMachineName1}; "Username" = @{"IsSecure" = $false; "Data" = $environmentUsername}; "Password" = @{"IsSecure" = $false; "Data" = $environmentPassword}}}} +$validResource1Duplicate = @{"Id" = $validMachineId1Duplicate; "Name" = $validMachineName1; "Type" = $null; "Username" = $environmentUsername; "Password" = $environmentPassword; "PropertyBag" = @{"Bag" = @{ "Microsoft-Vslabs-MG-Resource-FQDN" = @{"IsSecure" = $false; "Data" = $validMachineName1}; "Username" = @{"IsSecure" = $false; "Data" = $environmentUsername}; "Password" = @{"IsSecure" = $false; "Data" = $environmentPassword}}}} + +$validResources = New-Object 'System.Collections.Generic.List[System.Object]' +$validResources.Add($validResource1) +$validResources.Add($validResource2) + +$validResourcesWithDuplicateResourceName = New-Object 'System.Collections.Generic.List[System.Object]' +$validResourcesWithDuplicateResourceName.Add($validResource1) +$validResourcesWithDuplicateResourceName.Add($validResource1Duplicate) + +# Resource Property Key Names +$resourceFQDNKeyName = 'Microsoft-Vslabs-MG-Resource-FQDN' +$resourceWinRMHttpPortKeyName = 'WinRM_Http' +$resourceWinRMHttpsPortKeyName = 'WinRM_Https' +$skipCACheckKeyName = 'Microsoft-Vslabs-MG-SkipCACheck' + +#Deployment Responses +$passResponseForResource1 = @{"MachineName" = $validMachineName1; "Status" = $PassedStatus; "DeploymentLog" = $SuccessLog; "ServiceLog" = $null; "Error" = $null} +$passResponseForResource2 = @{"MachineName" = $validMachineName2; "Status" = $PassedStatus; "DeploymentLog" = $SuccessLog; "ServiceLog" = $null; "Error" = $null} +$failedResponseForCopy = @{"MachineName" = $machineNamesForFailCopy; "Status" = $FailedStatus; "DeploymentLog" = $FailedCopyLog; "ServiceLog" = $null; "Error" = @{"Message" = $FailedCopyError}} +$failedResponseForDeploy = @{"MachineName" = $machineNamesForFailDeploy; "Status" = $FailedStatus; "DeploymentLog" = $FailedDeployLog; "ServiceLog" = $null; "Error" = @{"Message" = $FailedDeployError}} +$JobPassResponse = @{"Status" = $PassedStatus; "DeploymentLog" = $SuccessLog; "ServiceLog" = $null; "Error" = $null} +$JobFailResponseForDeploy = @{"Status" = $FailedStatus; "DeploymentLog" = $FailedDeployLog; "ServiceLog" = $null; "Error" = $null} +$JobFailResponseForCopy = @{"Status" = $FailedStatus; "DeploymentLog" = $FailedCopyLog; "ServiceLog" = $null; "Error" = $null} + +#Jobs +$Job1 = @{"Id" = "1"; "Status" = "Completed"} +$Job2 = @{"Id" = "2"; "Status" = "Completed"} +$Job3 = @{"Id" = "3"; "Status" = "Completed"} + +#SkipCA Key and value +$doSkipCACheckOption = '-SkipCACheck' + +#WindowsFileCopy Constants +$validSourcePackage = $testPath +$validApplicationPath = $testPath +$invalidSourcePath = "Invalid" +$invalidTargetPath = "`$env:abc\123" + +#path to WindowsMachineFileCopy.ps1 +$copyFilesToMachinesPath = "$PSScriptRoot\..\WindowsMachineFileCopy.ps1" \ No newline at end of file diff --git a/Tasks/WindowsMachineFileCopy/Utility.ps1 b/Tasks/WindowsMachineFileCopy/Utility.ps1 new file mode 100644 index 000000000000..f9a9ca2c8625 --- /dev/null +++ b/Tasks/WindowsMachineFileCopy/Utility.ps1 @@ -0,0 +1,105 @@ +function ThrowError +{ + param([string]$errorMessage) + + throw "$errorMessage" +} + +function Get-ResourceConnectionDetails +{ + param( + [string]$envName, + [object]$resource + ) + + $resourceProperties = @{} + + $resourceName = $resource.Name + $resourceId = $resource.Id + + Write-Verbose "`t`t Starting Get-EnvironmentProperty cmdlet call on environment name: $environmentName with resource id: $resourceId(Name : $resourceName) and key: $resourceFQDNKeyName" + $fqdn = Get-EnvironmentProperty -Environment $environment -Key $resourceFQDNKeyName -ResourceId $resourceId -ErrorAction Stop + Write-Verbose "`t`t Completed Get-EnvironmentProperty cmdlet call on environment name: $environmentName with resource id: $resourceId(Name : $resourceName) and key: $resourceFQDNKeyName" + + Write-Verbose "`t`t Resource fqdn - $fqdn" + + $resourceProperties.fqdn = $fqdn + $resourceProperties.credential = Get-ResourceCredentials -resource $resource + + return $resourceProperties +} + +function Get-ResourcesProperties +{ + param( + [string]$envName, + [object]$resources + ) + + [hashtable]$resourcesPropertyBag = @{} + + foreach ($resource in $resources) + { + $resourceName = $resource.Name + $resourceId = $resource.Id + Write-Verbose "Get Resource properties for $resourceName (ResourceId = $resourceId)" + + # Get other connection details for resource like - fqdn wirmport, http protocol, skipCACheckOption, resource credentials + + $resourceProperties = Get-ResourceConnectionDetails -envName $envName -resource $resource + + $resourcesPropertyBag.Add($resourceId, $resourceProperties) + } + return $resourcesPropertyBag +} + +function Validate-Null( + [string]$value, + [string]$variableName + ) +{ + $value = $value.Trim() + if(-not $value) + { + ThrowError -errorMessage (Get-LocalizedString -Key "Parameter '{0}' cannot be null or empty." -ArgumentList $variableName) + } +} + +function Validate-SourcePath( + [string]$value + ) +{ + Validate-Null -value $value -variableName "sourcePath" + + if(-not (Test-Path -LiteralPath $value)) + { + ThrowError -errorMessage (Get-LocalizedString -Key "Source path '{0}' does not exist." -ArgumentList $value) + } +} + +function Validate-DestinationPath( + [string]$value, + [string]$environmentName + ) +{ + Validate-Null -value $value -variableName "targetPath" + + if($environmentName -and $value.StartsWith("`$env:")) + { + ThrowError -errorMessage (Get-LocalizedString -Key "Remote destination path '{0}' cannot contain environment variables." -ArgumentList $value) + } +} +# $sourcePath, $targetPath, $credential, $cleanTargetBeforeCopy, $additionalArguments +# $adminUserName, $adminPassword +function Copy-OnLocalMachine( + [string] $sourcePath, + [string] $targetPath, + [string] $adminUserName, + [string] $adminPassword, + [string] $cleanTargetBeforeCopy, + [string] $additionalArguments + ) +{ + $credential = New-Object 'System.Net.NetworkCredential' -ArgumentList $adminUserName, $adminPassword + Invoke-Command -ScriptBlock $CopyJob -ArgumentList "", $sourcePath, $targetPath, $credential, $cleanTargetBeforeCopy, $additionalArguments +} \ No newline at end of file diff --git a/Tasks/WindowsMachineFileCopy/WindowsMachineFileCopy.ps1 b/Tasks/WindowsMachineFileCopy/WindowsMachineFileCopy.ps1 index 4efd54c4cd81..4fff57d85ed9 100644 --- a/Tasks/WindowsMachineFileCopy/WindowsMachineFileCopy.ps1 +++ b/Tasks/WindowsMachineFileCopy/WindowsMachineFileCopy.ps1 @@ -22,7 +22,8 @@ Write-Verbose "additionalArguments = $additionalArguments" Write-Verbose "copyFilesInParallel = $copyFilesInParallel" Write-Verbose "cleanTargetBeforeCopy = $cleanTargetBeforeCopy" -. ./RoboCopyJob.ps1 +. $PSScriptRoot/RoboCopyJob.ps1 +. $PSScriptRoot/Utility.ps1 import-module "Microsoft.TeamFoundation.DistributedTask.Task.Common" import-module "Microsoft.TeamFoundation.DistributedTask.Task.Internal" @@ -38,99 +39,6 @@ $resourceFQDNKeyName = Get-ResourceFQDNTagKey $envOperationStatus = 'Passed' -function ThrowError -{ - param([string]$errorMessage) - - throw "$errorMessage" -} - -function Get-ResourceConnectionDetails -{ - param( - [string]$envName, - [object]$resource - ) - - $resourceProperties = @{} - - $resourceName = $resource.Name - $resourceId = $resource.Id - - Write-Verbose "`t`t Starting Get-EnvironmentProperty cmdlet call on environment name: $environmentName with resource id: $resourceId(Name : $resourceName) and key: $resourceFQDNKeyName" - $fqdn = Get-EnvironmentProperty -Environment $environment -Key $resourceFQDNKeyName -ResourceId $resourceId -ErrorAction Stop - Write-Verbose "`t`t Completed Get-EnvironmentProperty cmdlet call on environment name: $environmentName with resource id: $resourceId(Name : $resourceName) and key: $resourceFQDNKeyName" - - Write-Verbose "`t`t Resource fqdn - $fqdn" - - $resourceProperties.fqdn = $fqdn - $resourceProperties.credential = Get-ResourceCredentials -resource $resource - - return $resourceProperties -} - -function Get-ResourcesProperties -{ - param( - [string]$envName, - [object]$resources - ) - - [hashtable]$resourcesPropertyBag = @{} - - foreach ($resource in $resources) - { - $resourceName = $resource.Name - $resourceId = $resource.Id - Write-Verbose "Get Resource properties for $resourceName (ResourceId = $resourceId)" - - # Get other connection details for resource like - fqdn wirmport, http protocol, skipCACheckOption, resource credentials - - $resourceProperties = Get-ResourceConnectionDetails -envName $envName -resource $resource - - $resourcesPropertyBag.Add($resourceId, $resourceProperties) - } - return $resourcesPropertyBag -} - -function Validate-Null( - [string]$value, - [string]$variableName - ) -{ - $value = $value.Trim() - if(-not $value) - { - ThrowError -errorMessage (Get-LocalizedString -Key "Parameter '{0}' cannot be null or empty." -ArgumentList $variableName) - } -} - -function Validate-SourcePath( - [string]$value - ) -{ - Validate-Null -value $value -variableName "sourcePath" - - if(-not (Test-Path -LiteralPath $value)) - { - ThrowError -errorMessage (Get-LocalizedString -Key "Source path '{0}' does not exist." -ArgumentList $value) - } -} - -function Validate-DestinationPath( - [string]$value, - [string]$environmentName - ) -{ - Validate-Null -value $value -variableName "targetPath" - - if($environmentName -and $value.StartsWith("`$env:")) - { - ThrowError -errorMessage (Get-LocalizedString -Key "Remote destination path '{0}' cannot contain environment variables." -ArgumentList $value) - } -} - - Validate-SourcePath $sourcePath Validate-DestinationPath $targetPath $environmentName @@ -139,8 +47,9 @@ if([string]::IsNullOrWhiteSpace($environmentName)) Write-Verbose "No environment found. Copying to destination." Write-Output (Get-LocalizedString -Key "Copy started for - '{0}'" -ArgumentList $targetPath) - $credential = New-Object 'System.Net.NetworkCredential' -ArgumentList $adminUserName, $adminPassword - Invoke-Command -ScriptBlock $CopyJob -ArgumentList "", $sourcePath, $targetPath, $credential, $cleanTargetBeforeCopy, $additionalArguments + Copy-OnLocalMachine -sourcePath $sourcePath -targetPath $targetPath -adminUserName $adminUserName -adminPassword $adminPassword ` + -cleanTargetBeforeCopy $cleanTargetBeforeCopy -additionalArguments $additionalArguments + Write-Verbose "Files copied to destination successfully." } else { diff --git a/Tasks/WindowsMachineFileCopy/task.json b/Tasks/WindowsMachineFileCopy/task.json index 8ebf5ab8caf2..71a57504ae8b 100644 --- a/Tasks/WindowsMachineFileCopy/task.json +++ b/Tasks/WindowsMachineFileCopy/task.json @@ -13,7 +13,7 @@ "version": { "Major": 1, "Minor": 0, - "Patch": 36 + "Patch": 38 }, "minimumAgentVersion": "1.104.0", "groups": [ diff --git a/Tasks/WindowsMachineFileCopy/task.loc.json b/Tasks/WindowsMachineFileCopy/task.loc.json index a39431dbb1bc..5df8007bc483 100644 --- a/Tasks/WindowsMachineFileCopy/task.loc.json +++ b/Tasks/WindowsMachineFileCopy/task.loc.json @@ -13,7 +13,7 @@ "version": { "Major": 1, "Minor": 0, - "Patch": 36 + "Patch": 38 }, "minimumAgentVersion": "1.104.0", "groups": [ diff --git a/Tasks/WindowsMachineFileCopy/tsconfig.json b/Tasks/WindowsMachineFileCopy/tsconfig.json new file mode 100644 index 000000000000..79a868c8d1e3 --- /dev/null +++ b/Tasks/WindowsMachineFileCopy/tsconfig.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "target": "ES6", + "module": "commonjs" + }, + "exclude": [ + "node_modules" + ] +} \ No newline at end of file diff --git a/Tasks/XamarinLicense/Strings/resources.resjson/de-de/resources.resjson b/Tasks/XamarinLicense/Strings/resources.resjson/de-de/resources.resjson deleted file mode 100644 index 79faa709c149..000000000000 --- a/Tasks/XamarinLicense/Strings/resources.resjson/de-de/resources.resjson +++ /dev/null @@ -1,15 +0,0 @@ -{ - "loc.friendlyName": "Xamarin-Lizenz", - "loc.helpMarkDown": "[More Information](https://go.microsoft.com/fwlink/?LinkID=613739)", - "loc.description": "Xamarin-Lizenzen aktivieren oder deaktivieren", - "loc.instanceNameFormat": "Xamarin-Lizenz $(action)", - "loc.group.displayName.advanced": "Erweitert", - "loc.input.label.action": "Aktion", - "loc.input.label.email": "E-Mail", - "loc.input.help.email": "E-Mail-Adresse des Xamarin-Kontos.", - "loc.input.label.password": "Kennwort", - "loc.input.help.password": "Das Kennwort des Xamarin-Kontos. Verwenden Sie eine neue Buildvariable, deren Sperre auf der Registerkarte \"Variablen\" aktiviert ist, um diesen Wert zu verschlüsseln.", - "loc.input.label.product": "Xamarin-Produkt", - "loc.input.help.product": "Der Xamarin-Produktname.", - "loc.input.label.timeout": "Zeitüberschreitung in Sekunden" -} \ No newline at end of file diff --git a/Tasks/XamarinLicense/Strings/resources.resjson/en-US/resources.resjson b/Tasks/XamarinLicense/Strings/resources.resjson/en-US/resources.resjson deleted file mode 100644 index 1b2ae46f4135..000000000000 --- a/Tasks/XamarinLicense/Strings/resources.resjson/en-US/resources.resjson +++ /dev/null @@ -1,15 +0,0 @@ -{ - "loc.friendlyName": "Xamarin License", - "loc.helpMarkDown": "[More Information](https://go.microsoft.com/fwlink/?LinkID=613739)", - "loc.description": "Activate or deactivate Xamarin licenses (deprecated; upgrade to free version of Xamarin: https://store.xamarin.com)", - "loc.instanceNameFormat": "$(action) Xamarin license", - "loc.group.displayName.advanced": "Advanced", - "loc.input.label.action": "Action", - "loc.input.label.email": "Email", - "loc.input.help.email": "Xamarin account email address.", - "loc.input.label.password": "Password", - "loc.input.help.password": "Xamarin account password. Use a new build variable with its lock enabled on the Variables tab to encrypt this value.", - "loc.input.label.product": "Xamarin Product", - "loc.input.help.product": "Xamarin product name.", - "loc.input.label.timeout": "Timeout in Seconds" -} \ No newline at end of file diff --git a/Tasks/XamarinLicense/Strings/resources.resjson/es-es/resources.resjson b/Tasks/XamarinLicense/Strings/resources.resjson/es-es/resources.resjson deleted file mode 100644 index 9a66bc77fb2e..000000000000 --- a/Tasks/XamarinLicense/Strings/resources.resjson/es-es/resources.resjson +++ /dev/null @@ -1,15 +0,0 @@ -{ - "loc.friendlyName": "Licencia de Xamarin", - "loc.helpMarkDown": "[More Information](https://go.microsoft.com/fwlink/?LinkID=613739)", - "loc.description": "Activar o desactivar licencias de Xamarin", - "loc.instanceNameFormat": "$(action) licencia de Xamarin", - "loc.group.displayName.advanced": "Avanzado", - "loc.input.label.action": "Acción", - "loc.input.label.email": "Correo electrónico", - "loc.input.help.email": "Dirección de correo de la cuenta de Xamarin.", - "loc.input.label.password": "Contraseña", - "loc.input.help.password": "Contraseña de la cuenta de Xamarin. Use una nueva variable de compilación con el bloqueo habilitado en la pestaña Variables para cifrar este valor.", - "loc.input.label.product": "Producto de Xamarin", - "loc.input.help.product": "Nombre de producto de Xamarin.", - "loc.input.label.timeout": "Tiempo de espera en segundos" -} \ No newline at end of file diff --git a/Tasks/XamarinLicense/Strings/resources.resjson/fr-fr/resources.resjson b/Tasks/XamarinLicense/Strings/resources.resjson/fr-fr/resources.resjson deleted file mode 100644 index e0e587b8f2c4..000000000000 --- a/Tasks/XamarinLicense/Strings/resources.resjson/fr-fr/resources.resjson +++ /dev/null @@ -1,15 +0,0 @@ -{ - "loc.friendlyName": "Licence Xamarin", - "loc.helpMarkDown": "[More Information](https://go.microsoft.com/fwlink/?LinkID=613739)", - "loc.description": "Activer ou désactiver les licences Xamarin", - "loc.instanceNameFormat": "$(action) licence Xamarin", - "loc.group.displayName.advanced": "Avancé", - "loc.input.label.action": "Action", - "loc.input.label.email": "Messagerie", - "loc.input.help.email": "Adresse e-mail du compte Xamarin.", - "loc.input.label.password": "Mot de passe", - "loc.input.help.password": "Mot de passe du compte Xamarin. Pour chiffrer cette valeur, utilisez une nouvelle variable de build avec le verrou activé sous l'onglet Variables.", - "loc.input.label.product": "Produit Xamarin", - "loc.input.help.product": "Nom du produit Xamarin.", - "loc.input.label.timeout": "Délai d'expiration en secondes" -} \ No newline at end of file diff --git a/Tasks/XamarinLicense/Strings/resources.resjson/it-IT/resources.resjson b/Tasks/XamarinLicense/Strings/resources.resjson/it-IT/resources.resjson deleted file mode 100644 index a2fa8b8559cf..000000000000 --- a/Tasks/XamarinLicense/Strings/resources.resjson/it-IT/resources.resjson +++ /dev/null @@ -1,15 +0,0 @@ -{ - "loc.friendlyName": "Licenza Xamarin", - "loc.helpMarkDown": "[More Information](https://go.microsoft.com/fwlink/?LinkID=613739)", - "loc.description": "Consente di attivare o disattivare le licenze per Xamarin", - "loc.instanceNameFormat": "$(action) licenza Xamarin", - "loc.group.displayName.advanced": "Avanzate", - "loc.input.label.action": "Azione", - "loc.input.label.email": "Posta elettronica", - "loc.input.help.email": "Indirizzo di posta elettronica dell'account Xamarin.", - "loc.input.label.password": "Password", - "loc.input.help.password": "Password dell'account di Xamarin. Per crittografare questo valore, usare una nuova variabile di compilazione con il relativo blocco abilitato nella scheda Variabili.", - "loc.input.label.product": "Prodotto Xamarin", - "loc.input.help.product": "Nome del prodotto Xamarin.", - "loc.input.label.timeout": "Timeout in secondi" -} \ No newline at end of file diff --git a/Tasks/XamarinLicense/Strings/resources.resjson/ja-jp/resources.resjson b/Tasks/XamarinLicense/Strings/resources.resjson/ja-jp/resources.resjson deleted file mode 100644 index 2e58178195eb..000000000000 --- a/Tasks/XamarinLicense/Strings/resources.resjson/ja-jp/resources.resjson +++ /dev/null @@ -1,15 +0,0 @@ -{ - "loc.friendlyName": "Xamarin ライセンス", - "loc.helpMarkDown": "[More Information](https://go.microsoft.com/fwlink/?LinkID=613739)", - "loc.description": "Xamarin ライセンスをアクティブ化または非アクティブ化します", - "loc.instanceNameFormat": "$(action) Xamarin ライセンス", - "loc.group.displayName.advanced": "詳細設定", - "loc.input.label.action": "アクション", - "loc.input.label.email": "電子メール", - "loc.input.help.email": "Xamarin アカウントの電子メール アドレス。", - "loc.input.label.password": "パスワード", - "loc.input.help.password": "Xamarin アカウントのパスワード。[変数] タブでロックが有効になっている新しいビルド変数を使用して、この値を暗号化します。", - "loc.input.label.product": "Xamarin 製品", - "loc.input.help.product": "Xamarin の製品名。", - "loc.input.label.timeout": "タイムアウト (秒)" -} \ No newline at end of file diff --git a/Tasks/XamarinLicense/Strings/resources.resjson/ko-KR/resources.resjson b/Tasks/XamarinLicense/Strings/resources.resjson/ko-KR/resources.resjson deleted file mode 100644 index 0fa9e8440c78..000000000000 --- a/Tasks/XamarinLicense/Strings/resources.resjson/ko-KR/resources.resjson +++ /dev/null @@ -1,15 +0,0 @@ -{ - "loc.friendlyName": "Xamarin 라이선스", - "loc.helpMarkDown": "[More Information](https://go.microsoft.com/fwlink/?LinkID=613739)", - "loc.description": "Xamarin 라이선스 활성화 또는 비활성화", - "loc.instanceNameFormat": "Xamarin 라이선스 $(action)", - "loc.group.displayName.advanced": "고급", - "loc.input.label.action": "작업", - "loc.input.label.email": "메일", - "loc.input.help.email": "Xamarin 계정 메일 주소.", - "loc.input.label.password": "암호", - "loc.input.help.password": "Xamarin 계정 암호입니다. 이 값을 암호화하려면 [변수] 탭에서 해당 잠금을 사용하도록 설정한 상태로 새 빌드 변수를 사용하세요.", - "loc.input.label.product": "Xamarin 제품", - "loc.input.help.product": "Xamarin 제품 이름입니다.", - "loc.input.label.timeout": "시간 제한(초)" -} \ No newline at end of file diff --git a/Tasks/XamarinLicense/Strings/resources.resjson/ru-RU/resources.resjson b/Tasks/XamarinLicense/Strings/resources.resjson/ru-RU/resources.resjson deleted file mode 100644 index dbb260e44c77..000000000000 --- a/Tasks/XamarinLicense/Strings/resources.resjson/ru-RU/resources.resjson +++ /dev/null @@ -1,15 +0,0 @@ -{ - "loc.friendlyName": "Лицензия Xamarin", - "loc.helpMarkDown": "[More Information](https://go.microsoft.com/fwlink/?LinkID=613739)", - "loc.description": "Активация или деактивация лицензий Xamarin", - "loc.instanceNameFormat": "Лицензия Xamarin - $(action)", - "loc.group.displayName.advanced": "Дополнительно", - "loc.input.label.action": "Действие", - "loc.input.label.email": "Электронная почта", - "loc.input.help.email": "Адрес электронной почты учетной записи Xamarin.", - "loc.input.label.password": "Пароль", - "loc.input.help.password": "Пароль учетной записи Xamarin. Чтобы зашифровать это значение, используйте новую переменную сборки с включенной блокировкой на вкладке \"Переменные\".", - "loc.input.label.product": "Продукт Xamarin", - "loc.input.help.product": "Название продукта Xamarin.", - "loc.input.label.timeout": "Время ожидания в секундах" -} \ No newline at end of file diff --git a/Tasks/XamarinLicense/Strings/resources.resjson/zh-CN/resources.resjson b/Tasks/XamarinLicense/Strings/resources.resjson/zh-CN/resources.resjson deleted file mode 100644 index e7e1f20b2ef8..000000000000 --- a/Tasks/XamarinLicense/Strings/resources.resjson/zh-CN/resources.resjson +++ /dev/null @@ -1,15 +0,0 @@ -{ - "loc.friendlyName": "Xamarin 许可证", - "loc.helpMarkDown": "[More Information](https://go.microsoft.com/fwlink/?LinkID=613739)", - "loc.description": "激活或禁用 Xamarin 许可证", - "loc.instanceNameFormat": "$(action) Xamarin 许可证", - "loc.group.displayName.advanced": "高级", - "loc.input.label.action": "操作", - "loc.input.label.email": "电子邮件", - "loc.input.help.email": "Xamarin 帐户电子邮件地址。", - "loc.input.label.password": "密码", - "loc.input.help.password": "Xamarin 帐户密码。使用在“变量”选项卡上启用了锁定的新的生成变量来加密该值。", - "loc.input.label.product": "Xamarin 产品", - "loc.input.help.product": "Xamarin 产品名称。", - "loc.input.label.timeout": "超时秒数" -} \ No newline at end of file diff --git a/Tasks/XamarinLicense/Strings/resources.resjson/zh-TW/resources.resjson b/Tasks/XamarinLicense/Strings/resources.resjson/zh-TW/resources.resjson deleted file mode 100644 index 4b97bae7b415..000000000000 --- a/Tasks/XamarinLicense/Strings/resources.resjson/zh-TW/resources.resjson +++ /dev/null @@ -1,15 +0,0 @@ -{ - "loc.friendlyName": "Xamarin 授權", - "loc.helpMarkDown": "[More Information](https://go.microsoft.com/fwlink/?LinkID=613739)", - "loc.description": "啟動或停用 Xamarin 授權", - "loc.instanceNameFormat": "$(action) Xamarin 授權", - "loc.group.displayName.advanced": "進階", - "loc.input.label.action": "動作", - "loc.input.label.email": "電子郵件", - "loc.input.help.email": "Xamarin 帳戶電子郵件地址。", - "loc.input.label.password": "密碼", - "loc.input.help.password": "Xamarin 帳戶密碼。請使用已在 [變數] 索引標籤上啟用其鎖定的新組建變數來加密這個值。", - "loc.input.label.product": "Xamarin 產品", - "loc.input.help.product": "Xamarin 產品名稱。", - "loc.input.label.timeout": "逾時 (以秒為單位)" -} \ No newline at end of file diff --git a/Tasks/XamarinLicense/icon.png b/Tasks/XamarinLicense/icon.png deleted file mode 100644 index cd321692264d..000000000000 Binary files a/Tasks/XamarinLicense/icon.png and /dev/null differ diff --git a/Tasks/XamarinLicense/icon.svg b/Tasks/XamarinLicense/icon.svg deleted file mode 100644 index e098bfca4c45..000000000000 --- a/Tasks/XamarinLicense/icon.svg +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - diff --git a/Tasks/XamarinLicense/package.json b/Tasks/XamarinLicense/package.json deleted file mode 100644 index 750da8419208..000000000000 --- a/Tasks/XamarinLicense/package.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "vsts-xamarinlicense-task", - "version": "1.0.0", - "description": "VSTS Xamarin License Task", - "main": "xamarinlicense.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/microsoft/vsts-tasks.git" - }, - "author": "Microsoft Corporation", - "license": "MIT", - "bugs": { - "url": "https://github.com/microsoft/vsts-tasks/issues" - }, - "homepage": "https://github.com/microsoft/vsts-tasks#readme", - "dependencies": { - "vsts-task-lib": "0.7.4" - } -} diff --git a/Tasks/XamarinLicense/task.json b/Tasks/XamarinLicense/task.json deleted file mode 100644 index a8f77d8f763f..000000000000 --- a/Tasks/XamarinLicense/task.json +++ /dev/null @@ -1,83 +0,0 @@ -{ - "id": "6237827D-6244-4D52-B93E-47D8610FBD8A", - "name": "XamarinLicense", - "friendlyName": "Xamarin License", - "description": "Activate or deactivate Xamarin licenses (deprecated; upgrade to free version of Xamarin: https://store.xamarin.com)", - "helpMarkDown": "[More Information](https://go.microsoft.com/fwlink/?LinkID=613739)", - "category": "Utility", - "visibility": [ - "Build" - ], - "author": "Microsoft Corporation", - "version": { - "Major": 1, - "Minor": 0, - "Patch": 20 - }, - "demands": [], - "minimumAgentVersion": "1.83.0", - "groups": [ - { - "name": "advanced", - "displayName": "Advanced", - "isExpanded": true - } - ], - "inputs": [ - { - "name": "action", - "type": "radio", - "label": "Action", - "required": true, - "defaultValue": "Activate", - "options": { - "Activate": "Activate", - "Deactivate": "Deactivate" - } - }, - { - "name": "email", - "type": "string", - "label": "Email", - "defaultValue": "", - "required": true, - "helpMarkDown": "Xamarin account email address." - }, - { - "name": "password", - "type": "string", - "label": "Password", - "defaultValue": "", - "required": true, - "helpMarkDown": "Xamarin account password. Use a new build variable with its lock enabled on the Variables tab to encrypt this value." - }, - { - "name": "product", - "type": "pickList", - "label": "Xamarin Product", - "defaultValue": "MA", - "required": true, - "helpMarkDown": "Xamarin product name.", - "options": { - "MA": "Xamarin.Android", - "MT": "Xamarin.iOS", - "MM": "Xamarin.Mac" - } - }, - { - "name": "timeout", - "type": "string", - "label": "Timeout in Seconds", - "groupName": "advanced", - "defaultValue": "30", - "required": false - } - ], - "instanceNameFormat": "$(action) Xamarin license", - "execution": { - "Node": { - "target": "xamarinlicense.js", - "argumentFormat": "" - } - } -} \ No newline at end of file diff --git a/Tasks/XamarinLicense/task.loc.json b/Tasks/XamarinLicense/task.loc.json deleted file mode 100644 index a72d5013e5b5..000000000000 --- a/Tasks/XamarinLicense/task.loc.json +++ /dev/null @@ -1,83 +0,0 @@ -{ - "id": "6237827D-6244-4D52-B93E-47D8610FBD8A", - "name": "XamarinLicense", - "friendlyName": "ms-resource:loc.friendlyName", - "description": "ms-resource:loc.description", - "helpMarkDown": "ms-resource:loc.helpMarkDown", - "category": "Utility", - "visibility": [ - "Build" - ], - "author": "Microsoft Corporation", - "version": { - "Major": 1, - "Minor": 0, - "Patch": 20 - }, - "demands": [], - "minimumAgentVersion": "1.83.0", - "groups": [ - { - "name": "advanced", - "displayName": "ms-resource:loc.group.displayName.advanced", - "isExpanded": true - } - ], - "inputs": [ - { - "name": "action", - "type": "radio", - "label": "ms-resource:loc.input.label.action", - "required": true, - "defaultValue": "Activate", - "options": { - "Activate": "Activate", - "Deactivate": "Deactivate" - } - }, - { - "name": "email", - "type": "string", - "label": "ms-resource:loc.input.label.email", - "defaultValue": "", - "required": true, - "helpMarkDown": "ms-resource:loc.input.help.email" - }, - { - "name": "password", - "type": "string", - "label": "ms-resource:loc.input.label.password", - "defaultValue": "", - "required": true, - "helpMarkDown": "ms-resource:loc.input.help.password" - }, - { - "name": "product", - "type": "pickList", - "label": "ms-resource:loc.input.label.product", - "defaultValue": "MA", - "required": true, - "helpMarkDown": "ms-resource:loc.input.help.product", - "options": { - "MA": "Xamarin.Android", - "MT": "Xamarin.iOS", - "MM": "Xamarin.Mac" - } - }, - { - "name": "timeout", - "type": "string", - "label": "ms-resource:loc.input.label.timeout", - "groupName": "advanced", - "defaultValue": "30", - "required": false - } - ], - "instanceNameFormat": "ms-resource:loc.instanceNameFormat", - "execution": { - "Node": { - "target": "xamarinlicense.js", - "argumentFormat": "" - } - } -} \ No newline at end of file diff --git a/Tasks/XamarinLicense/typings/globals/node/index.d.ts b/Tasks/XamarinLicense/typings/globals/node/index.d.ts deleted file mode 100644 index 1dc54b352d88..000000000000 --- a/Tasks/XamarinLicense/typings/globals/node/index.d.ts +++ /dev/null @@ -1,3350 +0,0 @@ -// Generated by typings -// Source: https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/ab8d917787092fdfb16390f2bee6de8ab5c1783c/node/node.d.ts -interface Error { - stack?: string; -} - -interface ErrorConstructor { - captureStackTrace(targetObject: Object, constructorOpt?: Function): void; - stackTraceLimit: number; -} - -// compat for TypeScript 1.8 -// if you use with --target es3 or --target es5 and use below definitions, -// use the lib.es6.d.ts that is bundled with TypeScript 1.8. -interface MapConstructor { } -interface WeakMapConstructor { } -interface SetConstructor { } -interface WeakSetConstructor { } - -/************************************************ -* * -* GLOBAL * -* * -************************************************/ -declare var process: NodeJS.Process; -declare var global: NodeJS.Global; - -declare var __filename: string; -declare var __dirname: string; - -declare function setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): NodeJS.Timer; -declare function clearTimeout(timeoutId: NodeJS.Timer): void; -declare function setInterval(callback: (...args: any[]) => void, ms: number, ...args: any[]): NodeJS.Timer; -declare function clearInterval(intervalId: NodeJS.Timer): void; -declare function setImmediate(callback: (...args: any[]) => void, ...args: any[]): any; -declare function clearImmediate(immediateId: any): void; - -interface NodeRequireFunction { - (id: string): any; -} - -interface NodeRequire extends NodeRequireFunction { - resolve(id: string): string; - cache: any; - extensions: any; - main: any; -} - -declare var require: NodeRequire; - -interface NodeModule { - exports: any; - require: NodeRequireFunction; - id: string; - filename: string; - loaded: boolean; - parent: any; - children: any[]; -} - -declare var module: NodeModule; - -// Same as module.exports -declare var exports: any; -declare var SlowBuffer: { - new (str: string, encoding?: string): Buffer; - new (size: number): Buffer; - new (size: Uint8Array): Buffer; - new (array: any[]): Buffer; - prototype: Buffer; - isBuffer(obj: any): boolean; - byteLength(string: string, encoding?: string): number; - concat(list: Buffer[], totalLength?: number): Buffer; -}; - - -// Buffer class -type BufferEncoding = "ascii" | "utf8" | "utf16le" | "ucs2" | "binary" | "hex"; -interface Buffer extends NodeBuffer { } - -/** - * Raw data is stored in instances of the Buffer class. - * A Buffer is similar to an array of integers but corresponds to a raw memory allocation outside the V8 heap. A Buffer cannot be resized. - * Valid string encodings: 'ascii'|'utf8'|'utf16le'|'ucs2'(alias of 'utf16le')|'base64'|'binary'(deprecated)|'hex' - */ -declare var Buffer: { - /** - * Allocates a new buffer containing the given {str}. - * - * @param str String to store in buffer. - * @param encoding encoding to use, optional. Default is 'utf8' - */ - new (str: string, encoding?: string): Buffer; - /** - * Allocates a new buffer of {size} octets. - * - * @param size count of octets to allocate. - */ - new (size: number): Buffer; - /** - * Allocates a new buffer containing the given {array} of octets. - * - * @param array The octets to store. - */ - new (array: Uint8Array): Buffer; - /** - * Produces a Buffer backed by the same allocated memory as - * the given {ArrayBuffer}. - * - * - * @param arrayBuffer The ArrayBuffer with which to share memory. - */ - new (arrayBuffer: ArrayBuffer): Buffer; - /** - * Allocates a new buffer containing the given {array} of octets. - * - * @param array The octets to store. - */ - new (array: any[]): Buffer; - /** - * Copies the passed {buffer} data onto a new {Buffer} instance. - * - * @param buffer The buffer to copy. - */ - new (buffer: Buffer): Buffer; - prototype: Buffer; - /** - * Allocates a new Buffer using an {array} of octets. - * - * @param array - */ - from(array: any[]): Buffer; - /** - * When passed a reference to the .buffer property of a TypedArray instance, - * the newly created Buffer will share the same allocated memory as the TypedArray. - * The optional {byteOffset} and {length} arguments specify a memory range - * within the {arrayBuffer} that will be shared by the Buffer. - * - * @param arrayBuffer The .buffer property of a TypedArray or a new ArrayBuffer() - * @param byteOffset - * @param length - */ - from(arrayBuffer: ArrayBuffer, byteOffset?: number, length?: number): Buffer; - /** - * Copies the passed {buffer} data onto a new Buffer instance. - * - * @param buffer - */ - from(buffer: Buffer): Buffer; - /** - * Creates a new Buffer containing the given JavaScript string {str}. - * If provided, the {encoding} parameter identifies the character encoding. - * If not provided, {encoding} defaults to 'utf8'. - * - * @param str - */ - from(str: string, encoding?: string): Buffer; - /** - * Returns true if {obj} is a Buffer - * - * @param obj object to test. - */ - isBuffer(obj: any): obj is Buffer; - /** - * Returns true if {encoding} is a valid encoding argument. - * Valid string encodings in Node 0.12: 'ascii'|'utf8'|'utf16le'|'ucs2'(alias of 'utf16le')|'base64'|'binary'(deprecated)|'hex' - * - * @param encoding string to test. - */ - isEncoding(encoding: string): boolean; - /** - * Gives the actual byte length of a string. encoding defaults to 'utf8'. - * This is not the same as String.prototype.length since that returns the number of characters in a string. - * - * @param string string to test. - * @param encoding encoding used to evaluate (defaults to 'utf8') - */ - byteLength(string: string, encoding?: string): number; - /** - * Returns a buffer which is the result of concatenating all the buffers in the list together. - * - * If the list has no items, or if the totalLength is 0, then it returns a zero-length buffer. - * If the list has exactly one item, then the first item of the list is returned. - * If the list has more than one item, then a new Buffer is created. - * - * @param list An array of Buffer objects to concatenate - * @param totalLength Total length of the buffers when concatenated. - * If totalLength is not provided, it is read from the buffers in the list. However, this adds an additional loop to the function, so it is faster to provide the length explicitly. - */ - concat(list: Buffer[], totalLength?: number): Buffer; - /** - * The same as buf1.compare(buf2). - */ - compare(buf1: Buffer, buf2: Buffer): number; - /** - * Allocates a new buffer of {size} octets. - * - * @param size count of octets to allocate. - * @param fill if specified, buffer will be initialized by calling buf.fill(fill). - * If parameter is omitted, buffer will be filled with zeros. - * @param encoding encoding used for call to buf.fill while initalizing - */ - alloc(size: number, fill?: string | Buffer | number, encoding?: string): Buffer; - /** - * Allocates a new buffer of {size} octets, leaving memory not initialized, so the contents - * of the newly created Buffer are unknown and may contain sensitive data. - * - * @param size count of octets to allocate - */ - allocUnsafe(size: number): Buffer; - /** - * Allocates a new non-pooled buffer of {size} octets, leaving memory not initialized, so the contents - * of the newly created Buffer are unknown and may contain sensitive data. - * - * @param size count of octets to allocate - */ - allocUnsafeSlow(size: number): Buffer; -}; - -/************************************************ -* * -* GLOBAL INTERFACES * -* * -************************************************/ -declare namespace NodeJS { - export interface ErrnoException extends Error { - errno?: string; - code?: string; - path?: string; - syscall?: string; - stack?: string; - } - - export class EventEmitter { - addListener(event: string|symbol, listener: Function): this; - on(event: string|symbol, listener: Function): this; - once(event: string|symbol, listener: Function): this; - removeListener(event: string|symbol, listener: Function): this; - removeAllListeners(event?: string|symbol): this; - setMaxListeners(n: number): this; - getMaxListeners(): number; - listeners(event: string|symbol): Function[]; - emit(event: string|symbol, ...args: any[]): boolean; - listenerCount(type: string|symbol): number; - // Added in Node 6... - prependListener(event: string|symbol, listener: Function): this; - prependOnceListener(event: string|symbol, listener: Function): this; - eventNames(): (string|symbol)[]; - } - - export interface ReadableStream extends EventEmitter { - readable: boolean; - read(size?: number): string | Buffer; - setEncoding(encoding: string): void; - pause(): ReadableStream; - resume(): ReadableStream; - pipe(destination: T, options?: { end?: boolean; }): T; - unpipe(destination?: T): void; - unshift(chunk: string): void; - unshift(chunk: Buffer): void; - wrap(oldStream: ReadableStream): ReadableStream; - } - - export interface WritableStream extends EventEmitter { - writable: boolean; - write(buffer: Buffer | string, cb?: Function): boolean; - write(str: string, encoding?: string, cb?: Function): boolean; - end(): void; - end(buffer: Buffer, cb?: Function): void; - end(str: string, cb?: Function): void; - end(str: string, encoding?: string, cb?: Function): void; - } - - export interface ReadWriteStream extends ReadableStream, WritableStream { - pause(): ReadWriteStream; - resume(): ReadWriteStream; - } - - export interface Events extends EventEmitter { } - - export interface Domain extends Events { - run(fn: Function): void; - add(emitter: Events): void; - remove(emitter: Events): void; - bind(cb: (err: Error, data: any) => any): any; - intercept(cb: (data: any) => any): any; - dispose(): void; - - addListener(event: string, listener: Function): this; - on(event: string, listener: Function): this; - once(event: string, listener: Function): this; - removeListener(event: string, listener: Function): this; - removeAllListeners(event?: string): this; - } - - export interface MemoryUsage { - rss: number; - heapTotal: number; - heapUsed: number; - } - - export interface ProcessVersions { - http_parser: string; - node: string; - v8: string; - ares: string; - uv: string; - zlib: string; - modules: string; - openssl: string; - } - - export interface Process extends EventEmitter { - stdout: WritableStream; - stderr: WritableStream; - stdin: ReadableStream; - argv: string[]; - execArgv: string[]; - execPath: string; - abort(): void; - chdir(directory: string): void; - cwd(): string; - env: any; - exit(code?: number): void; - exitCode: number; - getgid(): number; - setgid(id: number): void; - setgid(id: string): void; - getuid(): number; - setuid(id: number): void; - setuid(id: string): void; - version: string; - versions: ProcessVersions; - config: { - target_defaults: { - cflags: any[]; - default_configuration: string; - defines: string[]; - include_dirs: string[]; - libraries: string[]; - }; - variables: { - clang: number; - host_arch: string; - node_install_npm: boolean; - node_install_waf: boolean; - node_prefix: string; - node_shared_openssl: boolean; - node_shared_v8: boolean; - node_shared_zlib: boolean; - node_use_dtrace: boolean; - node_use_etw: boolean; - node_use_openssl: boolean; - target_arch: string; - v8_no_strict_aliasing: number; - v8_use_snapshot: boolean; - visibility: string; - }; - }; - kill(pid: number, signal?: string | number): void; - pid: number; - title: string; - arch: string; - platform: string; - memoryUsage(): MemoryUsage; - nextTick(callback: Function, ...args: any[]): void; - umask(mask?: number): number; - uptime(): number; - hrtime(time?: number[]): number[]; - domain: Domain; - - // Worker - send?(message: any, sendHandle?: any): void; - disconnect(): void; - connected: boolean; - } - - export interface Global { - Array: typeof Array; - ArrayBuffer: typeof ArrayBuffer; - Boolean: typeof Boolean; - Buffer: typeof Buffer; - DataView: typeof DataView; - Date: typeof Date; - Error: typeof Error; - EvalError: typeof EvalError; - Float32Array: typeof Float32Array; - Float64Array: typeof Float64Array; - Function: typeof Function; - GLOBAL: Global; - Infinity: typeof Infinity; - Int16Array: typeof Int16Array; - Int32Array: typeof Int32Array; - Int8Array: typeof Int8Array; - Intl: typeof Intl; - JSON: typeof JSON; - Map: MapConstructor; - Math: typeof Math; - NaN: typeof NaN; - Number: typeof Number; - Object: typeof Object; - Promise: Function; - RangeError: typeof RangeError; - ReferenceError: typeof ReferenceError; - RegExp: typeof RegExp; - Set: SetConstructor; - String: typeof String; - Symbol: Function; - SyntaxError: typeof SyntaxError; - TypeError: typeof TypeError; - URIError: typeof URIError; - Uint16Array: typeof Uint16Array; - Uint32Array: typeof Uint32Array; - Uint8Array: typeof Uint8Array; - Uint8ClampedArray: Function; - WeakMap: WeakMapConstructor; - WeakSet: WeakSetConstructor; - clearImmediate: (immediateId: any) => void; - clearInterval: (intervalId: NodeJS.Timer) => void; - clearTimeout: (timeoutId: NodeJS.Timer) => void; - console: typeof console; - decodeURI: typeof decodeURI; - decodeURIComponent: typeof decodeURIComponent; - encodeURI: typeof encodeURI; - encodeURIComponent: typeof encodeURIComponent; - escape: (str: string) => string; - eval: typeof eval; - global: Global; - isFinite: typeof isFinite; - isNaN: typeof isNaN; - parseFloat: typeof parseFloat; - parseInt: typeof parseInt; - process: Process; - root: Global; - setImmediate: (callback: (...args: any[]) => void, ...args: any[]) => any; - setInterval: (callback: (...args: any[]) => void, ms: number, ...args: any[]) => NodeJS.Timer; - setTimeout: (callback: (...args: any[]) => void, ms: number, ...args: any[]) => NodeJS.Timer; - undefined: typeof undefined; - unescape: (str: string) => string; - gc: () => void; - v8debug?: any; - } - - export interface Timer { - ref(): void; - unref(): void; - } -} - -interface IterableIterator { } - -/** - * @deprecated - */ -interface NodeBuffer extends Uint8Array { - write(string: string, offset?: number, length?: number, encoding?: string): number; - toString(encoding?: string, start?: number, end?: number): string; - toJSON(): {type: 'Buffer', data: any[]}; - equals(otherBuffer: Buffer): boolean; - compare(otherBuffer: Buffer, targetStart?: number, targetEnd?: number, sourceStart?: number, sourceEnd?: number): number; - copy(targetBuffer: Buffer, targetStart?: number, sourceStart?: number, sourceEnd?: number): number; - slice(start?: number, end?: number): Buffer; - writeUIntLE(value: number, offset: number, byteLength: number, noAssert?: boolean): number; - writeUIntBE(value: number, offset: number, byteLength: number, noAssert?: boolean): number; - writeIntLE(value: number, offset: number, byteLength: number, noAssert?: boolean): number; - writeIntBE(value: number, offset: number, byteLength: number, noAssert?: boolean): number; - readUIntLE(offset: number, byteLength: number, noAssert?: boolean): number; - readUIntBE(offset: number, byteLength: number, noAssert?: boolean): number; - readIntLE(offset: number, byteLength: number, noAssert?: boolean): number; - readIntBE(offset: number, byteLength: number, noAssert?: boolean): number; - readUInt8(offset: number, noAssert?: boolean): number; - readUInt16LE(offset: number, noAssert?: boolean): number; - readUInt16BE(offset: number, noAssert?: boolean): number; - readUInt32LE(offset: number, noAssert?: boolean): number; - readUInt32BE(offset: number, noAssert?: boolean): number; - readInt8(offset: number, noAssert?: boolean): number; - readInt16LE(offset: number, noAssert?: boolean): number; - readInt16BE(offset: number, noAssert?: boolean): number; - readInt32LE(offset: number, noAssert?: boolean): number; - readInt32BE(offset: number, noAssert?: boolean): number; - readFloatLE(offset: number, noAssert?: boolean): number; - readFloatBE(offset: number, noAssert?: boolean): number; - readDoubleLE(offset: number, noAssert?: boolean): number; - readDoubleBE(offset: number, noAssert?: boolean): number; - swap16(): Buffer; - swap32(): Buffer; - swap64(): Buffer; - writeUInt8(value: number, offset: number, noAssert?: boolean): number; - writeUInt16LE(value: number, offset: number, noAssert?: boolean): number; - writeUInt16BE(value: number, offset: number, noAssert?: boolean): number; - writeUInt32LE(value: number, offset: number, noAssert?: boolean): number; - writeUInt32BE(value: number, offset: number, noAssert?: boolean): number; - writeInt8(value: number, offset: number, noAssert?: boolean): number; - writeInt16LE(value: number, offset: number, noAssert?: boolean): number; - writeInt16BE(value: number, offset: number, noAssert?: boolean): number; - writeInt32LE(value: number, offset: number, noAssert?: boolean): number; - writeInt32BE(value: number, offset: number, noAssert?: boolean): number; - writeFloatLE(value: number, offset: number, noAssert?: boolean): number; - writeFloatBE(value: number, offset: number, noAssert?: boolean): number; - writeDoubleLE(value: number, offset: number, noAssert?: boolean): number; - writeDoubleBE(value: number, offset: number, noAssert?: boolean): number; - fill(value: any, offset?: number, end?: number): this; - indexOf(value: string | number | Buffer, byteOffset?: number, encoding?: string): number; - lastIndexOf(value: string | number | Buffer, byteOffset?: number, encoding?: string): number; - entries(): IterableIterator<[number, number]>; - includes(value: string | number | Buffer, byteOffset?: number, encoding?: string): boolean; - keys(): IterableIterator; - values(): IterableIterator; -} - -/************************************************ -* * -* MODULES * -* * -************************************************/ -declare module "buffer" { - export var INSPECT_MAX_BYTES: number; - var BuffType: typeof Buffer; - var SlowBuffType: typeof SlowBuffer; - export { BuffType as Buffer, SlowBuffType as SlowBuffer }; -} - -declare module "querystring" { - export interface StringifyOptions { - encodeURIComponent?: Function; - } - - export interface ParseOptions { - maxKeys?: number; - decodeURIComponent?: Function; - } - - export function stringify(obj: T, sep?: string, eq?: string, options?: StringifyOptions): string; - export function parse(str: string, sep?: string, eq?: string, options?: ParseOptions): any; - export function parse(str: string, sep?: string, eq?: string, options?: ParseOptions): T; - export function escape(str: string): string; - export function unescape(str: string): string; -} - -declare module "events" { - export class EventEmitter extends NodeJS.EventEmitter { - static EventEmitter: EventEmitter; - static listenerCount(emitter: EventEmitter, event: string|symbol): number; // deprecated - static defaultMaxListeners: number; - - addListener(event: string|symbol, listener: Function): this; - on(event: string|symbol, listener: Function): this; - once(event: string|symbol, listener: Function): this; - prependListener(event: string|symbol, listener: Function): this; - prependOnceListener(event: string|symbol, listener: Function): this; - removeListener(event: string|symbol, listener: Function): this; - removeAllListeners(event?: string|symbol): this; - setMaxListeners(n: number): this; - getMaxListeners(): number; - listeners(event: string|symbol): Function[]; - emit(event: string|symbol, ...args: any[]): boolean; - eventNames(): (string|symbol)[]; - listenerCount(type: string|symbol): number; - } -} - -declare module "http" { - import * as events from "events"; - import * as net from "net"; - import * as stream from "stream"; - - export interface RequestOptions { - protocol?: string; - host?: string; - hostname?: string; - family?: number; - port?: number; - localAddress?: string; - socketPath?: string; - method?: string; - path?: string; - headers?: { [key: string]: any }; - auth?: string; - agent?: Agent | boolean; - } - - export interface Server extends net.Server { - setTimeout(msecs: number, callback: Function): void; - maxHeadersCount: number; - timeout: number; - listening: boolean; - } - /** - * @deprecated Use IncomingMessage - */ - export interface ServerRequest extends IncomingMessage { - connection: net.Socket; - } - export interface ServerResponse extends stream.Writable { - // Extended base methods - write(buffer: Buffer): boolean; - write(buffer: Buffer, cb?: Function): boolean; - write(str: string, cb?: Function): boolean; - write(str: string, encoding?: string, cb?: Function): boolean; - write(str: string, encoding?: string, fd?: string): boolean; - - writeContinue(): void; - writeHead(statusCode: number, reasonPhrase?: string, headers?: any): void; - writeHead(statusCode: number, headers?: any): void; - statusCode: number; - statusMessage: string; - headersSent: boolean; - setHeader(name: string, value: string | string[]): void; - setTimeout(msecs: number, callback: Function): ServerResponse; - sendDate: boolean; - getHeader(name: string): string; - removeHeader(name: string): void; - write(chunk: any, encoding?: string): any; - addTrailers(headers: any): void; - finished: boolean; - - // Extended base methods - end(): void; - end(buffer: Buffer, cb?: Function): void; - end(str: string, cb?: Function): void; - end(str: string, encoding?: string, cb?: Function): void; - end(data?: any, encoding?: string): void; - } - export interface ClientRequest extends stream.Writable { - // Extended base methods - write(buffer: Buffer): boolean; - write(buffer: Buffer, cb?: Function): boolean; - write(str: string, cb?: Function): boolean; - write(str: string, encoding?: string, cb?: Function): boolean; - write(str: string, encoding?: string, fd?: string): boolean; - - write(chunk: any, encoding?: string): void; - abort(): void; - setTimeout(timeout: number, callback?: Function): void; - setNoDelay(noDelay?: boolean): void; - setSocketKeepAlive(enable?: boolean, initialDelay?: number): void; - - setHeader(name: string, value: string | string[]): void; - getHeader(name: string): string; - removeHeader(name: string): void; - addTrailers(headers: any): void; - - // Extended base methods - end(): void; - end(buffer: Buffer, cb?: Function): void; - end(str: string, cb?: Function): void; - end(str: string, encoding?: string, cb?: Function): void; - end(data?: any, encoding?: string): void; - } - export interface IncomingMessage extends stream.Readable { - httpVersion: string; - httpVersionMajor: string; - httpVersionMinor: string; - connection: net.Socket; - headers: any; - rawHeaders: string[]; - trailers: any; - rawTrailers: any; - setTimeout(msecs: number, callback: Function): NodeJS.Timer; - /** - * Only valid for request obtained from http.Server. - */ - method?: string; - /** - * Only valid for request obtained from http.Server. - */ - url?: string; - /** - * Only valid for response obtained from http.ClientRequest. - */ - statusCode?: number; - /** - * Only valid for response obtained from http.ClientRequest. - */ - statusMessage?: string; - socket: net.Socket; - destroy(error?: Error): void; - } - /** - * @deprecated Use IncomingMessage - */ - export interface ClientResponse extends IncomingMessage { } - - export interface AgentOptions { - /** - * Keep sockets around in a pool to be used by other requests in the future. Default = false - */ - keepAlive?: boolean; - /** - * When using HTTP KeepAlive, how often to send TCP KeepAlive packets over sockets being kept alive. Default = 1000. - * Only relevant if keepAlive is set to true. - */ - keepAliveMsecs?: number; - /** - * Maximum number of sockets to allow per host. Default for Node 0.10 is 5, default for Node 0.12 is Infinity - */ - maxSockets?: number; - /** - * Maximum number of sockets to leave open in a free state. Only relevant if keepAlive is set to true. Default = 256. - */ - maxFreeSockets?: number; - } - - export class Agent { - maxSockets: number; - sockets: any; - requests: any; - - constructor(opts?: AgentOptions); - - /** - * Destroy any sockets that are currently in use by the agent. - * It is usually not necessary to do this. However, if you are using an agent with KeepAlive enabled, - * then it is best to explicitly shut down the agent when you know that it will no longer be used. Otherwise, - * sockets may hang open for quite a long time before the server terminates them. - */ - destroy(): void; - } - - export var METHODS: string[]; - - export var STATUS_CODES: { - [errorCode: number]: string; - [errorCode: string]: string; - }; - export function createServer(requestListener?: (request: IncomingMessage, response: ServerResponse) => void): Server; - export function createClient(port?: number, host?: string): any; - export function request(options: RequestOptions, callback?: (res: IncomingMessage) => void): ClientRequest; - export function get(options: any, callback?: (res: IncomingMessage) => void): ClientRequest; - export var globalAgent: Agent; -} - -declare module "cluster" { - import * as child from "child_process"; - import * as events from "events"; - import * as net from "net"; - - // interfaces - export interface ClusterSettings { - execArgv?: string[]; // default: process.execArgv - exec?: string; - args?: string[]; - silent?: boolean; - stdio?: any[]; - uid?: number; - gid?: number; - } - - export interface ClusterSetupMasterSettings { - exec?: string; // default: process.argv[1] - args?: string[]; // default: process.argv.slice(2) - silent?: boolean; // default: false - stdio?: any[]; - } - - export interface Address { - address: string; - port: number; - addressType: number | "udp4" | "udp6"; // 4, 6, -1, "udp4", "udp6" - } - - export class Worker extends events.EventEmitter { - id: string; - process: child.ChildProcess; - suicide: boolean; - send(message: any, sendHandle?: any): boolean; - kill(signal?: string): void; - destroy(signal?: string): void; - disconnect(): void; - isConnected(): boolean; - isDead(): boolean; - exitedAfterDisconnect: boolean; - - /** - * events.EventEmitter - * 1. disconnect - * 2. error - * 3. exit - * 4. listening - * 5. message - * 6. online - */ - addListener(event: string, listener: Function): this; - addListener(event: "disconnect", listener: () => void): this; - addListener(event: "error", listener: (code: number, signal: string) => void): this; - addListener(event: "exit", listener: (code: number, signal: string) => void): this; - addListener(event: "listening", listener: (address: Address) => void): this; - addListener(event: "message", listener: (message: any, handle: net.Socket | net.Server) => void): this; // the handle is a net.Socket or net.Server object, or undefined. - addListener(event: "online", listener: () => void): this; - - on(event: string, listener: Function): this; - on(event: "disconnect", listener: () => void): this; - on(event: "error", listener: (code: number, signal: string) => void): this; - on(event: "exit", listener: (code: number, signal: string) => void): this; - on(event: "listening", listener: (address: Address) => void): this; - on(event: "message", listener: (message: any, handle: net.Socket | net.Server) => void): this; // the handle is a net.Socket or net.Server object, or undefined. - on(event: "online", listener: () => void): this; - - once(event: string, listener: Function): this; - once(event: "disconnect", listener: () => void): this; - once(event: "error", listener: (code: number, signal: string) => void): this; - once(event: "exit", listener: (code: number, signal: string) => void): this; - once(event: "listening", listener: (address: Address) => void): this; - once(event: "message", listener: (message: any, handle: net.Socket | net.Server) => void): this; // the handle is a net.Socket or net.Server object, or undefined. - once(event: "online", listener: () => void): this; - - prependListener(event: string, listener: Function): this; - prependListener(event: "disconnect", listener: () => void): this; - prependListener(event: "error", listener: (code: number, signal: string) => void): this; - prependListener(event: "exit", listener: (code: number, signal: string) => void): this; - prependListener(event: "listening", listener: (address: Address) => void): this; - prependListener(event: "message", listener: (message: any, handle: net.Socket | net.Server) => void): this; // the handle is a net.Socket or net.Server object, or undefined. - prependListener(event: "online", listener: () => void): this; - - prependOnceListener(event: string, listener: Function): this; - prependOnceListener(event: "disconnect", listener: () => void): this; - prependOnceListener(event: "error", listener: (code: number, signal: string) => void): this; - prependOnceListener(event: "exit", listener: (code: number, signal: string) => void): this; - prependOnceListener(event: "listening", listener: (address: Address) => void): this; - prependOnceListener(event: "message", listener: (message: any, handle: net.Socket | net.Server) => void): this; // the handle is a net.Socket or net.Server object, or undefined. - prependOnceListener(event: "online", listener: () => void): this; - } - - export interface Cluster extends events.EventEmitter { - Worker: Worker; - disconnect(callback?: Function): void; - fork(env?: any): Worker; - isMaster: boolean; - isWorker: boolean; - // TODO: cluster.schedulingPolicy - settings: ClusterSettings; - setupMaster(settings?: ClusterSetupMasterSettings): void; - worker: Worker; - workers: { - [index: string]: Worker - }; - - /** - * events.EventEmitter - * 1. disconnect - * 2. exit - * 3. fork - * 4. listening - * 5. message - * 6. online - * 7. setup - */ - addListener(event: string, listener: Function): this; - addListener(event: "disconnect", listener: (worker: Worker) => void): this; - addListener(event: "exit", listener: (worker: Worker, code: number, signal: string) => void): this; - addListener(event: "fork", listener: (worker: Worker) => void): this; - addListener(event: "listening", listener: (worker: Worker, address: Address) => void): this; - addListener(event: "message", listener: (worker: Worker, message: any, handle: net.Socket | net.Server) => void): this; // the handle is a net.Socket or net.Server object, or undefined. - addListener(event: "online", listener: (worker: Worker) => void): this; - addListener(event: "setup", listener: (settings: any) => void): this; - - on(event: string, listener: Function): this; - on(event: "disconnect", listener: (worker: Worker) => void): this; - on(event: "exit", listener: (worker: Worker, code: number, signal: string) => void): this; - on(event: "fork", listener: (worker: Worker) => void): this; - on(event: "listening", listener: (worker: Worker, address: Address) => void): this; - on(event: "message", listener: (worker: Worker, message: any, handle: net.Socket | net.Server) => void): this; // the handle is a net.Socket or net.Server object, or undefined. - on(event: "online", listener: (worker: Worker) => void): this; - on(event: "setup", listener: (settings: any) => void): this; - - once(event: string, listener: Function): this; - once(event: "disconnect", listener: (worker: Worker) => void): this; - once(event: "exit", listener: (worker: Worker, code: number, signal: string) => void): this; - once(event: "fork", listener: (worker: Worker) => void): this; - once(event: "listening", listener: (worker: Worker, address: Address) => void): this; - once(event: "message", listener: (worker: Worker, message: any, handle: net.Socket | net.Server) => void): this; // the handle is a net.Socket or net.Server object, or undefined. - once(event: "online", listener: (worker: Worker) => void): this; - once(event: "setup", listener: (settings: any) => void): this; - - prependListener(event: string, listener: Function): this; - prependListener(event: "disconnect", listener: (worker: Worker) => void): this; - prependListener(event: "exit", listener: (worker: Worker, code: number, signal: string) => void): this; - prependListener(event: "fork", listener: (worker: Worker) => void): this; - prependListener(event: "listening", listener: (worker: Worker, address: Address) => void): this; - prependListener(event: "message", listener: (worker: Worker, message: any, handle: net.Socket | net.Server) => void): this; // the handle is a net.Socket or net.Server object, or undefined. - prependListener(event: "online", listener: (worker: Worker) => void): this; - prependListener(event: "setup", listener: (settings: any) => void): this; - - prependOnceListener(event: string, listener: Function): this; - prependOnceListener(event: "disconnect", listener: (worker: Worker) => void): this; - prependOnceListener(event: "exit", listener: (worker: Worker, code: number, signal: string) => void): this; - prependOnceListener(event: "fork", listener: (worker: Worker) => void): this; - prependOnceListener(event: "listening", listener: (worker: Worker, address: Address) => void): this; - prependOnceListener(event: "message", listener: (worker: Worker, message: any, handle: net.Socket | net.Server) => void): this; // the handle is a net.Socket or net.Server object, or undefined. - prependOnceListener(event: "online", listener: (worker: Worker) => void): this; - prependOnceListener(event: "setup", listener: (settings: any) => void): this; - - } - - export function disconnect(callback ?: Function): void; - export function fork(env?: any): Worker; - export var isMaster: boolean; - export var isWorker: boolean; - // TODO: cluster.schedulingPolicy - export var settings: ClusterSettings; - export function setupMaster(settings?: ClusterSetupMasterSettings): void; - export var worker: Worker; - export var workers: { - [index: string]: Worker - }; - - /** - * events.EventEmitter - * 1. disconnect - * 2. exit - * 3. fork - * 4. listening - * 5. message - * 6. online - * 7. setup - */ - export function addListener(event: string, listener: Function): Cluster; - export function addListener(event: "disconnect", listener: (worker: Worker) => void): Cluster; - export function addListener(event: "exit", listener: (worker: Worker, code: number, signal: string) => void): Cluster; - export function addListener(event: "fork", listener: (worker: Worker) => void): Cluster; - export function addListener(event: "listening", listener: (worker: Worker, address: Address) => void): Cluster; - export function addListener(event: "message", listener: (worker: Worker, message: any, handle: net.Socket | net.Server) => void): Cluster; // the handle is a net.Socket or net.Server object, or undefined. - export function addListener(event: "online", listener: (worker: Worker) => void): Cluster; - export function addListener(event: "setup", listener: (settings: any) => void): Cluster; - - export function on(event: string, listener: Function): Cluster; - export function on(event: "disconnect", listener: (worker: Worker) => void): Cluster; - export function on(event: "exit", listener: (worker: Worker, code: number, signal: string) => void): Cluster; - export function on(event: "fork", listener: (worker: Worker) => void): Cluster; - export function on(event: "listening", listener: (worker: Worker, address: Address) => void): Cluster; - export function on(event: "message", listener: (worker: Worker, message: any, handle: net.Socket | net.Server) => void): Cluster; // the handle is a net.Socket or net.Server object, or undefined. - export function on(event: "online", listener: (worker: Worker) => void): Cluster; - export function on(event: "setup", listener: (settings: any) => void): Cluster; - - export function once(event: string, listener: Function): Cluster; - export function once(event: "disconnect", listener: (worker: Worker) => void): Cluster; - export function once(event: "exit", listener: (worker: Worker, code: number, signal: string) => void): Cluster; - export function once(event: "fork", listener: (worker: Worker) => void): Cluster; - export function once(event: "listening", listener: (worker: Worker, address: Address) => void): Cluster; - export function once(event: "message", listener: (worker: Worker, message: any, handle: net.Socket | net.Server) => void): Cluster; // the handle is a net.Socket or net.Server object, or undefined. - export function once(event: "online", listener: (worker: Worker) => void): Cluster; - export function once(event: "setup", listener: (settings: any) => void): Cluster; - - export function removeListener(event: string, listener: Function): Cluster; - export function removeAllListeners(event?: string): Cluster; - export function setMaxListeners(n: number): Cluster; - export function getMaxListeners(): number; - export function listeners(event: string): Function[]; - export function emit(event: string, ...args: any[]): boolean; - export function listenerCount(type: string): number; - - export function prependListener(event: string, listener: Function): Cluster; - export function prependListener(event: "disconnect", listener: (worker: Worker) => void): Cluster; - export function prependListener(event: "exit", listener: (worker: Worker, code: number, signal: string) => void): Cluster; - export function prependListener(event: "fork", listener: (worker: Worker) => void): Cluster; - export function prependListener(event: "listening", listener: (worker: Worker, address: Address) => void): Cluster; - export function prependListener(event: "message", listener: (worker: Worker, message: any, handle: net.Socket | net.Server) => void): Cluster; // the handle is a net.Socket or net.Server object, or undefined. - export function prependListener(event: "online", listener: (worker: Worker) => void): Cluster; - export function prependListener(event: "setup", listener: (settings: any) => void): Cluster; - - export function prependOnceListener(event: string, listener: Function): Cluster; - export function prependOnceListener(event: "disconnect", listener: (worker: Worker) => void): Cluster; - export function prependOnceListener(event: "exit", listener: (worker: Worker, code: number, signal: string) => void): Cluster; - export function prependOnceListener(event: "fork", listener: (worker: Worker) => void): Cluster; - export function prependOnceListener(event: "listening", listener: (worker: Worker, address: Address) => void): Cluster; - export function prependOnceListener(event: "message", listener: (worker: Worker, message: any, handle: net.Socket | net.Server) => void): Cluster; // the handle is a net.Socket or net.Server object, or undefined. - export function prependOnceListener(event: "online", listener: (worker: Worker) => void): Cluster; - export function prependOnceListener(event: "setup", listener: (settings: any) => void): Cluster; - - export function eventNames(): string[]; -} - -declare module "zlib" { - import * as stream from "stream"; - export interface ZlibOptions { chunkSize?: number; windowBits?: number; level?: number; memLevel?: number; strategy?: number; dictionary?: any; } - - export interface Gzip extends stream.Transform { } - export interface Gunzip extends stream.Transform { } - export interface Deflate extends stream.Transform { } - export interface Inflate extends stream.Transform { } - export interface DeflateRaw extends stream.Transform { } - export interface InflateRaw extends stream.Transform { } - export interface Unzip extends stream.Transform { } - - export function createGzip(options?: ZlibOptions): Gzip; - export function createGunzip(options?: ZlibOptions): Gunzip; - export function createDeflate(options?: ZlibOptions): Deflate; - export function createInflate(options?: ZlibOptions): Inflate; - export function createDeflateRaw(options?: ZlibOptions): DeflateRaw; - export function createInflateRaw(options?: ZlibOptions): InflateRaw; - export function createUnzip(options?: ZlibOptions): Unzip; - - export function deflate(buf: Buffer, callback: (error: Error, result: any) => void): void; - export function deflateSync(buf: Buffer, options?: ZlibOptions): any; - export function deflateRaw(buf: Buffer, callback: (error: Error, result: any) => void): void; - export function deflateRawSync(buf: Buffer, options?: ZlibOptions): any; - export function gzip(buf: Buffer, callback: (error: Error, result: any) => void): void; - export function gzipSync(buf: Buffer, options?: ZlibOptions): any; - export function gunzip(buf: Buffer, callback: (error: Error, result: any) => void): void; - export function gunzipSync(buf: Buffer, options?: ZlibOptions): any; - export function inflate(buf: Buffer, callback: (error: Error, result: any) => void): void; - export function inflateSync(buf: Buffer, options?: ZlibOptions): any; - export function inflateRaw(buf: Buffer, callback: (error: Error, result: any) => void): void; - export function inflateRawSync(buf: Buffer, options?: ZlibOptions): any; - export function unzip(buf: Buffer, callback: (error: Error, result: any) => void): void; - export function unzipSync(buf: Buffer, options?: ZlibOptions): any; - - // Constants - export var Z_NO_FLUSH: number; - export var Z_PARTIAL_FLUSH: number; - export var Z_SYNC_FLUSH: number; - export var Z_FULL_FLUSH: number; - export var Z_FINISH: number; - export var Z_BLOCK: number; - export var Z_TREES: number; - export var Z_OK: number; - export var Z_STREAM_END: number; - export var Z_NEED_DICT: number; - export var Z_ERRNO: number; - export var Z_STREAM_ERROR: number; - export var Z_DATA_ERROR: number; - export var Z_MEM_ERROR: number; - export var Z_BUF_ERROR: number; - export var Z_VERSION_ERROR: number; - export var Z_NO_COMPRESSION: number; - export var Z_BEST_SPEED: number; - export var Z_BEST_COMPRESSION: number; - export var Z_DEFAULT_COMPRESSION: number; - export var Z_FILTERED: number; - export var Z_HUFFMAN_ONLY: number; - export var Z_RLE: number; - export var Z_FIXED: number; - export var Z_DEFAULT_STRATEGY: number; - export var Z_BINARY: number; - export var Z_TEXT: number; - export var Z_ASCII: number; - export var Z_UNKNOWN: number; - export var Z_DEFLATED: number; - export var Z_NULL: number; -} - -declare module "os" { - export interface CpuInfo { - model: string; - speed: number; - times: { - user: number; - nice: number; - sys: number; - idle: number; - irq: number; - }; - } - - export interface NetworkInterfaceInfo { - address: string; - netmask: string; - family: string; - mac: string; - internal: boolean; - } - - export function hostname(): string; - export function loadavg(): number[]; - export function uptime(): number; - export function freemem(): number; - export function totalmem(): number; - export function cpus(): CpuInfo[]; - export function type(): string; - export function release(): string; - export function networkInterfaces(): { [index: string]: NetworkInterfaceInfo[] }; - export function homedir(): string; - export function userInfo(options?: { encoding: string }): { username: string, uid: number, gid: number, shell: any, homedir: string } - export var constants: { - UV_UDP_REUSEADDR: number, - errno: { - SIGHUP: number; - SIGINT: number; - SIGQUIT: number; - SIGILL: number; - SIGTRAP: number; - SIGABRT: number; - SIGIOT: number; - SIGBUS: number; - SIGFPE: number; - SIGKILL: number; - SIGUSR1: number; - SIGSEGV: number; - SIGUSR2: number; - SIGPIPE: number; - SIGALRM: number; - SIGTERM: number; - SIGCHLD: number; - SIGSTKFLT: number; - SIGCONT: number; - SIGSTOP: number; - SIGTSTP: number; - SIGTTIN: number; - SIGTTOU: number; - SIGURG: number; - SIGXCPU: number; - SIGXFSZ: number; - SIGVTALRM: number; - SIGPROF: number; - SIGWINCH: number; - SIGIO: number; - SIGPOLL: number; - SIGPWR: number; - SIGSYS: number; - SIGUNUSED: number; - }, - signals: { - E2BIG: number; - EACCES: number; - EADDRINUSE: number; - EADDRNOTAVAIL: number; - EAFNOSUPPORT: number; - EAGAIN: number; - EALREADY: number; - EBADF: number; - EBADMSG: number; - EBUSY: number; - ECANCELED: number; - ECHILD: number; - ECONNABORTED: number; - ECONNREFUSED: number; - ECONNRESET: number; - EDEADLK: number; - EDESTADDRREQ: number; - EDOM: number; - EDQUOT: number; - EEXIST: number; - EFAULT: number; - EFBIG: number; - EHOSTUNREACH: number; - EIDRM: number; - EILSEQ: number; - EINPROGRESS: number; - EINTR: number; - EINVAL: number; - EIO: number; - EISCONN: number; - EISDIR: number; - ELOOP: number; - EMFILE: number; - EMLINK: number; - EMSGSIZE: number; - EMULTIHOP: number; - ENAMETOOLONG: number; - ENETDOWN: number; - ENETRESET: number; - ENETUNREACH: number; - ENFILE: number; - ENOBUFS: number; - ENODATA: number; - ENODEV: number; - ENOENT: number; - ENOEXEC: number; - ENOLCK: number; - ENOLINK: number; - ENOMEM: number; - ENOMSG: number; - ENOPROTOOPT: number; - ENOSPC: number; - ENOSR: number; - ENOSTR: number; - ENOSYS: number; - ENOTCONN: number; - ENOTDIR: number; - ENOTEMPTY: number; - ENOTSOCK: number; - ENOTSUP: number; - ENOTTY: number; - ENXIO: number; - EOPNOTSUPP: number; - EOVERFLOW: number; - EPERM: number; - EPIPE: number; - EPROTO: number; - EPROTONOSUPPORT: number; - EPROTOTYPE: number; - ERANGE: number; - EROFS: number; - ESPIPE: number; - ESRCH: number; - ESTALE: number; - ETIME: number; - ETIMEDOUT: number; - ETXTBSY: number; - EWOULDBLOCK: number; - EXDEV: number; - }, - }; - export function arch(): string; - export function platform(): string; - export function tmpdir(): string; - export var EOL: string; - export function endianness(): "BE" | "LE"; -} - -declare module "https" { - import * as tls from "tls"; - import * as events from "events"; - import * as http from "http"; - - export interface ServerOptions { - pfx?: any; - key?: any; - passphrase?: string; - cert?: any; - ca?: any; - crl?: any; - ciphers?: string; - honorCipherOrder?: boolean; - requestCert?: boolean; - rejectUnauthorized?: boolean; - NPNProtocols?: any; - SNICallback?: (servername: string, cb: (err: Error, ctx: tls.SecureContext) => any) => any; - } - - export interface RequestOptions extends http.RequestOptions { - pfx?: any; - key?: any; - passphrase?: string; - cert?: any; - ca?: any; - ciphers?: string; - rejectUnauthorized?: boolean; - secureProtocol?: string; - } - - export interface Agent extends http.Agent { } - - export interface AgentOptions extends http.AgentOptions { - pfx?: any; - key?: any; - passphrase?: string; - cert?: any; - ca?: any; - ciphers?: string; - rejectUnauthorized?: boolean; - secureProtocol?: string; - maxCachedSessions?: number; - } - - export var Agent: { - new (options?: AgentOptions): Agent; - }; - export interface Server extends tls.Server { } - export function createServer(options: ServerOptions, requestListener?: Function): Server; - export function request(options: RequestOptions, callback?: (res: http.IncomingMessage) => void): http.ClientRequest; - export function get(options: RequestOptions, callback?: (res: http.IncomingMessage) => void): http.ClientRequest; - export var globalAgent: Agent; -} - -declare module "punycode" { - export function decode(string: string): string; - export function encode(string: string): string; - export function toUnicode(domain: string): string; - export function toASCII(domain: string): string; - export var ucs2: ucs2; - interface ucs2 { - decode(string: string): number[]; - encode(codePoints: number[]): string; - } - export var version: any; -} - -declare module "repl" { - import * as stream from "stream"; - import * as readline from "readline"; - - export interface ReplOptions { - prompt?: string; - input?: NodeJS.ReadableStream; - output?: NodeJS.WritableStream; - terminal?: boolean; - eval?: Function; - useColors?: boolean; - useGlobal?: boolean; - ignoreUndefined?: boolean; - writer?: Function; - completer?: Function; - replMode?: any; - breakEvalOnSigint?: any; - } - - export interface REPLServer extends readline.ReadLine { - defineCommand(keyword: string, cmd: Function | { help: string, action: Function }): void; - displayPrompt(preserveCursor?: boolean): void - } - - export function start(options: ReplOptions): REPLServer; -} - -declare module "readline" { - import * as events from "events"; - import * as stream from "stream"; - - export interface Key { - sequence?: string; - name?: string; - ctrl?: boolean; - meta?: boolean; - shift?: boolean; - } - - export interface ReadLine extends events.EventEmitter { - setPrompt(prompt: string): void; - prompt(preserveCursor?: boolean): void; - question(query: string, callback: (answer: string) => void): void; - pause(): ReadLine; - resume(): ReadLine; - close(): void; - write(data: string | Buffer, key?: Key): void; - } - - export interface Completer { - (line: string): CompleterResult; - (line: string, callback: (err: any, result: CompleterResult) => void): any; - } - - export interface CompleterResult { - completions: string[]; - line: string; - } - - export interface ReadLineOptions { - input: NodeJS.ReadableStream; - output?: NodeJS.WritableStream; - completer?: Completer; - terminal?: boolean; - historySize?: number; - } - - export function createInterface(input: NodeJS.ReadableStream, output?: NodeJS.WritableStream, completer?: Completer, terminal?: boolean): ReadLine; - export function createInterface(options: ReadLineOptions): ReadLine; - - export function cursorTo(stream: NodeJS.WritableStream, x: number, y: number): void; - export function moveCursor(stream: NodeJS.WritableStream, dx: number | string, dy: number | string): void; - export function clearLine(stream: NodeJS.WritableStream, dir: number): void; - export function clearScreenDown(stream: NodeJS.WritableStream): void; -} - -declare module "vm" { - export interface Context { } - export interface ScriptOptions { - filename?: string; - lineOffset?: number; - columnOffset?: number; - displayErrors?: boolean; - timeout?: number; - cachedData?: Buffer; - produceCachedData?: boolean; - } - export interface RunningScriptOptions { - filename?: string; - lineOffset?: number; - columnOffset?: number; - displayErrors?: boolean; - timeout?: number; - } - export class Script { - constructor(code: string, options?: ScriptOptions); - runInContext(contextifiedSandbox: Context, options?: RunningScriptOptions): any; - runInNewContext(sandbox?: Context, options?: RunningScriptOptions): any; - runInThisContext(options?: RunningScriptOptions): any; - } - export function createContext(sandbox?: Context): Context; - export function isContext(sandbox: Context): boolean; - export function runInContext(code: string, contextifiedSandbox: Context, options?: RunningScriptOptions): any; - export function runInDebugContext(code: string): any; - export function runInNewContext(code: string, sandbox?: Context, options?: RunningScriptOptions): any; - export function runInThisContext(code: string, options?: RunningScriptOptions): any; -} - -declare module "child_process" { - import * as events from "events"; - import * as stream from "stream"; - - export interface ChildProcess extends events.EventEmitter { - stdin: stream.Writable; - stdout: stream.Readable; - stderr: stream.Readable; - stdio: [stream.Writable, stream.Readable, stream.Readable]; - pid: number; - kill(signal?: string): void; - send(message: any, sendHandle?: any): boolean; - connected: boolean; - disconnect(): void; - unref(): void; - ref(): void; - } - - export interface SpawnOptions { - cwd?: string; - env?: any; - stdio?: any; - detached?: boolean; - uid?: number; - gid?: number; - shell?: boolean | string; - } - export function spawn(command: string, args?: string[], options?: SpawnOptions): ChildProcess; - - export interface ExecOptions { - cwd?: string; - env?: any; - shell?: string; - timeout?: number; - maxBuffer?: number; - killSignal?: string; - uid?: number; - gid?: number; - } - export interface ExecOptionsWithStringEncoding extends ExecOptions { - encoding: BufferEncoding; - } - export interface ExecOptionsWithBufferEncoding extends ExecOptions { - encoding: string; // specify `null`. - } - export function exec(command: string, callback?: (error: Error, stdout: string, stderr: string) => void): ChildProcess; - export function exec(command: string, options: ExecOptionsWithStringEncoding, callback?: (error: Error, stdout: string, stderr: string) => void): ChildProcess; - // usage. child_process.exec("tsc", {encoding: null as string}, (err, stdout, stderr) => {}); - export function exec(command: string, options: ExecOptionsWithBufferEncoding, callback?: (error: Error, stdout: Buffer, stderr: Buffer) => void): ChildProcess; - export function exec(command: string, options: ExecOptions, callback?: (error: Error, stdout: string, stderr: string) => void): ChildProcess; - - export interface ExecFileOptions { - cwd?: string; - env?: any; - timeout?: number; - maxBuffer?: number; - killSignal?: string; - uid?: number; - gid?: number; - } - export interface ExecFileOptionsWithStringEncoding extends ExecFileOptions { - encoding: BufferEncoding; - } - export interface ExecFileOptionsWithBufferEncoding extends ExecFileOptions { - encoding: string; // specify `null`. - } - export function execFile(file: string, callback?: (error: Error, stdout: string, stderr: string) => void): ChildProcess; - export function execFile(file: string, options?: ExecFileOptionsWithStringEncoding, callback?: (error: Error, stdout: string, stderr: string) => void): ChildProcess; - // usage. child_process.execFile("file.sh", {encoding: null as string}, (err, stdout, stderr) => {}); - export function execFile(file: string, options?: ExecFileOptionsWithBufferEncoding, callback?: (error: Error, stdout: Buffer, stderr: Buffer) => void): ChildProcess; - export function execFile(file: string, options?: ExecFileOptions, callback?: (error: Error, stdout: string, stderr: string) => void): ChildProcess; - export function execFile(file: string, args?: string[], callback?: (error: Error, stdout: string, stderr: string) => void): ChildProcess; - export function execFile(file: string, args?: string[], options?: ExecFileOptionsWithStringEncoding, callback?: (error: Error, stdout: string, stderr: string) => void): ChildProcess; - // usage. child_process.execFile("file.sh", ["foo"], {encoding: null as string}, (err, stdout, stderr) => {}); - export function execFile(file: string, args?: string[], options?: ExecFileOptionsWithBufferEncoding, callback?: (error: Error, stdout: Buffer, stderr: Buffer) => void): ChildProcess; - export function execFile(file: string, args?: string[], options?: ExecFileOptions, callback?: (error: Error, stdout: string, stderr: string) => void): ChildProcess; - - export interface ForkOptions { - cwd?: string; - env?: any; - execPath?: string; - execArgv?: string[]; - silent?: boolean; - uid?: number; - gid?: number; - } - export function fork(modulePath: string, args?: string[], options?: ForkOptions): ChildProcess; - - export interface SpawnSyncOptions { - cwd?: string; - input?: string | Buffer; - stdio?: any; - env?: any; - uid?: number; - gid?: number; - timeout?: number; - killSignal?: string; - maxBuffer?: number; - encoding?: string; - shell?: boolean | string; - } - export interface SpawnSyncOptionsWithStringEncoding extends SpawnSyncOptions { - encoding: BufferEncoding; - } - export interface SpawnSyncOptionsWithBufferEncoding extends SpawnSyncOptions { - encoding: string; // specify `null`. - } - export interface SpawnSyncReturns { - pid: number; - output: string[]; - stdout: T; - stderr: T; - status: number; - signal: string; - error: Error; - } - export function spawnSync(command: string): SpawnSyncReturns; - export function spawnSync(command: string, options?: SpawnSyncOptionsWithStringEncoding): SpawnSyncReturns; - export function spawnSync(command: string, options?: SpawnSyncOptionsWithBufferEncoding): SpawnSyncReturns; - export function spawnSync(command: string, options?: SpawnSyncOptions): SpawnSyncReturns; - export function spawnSync(command: string, args?: string[], options?: SpawnSyncOptionsWithStringEncoding): SpawnSyncReturns; - export function spawnSync(command: string, args?: string[], options?: SpawnSyncOptionsWithBufferEncoding): SpawnSyncReturns; - export function spawnSync(command: string, args?: string[], options?: SpawnSyncOptions): SpawnSyncReturns; - - export interface ExecSyncOptions { - cwd?: string; - input?: string | Buffer; - stdio?: any; - env?: any; - shell?: string; - uid?: number; - gid?: number; - timeout?: number; - killSignal?: string; - maxBuffer?: number; - encoding?: string; - } - export interface ExecSyncOptionsWithStringEncoding extends ExecSyncOptions { - encoding: BufferEncoding; - } - export interface ExecSyncOptionsWithBufferEncoding extends ExecSyncOptions { - encoding: string; // specify `null`. - } - export function execSync(command: string): Buffer; - export function execSync(command: string, options?: ExecSyncOptionsWithStringEncoding): string; - export function execSync(command: string, options?: ExecSyncOptionsWithBufferEncoding): Buffer; - export function execSync(command: string, options?: ExecSyncOptions): Buffer; - - export interface ExecFileSyncOptions { - cwd?: string; - input?: string | Buffer; - stdio?: any; - env?: any; - uid?: number; - gid?: number; - timeout?: number; - killSignal?: string; - maxBuffer?: number; - encoding?: string; - } - export interface ExecFileSyncOptionsWithStringEncoding extends ExecFileSyncOptions { - encoding: BufferEncoding; - } - export interface ExecFileSyncOptionsWithBufferEncoding extends ExecFileSyncOptions { - encoding: string; // specify `null`. - } - export function execFileSync(command: string): Buffer; - export function execFileSync(command: string, options?: ExecFileSyncOptionsWithStringEncoding): string; - export function execFileSync(command: string, options?: ExecFileSyncOptionsWithBufferEncoding): Buffer; - export function execFileSync(command: string, options?: ExecFileSyncOptions): Buffer; - export function execFileSync(command: string, args?: string[], options?: ExecFileSyncOptionsWithStringEncoding): string; - export function execFileSync(command: string, args?: string[], options?: ExecFileSyncOptionsWithBufferEncoding): Buffer; - export function execFileSync(command: string, args?: string[], options?: ExecFileSyncOptions): Buffer; -} - -declare module "url" { - export interface Url { - href?: string; - protocol?: string; - auth?: string; - hostname?: string; - port?: string; - host?: string; - pathname?: string; - search?: string; - query?: string | any; - slashes?: boolean; - hash?: string; - path?: string; - } - - export function parse(urlStr: string, parseQueryString?: boolean, slashesDenoteHost?: boolean): Url; - export function format(url: Url): string; - export function resolve(from: string, to: string): string; -} - -declare module "dns" { - export interface MxRecord { - exchange: string, - priority: number - } - - export function lookup(domain: string, family: number, callback: (err: Error, address: string, family: number) => void): string; - export function lookup(domain: string, callback: (err: Error, address: string, family: number) => void): string; - export function resolve(domain: string, rrtype: string, callback: (err: Error, addresses: string[]) => void): string[]; - export function resolve(domain: string, callback: (err: Error, addresses: string[]) => void): string[]; - export function resolve4(domain: string, callback: (err: Error, addresses: string[]) => void): string[]; - export function resolve6(domain: string, callback: (err: Error, addresses: string[]) => void): string[]; - export function resolveMx(domain: string, callback: (err: Error, addresses: MxRecord[]) =>void ): string[]; - export function resolveTxt(domain: string, callback: (err: Error, addresses: string[]) => void): string[]; - export function resolveSrv(domain: string, callback: (err: Error, addresses: string[]) => void): string[]; - export function resolveNs(domain: string, callback: (err: Error, addresses: string[]) => void): string[]; - export function resolveCname(domain: string, callback: (err: Error, addresses: string[]) => void): string[]; - export function reverse(ip: string, callback: (err: Error, domains: string[]) => void): string[]; - export function setServers(servers: string[]): void; - - //Error codes - export var NODATA: string; - export var FORMERR: string; - export var SERVFAIL: string; - export var NOTFOUND: string; - export var NOTIMP: string; - export var REFUSED: string; - export var BADQUERY: string; - export var BADNAME: string; - export var BADFAMILY: string; - export var BADRESP: string; - export var CONNREFUSED: string; - export var TIMEOUT: string; - export var EOF: string; - export var FILE: string; - export var NOMEM: string; - export var DESTRUCTION: string; - export var BADSTR: string; - export var BADFLAGS: string; - export var NONAME: string; - export var BADHINTS: string; - export var NOTINITIALIZED: string; - export var LOADIPHLPAPI: string; - export var ADDRGETNETWORKPARAMS: string; - export var CANCELLED: string; -} - -declare module "net" { - import * as stream from "stream"; - - export interface Socket extends stream.Duplex { - // Extended base methods - write(buffer: Buffer): boolean; - write(buffer: Buffer, cb?: Function): boolean; - write(str: string, cb?: Function): boolean; - write(str: string, encoding?: string, cb?: Function): boolean; - write(str: string, encoding?: string, fd?: string): boolean; - - connect(port: number, host?: string, connectionListener?: Function): void; - connect(path: string, connectionListener?: Function): void; - bufferSize: number; - setEncoding(encoding?: string): void; - write(data: any, encoding?: string, callback?: Function): void; - destroy(): void; - pause(): Socket; - resume(): Socket; - setTimeout(timeout: number, callback?: Function): void; - setNoDelay(noDelay?: boolean): void; - setKeepAlive(enable?: boolean, initialDelay?: number): void; - address(): { port: number; family: string; address: string; }; - unref(): void; - ref(): void; - - remoteAddress: string; - remoteFamily: string; - remotePort: number; - localAddress: string; - localPort: number; - bytesRead: number; - bytesWritten: number; - - // Extended base methods - end(): void; - end(buffer: Buffer, cb?: Function): void; - end(str: string, cb?: Function): void; - end(str: string, encoding?: string, cb?: Function): void; - end(data?: any, encoding?: string): void; - } - - export var Socket: { - new (options?: { fd?: string; type?: string; allowHalfOpen?: boolean; }): Socket; - }; - - export interface ListenOptions { - port?: number; - host?: string; - backlog?: number; - path?: string; - exclusive?: boolean; - } - - export interface Server extends Socket { - listen(port: number, hostname?: string, backlog?: number, listeningListener?: Function): Server; - listen(port: number, hostname?: string, listeningListener?: Function): Server; - listen(port: number, backlog?: number, listeningListener?: Function): Server; - listen(port: number, listeningListener?: Function): Server; - listen(path: string, backlog?: number, listeningListener?: Function): Server; - listen(path: string, listeningListener?: Function): Server; - listen(handle: any, backlog?: number, listeningListener?: Function): Server; - listen(handle: any, listeningListener?: Function): Server; - listen(options: ListenOptions, listeningListener?: Function): Server; - close(callback?: Function): Server; - address(): { port: number; family: string; address: string; }; - getConnections(cb: (error: Error, count: number) => void): void; - ref(): Server; - unref(): Server; - maxConnections: number; - connections: number; - } - export function createServer(connectionListener?: (socket: Socket) => void): Server; - export function createServer(options?: { allowHalfOpen?: boolean; }, connectionListener?: (socket: Socket) => void): Server; - export function connect(options: { port: number, host?: string, localAddress?: string, localPort?: string, family?: number, allowHalfOpen?: boolean; }, connectionListener?: Function): Socket; - export function connect(port: number, host?: string, connectionListener?: Function): Socket; - export function connect(path: string, connectionListener?: Function): Socket; - export function createConnection(options: { port: number, host?: string, localAddress?: string, localPort?: string, family?: number, allowHalfOpen?: boolean; }, connectionListener?: Function): Socket; - export function createConnection(port: number, host?: string, connectionListener?: Function): Socket; - export function createConnection(path: string, connectionListener?: Function): Socket; - export function isIP(input: string): number; - export function isIPv4(input: string): boolean; - export function isIPv6(input: string): boolean; -} - -declare module "dgram" { - import * as events from "events"; - - interface RemoteInfo { - address: string; - port: number; - size: number; - } - - interface AddressInfo { - address: string; - family: string; - port: number; - } - - interface BindOptions { - port: number; - address?: string; - exclusive?: boolean; - } - - interface SocketOptions { - type: "udp4" | "udp6"; - reuseAddr?: boolean; - } - - export function createSocket(type: string, callback?: (msg: Buffer, rinfo: RemoteInfo) => void): Socket; - export function createSocket(options: SocketOptions, callback?: (msg: Buffer, rinfo: RemoteInfo) => void): Socket; - - export interface Socket extends events.EventEmitter { - send(msg: Buffer | String | any[], port: number, address: string, callback?: (error: Error, bytes: number) => void): void; - send(msg: Buffer | String | any[], offset: number, length: number, port: number, address: string, callback?: (error: Error, bytes: number) => void): void; - bind(port?: number, address?: string, callback?: () => void): void; - bind(options: BindOptions, callback?: Function): void; - close(callback?: any): void; - address(): AddressInfo; - setBroadcast(flag: boolean): void; - setTTL(ttl: number): void; - setMulticastTTL(ttl: number): void; - setMulticastLoopback(flag: boolean): void; - addMembership(multicastAddress: string, multicastInterface?: string): void; - dropMembership(multicastAddress: string, multicastInterface?: string): void; - ref(): void; - unref(): void; - } -} - -declare module "fs" { - import * as stream from "stream"; - import * as events from "events"; - - interface Stats { - isFile(): boolean; - isDirectory(): boolean; - isBlockDevice(): boolean; - isCharacterDevice(): boolean; - isSymbolicLink(): boolean; - isFIFO(): boolean; - isSocket(): boolean; - dev: number; - ino: number; - mode: number; - nlink: number; - uid: number; - gid: number; - rdev: number; - size: number; - blksize: number; - blocks: number; - atime: Date; - mtime: Date; - ctime: Date; - birthtime: Date; - } - - interface FSWatcher extends events.EventEmitter { - close(): void; - - /** - * events.EventEmitter - * 1. change - * 2. error - */ - addListener(event: string, listener: Function): this; - addListener(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this; - addListener(event: "error", listener: (code: number, signal: string) => void): this; - - on(event: string, listener: Function): this; - on(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this; - on(event: "error", listener: (code: number, signal: string) => void): this; - - once(event: string, listener: Function): this; - once(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this; - once(event: "error", listener: (code: number, signal: string) => void): this; - - prependListener(event: string, listener: Function): this; - prependListener(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this; - prependListener(event: "error", listener: (code: number, signal: string) => void): this; - - prependOnceListener(event: string, listener: Function): this; - prependOnceListener(event: "change", listener: (eventType: string, filename: string | Buffer) => void): this; - prependOnceListener(event: "error", listener: (code: number, signal: string) => void): this; - } - - export interface ReadStream extends stream.Readable { - close(): void; - destroy(): void; - - /** - * events.EventEmitter - * 1. open - * 2. close - */ - addListener(event: string, listener: Function): this; - addListener(event: "open", listener: (fd: number) => void): this; - addListener(event: "close", listener: () => void): this; - - on(event: string, listener: Function): this; - on(event: "open", listener: (fd: number) => void): this; - on(event: "close", listener: () => void): this; - - once(event: string, listener: Function): this; - once(event: "open", listener: (fd: number) => void): this; - once(event: "close", listener: () => void): this; - - prependListener(event: string, listener: Function): this; - prependListener(event: "open", listener: (fd: number) => void): this; - prependListener(event: "close", listener: () => void): this; - - prependOnceListener(event: string, listener: Function): this; - prependOnceListener(event: "open", listener: (fd: number) => void): this; - prependOnceListener(event: "close", listener: () => void): this; - } - - export interface WriteStream extends stream.Writable { - close(): void; - bytesWritten: number; - path: string | Buffer; - - /** - * events.EventEmitter - * 1. open - * 2. close - */ - addListener(event: string, listener: Function): this; - addListener(event: "open", listener: (fd: number) => void): this; - addListener(event: "close", listener: () => void): this; - - on(event: string, listener: Function): this; - on(event: "open", listener: (fd: number) => void): this; - on(event: "close", listener: () => void): this; - - once(event: string, listener: Function): this; - once(event: "open", listener: (fd: number) => void): this; - once(event: "close", listener: () => void): this; - - prependListener(event: string, listener: Function): this; - prependListener(event: "open", listener: (fd: number) => void): this; - prependListener(event: "close", listener: () => void): this; - - prependOnceListener(event: string, listener: Function): this; - prependOnceListener(event: "open", listener: (fd: number) => void): this; - prependOnceListener(event: "close", listener: () => void): this; - } - - /** - * Asynchronous rename. - * @param oldPath - * @param newPath - * @param callback No arguments other than a possible exception are given to the completion callback. - */ - export function rename(oldPath: string, newPath: string, callback?: (err?: NodeJS.ErrnoException) => void): void; - /** - * Synchronous rename - * @param oldPath - * @param newPath - */ - export function renameSync(oldPath: string, newPath: string): void; - export function truncate(path: string | Buffer, callback?: (err?: NodeJS.ErrnoException) => void): void; - export function truncate(path: string | Buffer, len: number, callback?: (err?: NodeJS.ErrnoException) => void): void; - export function truncateSync(path: string | Buffer, len?: number): void; - export function ftruncate(fd: number, callback?: (err?: NodeJS.ErrnoException) => void): void; - export function ftruncate(fd: number, len: number, callback?: (err?: NodeJS.ErrnoException) => void): void; - export function ftruncateSync(fd: number, len?: number): void; - export function chown(path: string | Buffer, uid: number, gid: number, callback?: (err?: NodeJS.ErrnoException) => void): void; - export function chownSync(path: string | Buffer, uid: number, gid: number): void; - export function fchown(fd: number, uid: number, gid: number, callback?: (err?: NodeJS.ErrnoException) => void): void; - export function fchownSync(fd: number, uid: number, gid: number): void; - export function lchown(path: string | Buffer, uid: number, gid: number, callback?: (err?: NodeJS.ErrnoException) => void): void; - export function lchownSync(path: string | Buffer, uid: number, gid: number): void; - export function chmod(path: string | Buffer, mode: number, callback?: (err?: NodeJS.ErrnoException) => void): void; - export function chmod(path: string | Buffer, mode: string, callback?: (err?: NodeJS.ErrnoException) => void): void; - export function chmodSync(path: string | Buffer, mode: number): void; - export function chmodSync(path: string | Buffer, mode: string): void; - export function fchmod(fd: number, mode: number, callback?: (err?: NodeJS.ErrnoException) => void): void; - export function fchmod(fd: number, mode: string, callback?: (err?: NodeJS.ErrnoException) => void): void; - export function fchmodSync(fd: number, mode: number): void; - export function fchmodSync(fd: number, mode: string): void; - export function lchmod(path: string | Buffer, mode: number, callback?: (err?: NodeJS.ErrnoException) => void): void; - export function lchmod(path: string | Buffer, mode: string, callback?: (err?: NodeJS.ErrnoException) => void): void; - export function lchmodSync(path: string | Buffer, mode: number): void; - export function lchmodSync(path: string | Buffer, mode: string): void; - export function stat(path: string | Buffer, callback?: (err: NodeJS.ErrnoException, stats: Stats) => any): void; - export function lstat(path: string | Buffer, callback?: (err: NodeJS.ErrnoException, stats: Stats) => any): void; - export function fstat(fd: number, callback?: (err: NodeJS.ErrnoException, stats: Stats) => any): void; - export function statSync(path: string | Buffer): Stats; - export function lstatSync(path: string | Buffer): Stats; - export function fstatSync(fd: number): Stats; - export function link(srcpath: string | Buffer, dstpath: string | Buffer, callback?: (err?: NodeJS.ErrnoException) => void): void; - export function linkSync(srcpath: string | Buffer, dstpath: string | Buffer): void; - export function symlink(srcpath: string | Buffer, dstpath: string | Buffer, type?: string, callback?: (err?: NodeJS.ErrnoException) => void): void; - export function symlinkSync(srcpath: string | Buffer, dstpath: string | Buffer, type?: string): void; - export function readlink(path: string | Buffer, callback?: (err: NodeJS.ErrnoException, linkString: string) => any): void; - export function readlinkSync(path: string | Buffer): string; - export function realpath(path: string | Buffer, callback?: (err: NodeJS.ErrnoException, resolvedPath: string) => any): void; - export function realpath(path: string | Buffer, cache: { [path: string]: string }, callback: (err: NodeJS.ErrnoException, resolvedPath: string) => any): void; - export function realpathSync(path: string | Buffer, cache?: { [path: string]: string }): string; - /* - * Asynchronous unlink - deletes the file specified in {path} - * - * @param path - * @param callback No arguments other than a possible exception are given to the completion callback. - */ - export function unlink(path: string | Buffer, callback?: (err?: NodeJS.ErrnoException) => void): void; - /* - * Synchronous unlink - deletes the file specified in {path} - * - * @param path - */ - export function unlinkSync(path: string | Buffer): void; - /* - * Asynchronous rmdir - removes the directory specified in {path} - * - * @param path - * @param callback No arguments other than a possible exception are given to the completion callback. - */ - export function rmdir(path: string | Buffer, callback?: (err?: NodeJS.ErrnoException) => void): void; - /* - * Synchronous rmdir - removes the directory specified in {path} - * - * @param path - */ - export function rmdirSync(path: string | Buffer): void; - /* - * Asynchronous mkdir - creates the directory specified in {path}. Parameter {mode} defaults to 0777. - * - * @param path - * @param callback No arguments other than a possible exception are given to the completion callback. - */ - export function mkdir(path: string | Buffer, callback?: (err?: NodeJS.ErrnoException) => void): void; - /* - * Asynchronous mkdir - creates the directory specified in {path}. Parameter {mode} defaults to 0777. - * - * @param path - * @param mode - * @param callback No arguments other than a possible exception are given to the completion callback. - */ - export function mkdir(path: string | Buffer, mode: number, callback?: (err?: NodeJS.ErrnoException) => void): void; - /* - * Asynchronous mkdir - creates the directory specified in {path}. Parameter {mode} defaults to 0777. - * - * @param path - * @param mode - * @param callback No arguments other than a possible exception are given to the completion callback. - */ - export function mkdir(path: string | Buffer, mode: string, callback?: (err?: NodeJS.ErrnoException) => void): void; - /* - * Synchronous mkdir - creates the directory specified in {path}. Parameter {mode} defaults to 0777. - * - * @param path - * @param mode - * @param callback No arguments other than a possible exception are given to the completion callback. - */ - export function mkdirSync(path: string | Buffer, mode?: number): void; - /* - * Synchronous mkdir - creates the directory specified in {path}. Parameter {mode} defaults to 0777. - * - * @param path - * @param mode - * @param callback No arguments other than a possible exception are given to the completion callback. - */ - export function mkdirSync(path: string | Buffer, mode?: string): void; - /* - * Asynchronous mkdtemp - Creates a unique temporary directory. Generates six random characters to be appended behind a required prefix to create a unique temporary directory. - * - * @param prefix - * @param callback The created folder path is passed as a string to the callback's second parameter. - */ - export function mkdtemp(prefix: string, callback?: (err: NodeJS.ErrnoException, folder: string) => void): void; - /* - * Synchronous mkdtemp - Creates a unique temporary directory. Generates six random characters to be appended behind a required prefix to create a unique temporary directory. - * - * @param prefix - * @returns Returns the created folder path. - */ - export function mkdtempSync(prefix: string): string; - export function readdir(path: string | Buffer, callback?: (err: NodeJS.ErrnoException, files: string[]) => void): void; - export function readdirSync(path: string | Buffer): string[]; - export function close(fd: number, callback?: (err?: NodeJS.ErrnoException) => void): void; - export function closeSync(fd: number): void; - export function open(path: string | Buffer, flags: string | number, callback: (err: NodeJS.ErrnoException, fd: number) => void): void; - export function open(path: string | Buffer, flags: string | number, mode: number, callback: (err: NodeJS.ErrnoException, fd: number) => void): void; - export function openSync(path: string | Buffer, flags: string | number, mode?: number): number; - export function utimes(path: string | Buffer, atime: number, mtime: number, callback?: (err?: NodeJS.ErrnoException) => void): void; - export function utimes(path: string | Buffer, atime: Date, mtime: Date, callback?: (err?: NodeJS.ErrnoException) => void): void; - export function utimesSync(path: string | Buffer, atime: number, mtime: number): void; - export function utimesSync(path: string | Buffer, atime: Date, mtime: Date): void; - export function futimes(fd: number, atime: number, mtime: number, callback?: (err?: NodeJS.ErrnoException) => void): void; - export function futimes(fd: number, atime: Date, mtime: Date, callback?: (err?: NodeJS.ErrnoException) => void): void; - export function futimesSync(fd: number, atime: number, mtime: number): void; - export function futimesSync(fd: number, atime: Date, mtime: Date): void; - export function fsync(fd: number, callback?: (err?: NodeJS.ErrnoException) => void): void; - export function fsyncSync(fd: number): void; - export function write(fd: number, buffer: Buffer, offset: number, length: number, position: number, callback?: (err: NodeJS.ErrnoException, written: number, buffer: Buffer) => void): void; - export function write(fd: number, buffer: Buffer, offset: number, length: number, callback?: (err: NodeJS.ErrnoException, written: number, buffer: Buffer) => void): void; - export function write(fd: number, data: any, callback?: (err: NodeJS.ErrnoException, written: number, str: string) => void): void; - export function write(fd: number, data: any, offset: number, callback?: (err: NodeJS.ErrnoException, written: number, str: string) => void): void; - export function write(fd: number, data: any, offset: number, encoding: string, callback?: (err: NodeJS.ErrnoException, written: number, str: string) => void): void; - export function writeSync(fd: number, buffer: Buffer, offset: number, length: number, position?: number): number; - export function writeSync(fd: number, data: any, position?: number, enconding?: string): number; - export function read(fd: number, buffer: Buffer, offset: number, length: number, position: number, callback?: (err: NodeJS.ErrnoException, bytesRead: number, buffer: Buffer) => void): void; - export function readSync(fd: number, buffer: Buffer, offset: number, length: number, position: number): number; - /* - * Asynchronous readFile - Asynchronously reads the entire contents of a file. - * - * @param fileName - * @param encoding - * @param callback - The callback is passed two arguments (err, data), where data is the contents of the file. - */ - export function readFile(filename: string, encoding: string, callback: (err: NodeJS.ErrnoException, data: string) => void): void; - /* - * Asynchronous readFile - Asynchronously reads the entire contents of a file. - * - * @param fileName - * @param options An object with optional {encoding} and {flag} properties. If {encoding} is specified, readFile returns a string; otherwise it returns a Buffer. - * @param callback - The callback is passed two arguments (err, data), where data is the contents of the file. - */ - export function readFile(filename: string, options: { encoding: string; flag?: string; }, callback: (err: NodeJS.ErrnoException, data: string) => void): void; - /* - * Asynchronous readFile - Asynchronously reads the entire contents of a file. - * - * @param fileName - * @param options An object with optional {encoding} and {flag} properties. If {encoding} is specified, readFile returns a string; otherwise it returns a Buffer. - * @param callback - The callback is passed two arguments (err, data), where data is the contents of the file. - */ - export function readFile(filename: string, options: { flag?: string; }, callback: (err: NodeJS.ErrnoException, data: Buffer) => void): void; - /* - * Asynchronous readFile - Asynchronously reads the entire contents of a file. - * - * @param fileName - * @param callback - The callback is passed two arguments (err, data), where data is the contents of the file. - */ - export function readFile(filename: string, callback: (err: NodeJS.ErrnoException, data: Buffer) => void): void; - /* - * Synchronous readFile - Synchronously reads the entire contents of a file. - * - * @param fileName - * @param encoding - */ - export function readFileSync(filename: string, encoding: string): string; - /* - * Synchronous readFile - Synchronously reads the entire contents of a file. - * - * @param fileName - * @param options An object with optional {encoding} and {flag} properties. If {encoding} is specified, readFileSync returns a string; otherwise it returns a Buffer. - */ - export function readFileSync(filename: string, options: { encoding: string; flag?: string; }): string; - /* - * Synchronous readFile - Synchronously reads the entire contents of a file. - * - * @param fileName - * @param options An object with optional {encoding} and {flag} properties. If {encoding} is specified, readFileSync returns a string; otherwise it returns a Buffer. - */ - export function readFileSync(filename: string, options?: { flag?: string; }): Buffer; - export function writeFile(filename: string, data: any, callback?: (err: NodeJS.ErrnoException) => void): void; - export function writeFile(filename: string, data: any, options: { encoding?: string; mode?: number; flag?: string; }, callback?: (err: NodeJS.ErrnoException) => void): void; - export function writeFile(filename: string, data: any, options: { encoding?: string; mode?: string; flag?: string; }, callback?: (err: NodeJS.ErrnoException) => void): void; - export function writeFileSync(filename: string, data: any, options?: { encoding?: string; mode?: number; flag?: string; }): void; - export function writeFileSync(filename: string, data: any, options?: { encoding?: string; mode?: string; flag?: string; }): void; - export function appendFile(filename: string, data: any, options: { encoding?: string; mode?: number; flag?: string; }, callback?: (err: NodeJS.ErrnoException) => void): void; - export function appendFile(filename: string, data: any, options: { encoding?: string; mode?: string; flag?: string; }, callback?: (err: NodeJS.ErrnoException) => void): void; - export function appendFile(filename: string, data: any, callback?: (err: NodeJS.ErrnoException) => void): void; - export function appendFileSync(filename: string, data: any, options?: { encoding?: string; mode?: number; flag?: string; }): void; - export function appendFileSync(filename: string, data: any, options?: { encoding?: string; mode?: string; flag?: string; }): void; - export function watchFile(filename: string, listener: (curr: Stats, prev: Stats) => void): void; - export function watchFile(filename: string, options: { persistent?: boolean; interval?: number; }, listener: (curr: Stats, prev: Stats) => void): void; - export function unwatchFile(filename: string, listener?: (curr: Stats, prev: Stats) => void): void; - export function watch(filename: string, listener?: (event: string, filename: string) => any): FSWatcher; - export function watch(filename: string, encoding: string, listener?: (event: string, filename: string | Buffer) => any): FSWatcher; - export function watch(filename: string, options: { persistent?: boolean; recursive?: boolean; encoding?: string }, listener?: (event: string, filename: string | Buffer) => any): FSWatcher; - export function exists(path: string | Buffer, callback?: (exists: boolean) => void): void; - export function existsSync(path: string | Buffer): boolean; - - interface Constants { - /** Constant for fs.access(). File is visible to the calling process. */ - F_OK: number; - - /** Constant for fs.access(). File can be read by the calling process. */ - R_OK: number; - - /** Constant for fs.access(). File can be written by the calling process. */ - W_OK: number; - - /** Constant for fs.access(). File can be executed by the calling process. */ - X_OK: number; - } - - export const constants: Constants; - - /** Tests a user's permissions for the file specified by path. */ - export function access(path: string | Buffer, callback: (err: NodeJS.ErrnoException) => void): void; - export function access(path: string | Buffer, mode: number, callback: (err: NodeJS.ErrnoException) => void): void; - /** Synchronous version of fs.access. This throws if any accessibility checks fail, and does nothing otherwise. */ - export function accessSync(path: string | Buffer, mode?: number): void; - export function createReadStream(path: string | Buffer, options?: { - flags?: string; - encoding?: string; - fd?: number; - mode?: number; - autoClose?: boolean; - start?: number; - end?: number; - }): ReadStream; - export function createWriteStream(path: string | Buffer, options?: { - flags?: string; - encoding?: string; - fd?: number; - mode?: number; - }): WriteStream; - export function fdatasync(fd: number, callback: Function): void; - export function fdatasyncSync(fd: number): void; -} - -declare module "path" { - - /** - * A parsed path object generated by path.parse() or consumed by path.format(). - */ - export interface ParsedPath { - /** - * The root of the path such as '/' or 'c:\' - */ - root: string; - /** - * The full directory path such as '/home/user/dir' or 'c:\path\dir' - */ - dir: string; - /** - * The file name including extension (if any) such as 'index.html' - */ - base: string; - /** - * The file extension (if any) such as '.html' - */ - ext: string; - /** - * The file name without extension (if any) such as 'index' - */ - name: string; - } - - /** - * Normalize a string path, reducing '..' and '.' parts. - * When multiple slashes are found, they're replaced by a single one; when the path contains a trailing slash, it is preserved. On Windows backslashes are used. - * - * @param p string path to normalize. - */ - export function normalize(p: string): string; - /** - * Join all arguments together and normalize the resulting path. - * Arguments must be strings. In v0.8, non-string arguments were silently ignored. In v0.10 and up, an exception is thrown. - * - * @param paths string paths to join. - */ - export function join(...paths: any[]): string; - /** - * Join all arguments together and normalize the resulting path. - * Arguments must be strings. In v0.8, non-string arguments were silently ignored. In v0.10 and up, an exception is thrown. - * - * @param paths string paths to join. - */ - export function join(...paths: string[]): string; - /** - * The right-most parameter is considered {to}. Other parameters are considered an array of {from}. - * - * Starting from leftmost {from} paramter, resolves {to} to an absolute path. - * - * If {to} isn't already absolute, {from} arguments are prepended in right to left order, until an absolute path is found. If after using all {from} paths still no absolute path is found, the current working directory is used as well. The resulting path is normalized, and trailing slashes are removed unless the path gets resolved to the root directory. - * - * @param pathSegments string paths to join. Non-string arguments are ignored. - */ - export function resolve(...pathSegments: any[]): string; - /** - * Determines whether {path} is an absolute path. An absolute path will always resolve to the same location, regardless of the working directory. - * - * @param path path to test. - */ - export function isAbsolute(path: string): boolean; - /** - * Solve the relative path from {from} to {to}. - * At times we have two absolute paths, and we need to derive the relative path from one to the other. This is actually the reverse transform of path.resolve. - * - * @param from - * @param to - */ - export function relative(from: string, to: string): string; - /** - * Return the directory name of a path. Similar to the Unix dirname command. - * - * @param p the path to evaluate. - */ - export function dirname(p: string): string; - /** - * Return the last portion of a path. Similar to the Unix basename command. - * Often used to extract the file name from a fully qualified path. - * - * @param p the path to evaluate. - * @param ext optionally, an extension to remove from the result. - */ - export function basename(p: string, ext?: string): string; - /** - * Return the extension of the path, from the last '.' to end of string in the last portion of the path. - * If there is no '.' in the last portion of the path or the first character of it is '.', then it returns an empty string - * - * @param p the path to evaluate. - */ - export function extname(p: string): string; - /** - * The platform-specific file separator. '\\' or '/'. - */ - export var sep: string; - /** - * The platform-specific file delimiter. ';' or ':'. - */ - export var delimiter: string; - /** - * Returns an object from a path string - the opposite of format(). - * - * @param pathString path to evaluate. - */ - export function parse(pathString: string): ParsedPath; - /** - * Returns a path string from an object - the opposite of parse(). - * - * @param pathString path to evaluate. - */ - export function format(pathObject: ParsedPath): string; - - export module posix { - export function normalize(p: string): string; - export function join(...paths: any[]): string; - export function resolve(...pathSegments: any[]): string; - export function isAbsolute(p: string): boolean; - export function relative(from: string, to: string): string; - export function dirname(p: string): string; - export function basename(p: string, ext?: string): string; - export function extname(p: string): string; - export var sep: string; - export var delimiter: string; - export function parse(p: string): ParsedPath; - export function format(pP: ParsedPath): string; - } - - export module win32 { - export function normalize(p: string): string; - export function join(...paths: any[]): string; - export function resolve(...pathSegments: any[]): string; - export function isAbsolute(p: string): boolean; - export function relative(from: string, to: string): string; - export function dirname(p: string): string; - export function basename(p: string, ext?: string): string; - export function extname(p: string): string; - export var sep: string; - export var delimiter: string; - export function parse(p: string): ParsedPath; - export function format(pP: ParsedPath): string; - } -} - -declare module "string_decoder" { - export interface NodeStringDecoder { - write(buffer: Buffer): string; - end(buffer?: Buffer): string; - } - export var StringDecoder: { - new (encoding?: string): NodeStringDecoder; - }; -} - -declare module "tls" { - import * as crypto from "crypto"; - import * as net from "net"; - import * as stream from "stream"; - - var CLIENT_RENEG_LIMIT: number; - var CLIENT_RENEG_WINDOW: number; - - export interface Certificate { - /** - * Country code. - */ - C: string; - /** - * Street. - */ - ST: string; - /** - * Locality. - */ - L: string; - /** - * Organization. - */ - O: string; - /** - * Organizational unit. - */ - OU: string; - /** - * Common name. - */ - CN: string; - } - - export interface CipherNameAndProtocol { - /** - * The cipher name. - */ - name: string; - /** - * SSL/TLS protocol version. - */ - version: string; - } - - export class TLSSocket extends stream.Duplex { - /** - * Returns the bound address, the address family name and port of the underlying socket as reported by - * the operating system. - * @returns {any} - An object with three properties, e.g. { port: 12346, family: 'IPv4', address: '127.0.0.1' }. - */ - address(): { port: number; family: string; address: string }; - /** - * A boolean that is true if the peer certificate was signed by one of the specified CAs, otherwise false. - */ - authorized: boolean; - /** - * The reason why the peer's certificate has not been verified. - * This property becomes available only when tlsSocket.authorized === false. - */ - authorizationError: Error; - /** - * Static boolean value, always true. - * May be used to distinguish TLS sockets from regular ones. - */ - encrypted: boolean; - /** - * Returns an object representing the cipher name and the SSL/TLS protocol version of the current connection. - * @returns {CipherNameAndProtocol} - Returns an object representing the cipher name - * and the SSL/TLS protocol version of the current connection. - */ - getCipher(): CipherNameAndProtocol; - /** - * Returns an object representing the peer's certificate. - * The returned object has some properties corresponding to the field of the certificate. - * If detailed argument is true the full chain with issuer property will be returned, - * if false only the top certificate without issuer property. - * If the peer does not provide a certificate, it returns null or an empty object. - * @param {boolean} detailed - If true; the full chain with issuer property will be returned. - * @returns {any} - An object representing the peer's certificate. - */ - getPeerCertificate(detailed?: boolean): { - subject: Certificate; - issuerInfo: Certificate; - issuer: Certificate; - raw: any; - valid_from: string; - valid_to: string; - fingerprint: string; - serialNumber: string; - }; - /** - * Could be used to speed up handshake establishment when reconnecting to the server. - * @returns {any} - ASN.1 encoded TLS session or undefined if none was negotiated. - */ - getSession(): any; - /** - * NOTE: Works only with client TLS sockets. - * Useful only for debugging, for session reuse provide session option to tls.connect(). - * @returns {any} - TLS session ticket or undefined if none was negotiated. - */ - getTLSTicket(): any; - /** - * The string representation of the local IP address. - */ - localAddress: string; - /** - * The numeric representation of the local port. - */ - localPort: string; - /** - * The string representation of the remote IP address. - * For example, '74.125.127.100' or '2001:4860:a005::68'. - */ - remoteAddress: string; - /** - * The string representation of the remote IP family. 'IPv4' or 'IPv6'. - */ - remoteFamily: string; - /** - * The numeric representation of the remote port. For example, 443. - */ - remotePort: number; - /** - * Initiate TLS renegotiation process. - * - * NOTE: Can be used to request peer's certificate after the secure connection has been established. - * ANOTHER NOTE: When running as the server, socket will be destroyed with an error after handshakeTimeout timeout. - * @param {TlsOptions} options - The options may contain the following fields: rejectUnauthorized, - * requestCert (See tls.createServer() for details). - * @param {Function} callback - callback(err) will be executed with null as err, once the renegotiation - * is successfully completed. - */ - renegotiate(options: TlsOptions, callback: (err: Error) => any): any; - /** - * Set maximum TLS fragment size (default and maximum value is: 16384, minimum is: 512). - * Smaller fragment size decreases buffering latency on the client: large fragments are buffered by - * the TLS layer until the entire fragment is received and its integrity is verified; - * large fragments can span multiple roundtrips, and their processing can be delayed due to packet - * loss or reordering. However, smaller fragments add extra TLS framing bytes and CPU overhead, - * which may decrease overall server throughput. - * @param {number} size - TLS fragment size (default and maximum value is: 16384, minimum is: 512). - * @returns {boolean} - Returns true on success, false otherwise. - */ - setMaxSendFragment(size: number): boolean; - } - - export interface TlsOptions { - host?: string; - port?: number; - pfx?: string | Buffer[]; - key?: string | string[] | Buffer | any[]; - passphrase?: string; - cert?: string | string[] | Buffer | Buffer[]; - ca?: string | string[] | Buffer | Buffer[]; - crl?: string | string[]; - ciphers?: string; - honorCipherOrder?: boolean; - requestCert?: boolean; - rejectUnauthorized?: boolean; - NPNProtocols?: string[] | Buffer; - SNICallback?: (servername: string, cb: (err: Error, ctx: SecureContext) => any) => any; - ecdhCurve?: string; - dhparam?: string | Buffer; - handshakeTimeout?: number; - ALPNProtocols?: string[] | Buffer; - sessionTimeout?: number; - ticketKeys?: any; - sessionIdContext?: string; - secureProtocol?: string; - } - - export interface ConnectionOptions { - host?: string; - port?: number; - socket?: net.Socket; - pfx?: string | Buffer - key?: string | string[] | Buffer | Buffer[]; - passphrase?: string; - cert?: string | string[] | Buffer | Buffer[]; - ca?: string | Buffer | (string | Buffer)[]; - rejectUnauthorized?: boolean; - NPNProtocols?: (string | Buffer)[]; - servername?: string; - path?: string; - ALPNProtocols?: (string | Buffer)[]; - checkServerIdentity?: (servername: string, cert: string | Buffer | (string | Buffer)[]) => any; - secureProtocol?: string; - secureContext?: Object; - session?: Buffer; - minDHSize?: number; - } - - export interface Server extends net.Server { - close(): Server; - address(): { port: number; family: string; address: string; }; - addContext(hostName: string, credentials: { - key: string; - cert: string; - ca: string; - }): void; - maxConnections: number; - connections: number; - } - - export interface ClearTextStream extends stream.Duplex { - authorized: boolean; - authorizationError: Error; - getPeerCertificate(): any; - getCipher: { - name: string; - version: string; - }; - address: { - port: number; - family: string; - address: string; - }; - remoteAddress: string; - remotePort: number; - } - - export interface SecurePair { - encrypted: any; - cleartext: any; - } - - export interface SecureContextOptions { - pfx?: string | Buffer; - key?: string | Buffer; - passphrase?: string; - cert?: string | Buffer; - ca?: string | Buffer; - crl?: string | string[] - ciphers?: string; - honorCipherOrder?: boolean; - } - - export interface SecureContext { - context: any; - } - - export function createServer(options: TlsOptions, secureConnectionListener?: (cleartextStream: ClearTextStream) => void): Server; - export function connect(options: ConnectionOptions, secureConnectionListener?: () => void): ClearTextStream; - export function connect(port: number, host?: string, options?: ConnectionOptions, secureConnectListener?: () => void): ClearTextStream; - export function connect(port: number, options?: ConnectionOptions, secureConnectListener?: () => void): ClearTextStream; - export function createSecurePair(credentials?: crypto.Credentials, isServer?: boolean, requestCert?: boolean, rejectUnauthorized?: boolean): SecurePair; - export function createSecureContext(details: SecureContextOptions): SecureContext; -} - -declare module "crypto" { - export interface Certificate { - exportChallenge(spkac: string | Buffer): Buffer; - exportPublicKey(spkac: string | Buffer): Buffer; - verifySpkac(spkac: Buffer): boolean; - } - export var Certificate: { - new (): Certificate; - (): Certificate; - } - - export var fips: boolean; - - export interface CredentialDetails { - pfx: string; - key: string; - passphrase: string; - cert: string; - ca: string | string[]; - crl: string | string[]; - ciphers: string; - } - export interface Credentials { context?: any; } - export function createCredentials(details: CredentialDetails): Credentials; - export function createHash(algorithm: string): Hash; - export function createHmac(algorithm: string, key: string | Buffer): Hmac; - - type Utf8AsciiLatin1Encoding = "utf8" | "ascii" | "latin1"; - type HexBase64Latin1Encoding = "latin1" | "hex" | "base64"; - type Utf8AsciiBinaryEncoding = "utf8" | "ascii" | "binary"; - type HexBase64BinaryEncoding = "binary" | "base64" | "hex"; - type ECDHKeyFormat = "compressed" | "uncompressed" | "hybrid"; - - export interface Hash extends NodeJS.ReadWriteStream { - update(data: string | Buffer): Hash; - update(data: string | Buffer, input_encoding: Utf8AsciiLatin1Encoding): Hash; - digest(): Buffer; - digest(encoding: HexBase64Latin1Encoding): string; - } - export interface Hmac extends NodeJS.ReadWriteStream { - update(data: string | Buffer): Hmac; - update(data: string | Buffer, input_encoding: Utf8AsciiLatin1Encoding): Hmac; - digest(): Buffer; - digest(encoding: HexBase64Latin1Encoding): string; - } - export function createCipher(algorithm: string, password: any): Cipher; - export function createCipheriv(algorithm: string, key: any, iv: any): Cipher; - export interface Cipher extends NodeJS.ReadWriteStream { - update(data: Buffer): Buffer; - update(data: string, input_encoding: Utf8AsciiBinaryEncoding): Buffer; - update(data: Buffer, input_encoding: any, output_encoding: HexBase64BinaryEncoding): string; - update(data: string, input_encoding: Utf8AsciiBinaryEncoding, output_encoding: HexBase64BinaryEncoding): string; - final(): Buffer; - final(output_encoding: string): string; - setAutoPadding(auto_padding?: boolean): void; - getAuthTag(): Buffer; - setAAD(buffer: Buffer): void; - } - export function createDecipher(algorithm: string, password: any): Decipher; - export function createDecipheriv(algorithm: string, key: any, iv: any): Decipher; - export interface Decipher extends NodeJS.ReadWriteStream { - update(data: Buffer): Buffer; - update(data: string, input_encoding: HexBase64BinaryEncoding): Buffer; - update(data: Buffer, input_encoding: any, output_encoding: Utf8AsciiBinaryEncoding): string; - update(data: string, input_encoding: HexBase64BinaryEncoding, output_encoding: Utf8AsciiBinaryEncoding): string; - final(): Buffer; - final(output_encoding: string): string; - setAutoPadding(auto_padding?: boolean): void; - setAuthTag(tag: Buffer): void; - setAAD(buffer: Buffer): void; - } - export function createSign(algorithm: string): Signer; - export interface Signer extends NodeJS.WritableStream { - update(data: string | Buffer): Signer; - update(data: string | Buffer, input_encoding: Utf8AsciiLatin1Encoding): Signer; - sign(private_key: string | { key: string; passphrase: string }): Buffer; - sign(private_key: string | { key: string; passphrase: string }, output_format: HexBase64Latin1Encoding): string; - } - export function createVerify(algorith: string): Verify; - export interface Verify extends NodeJS.WritableStream { - update(data: string | Buffer): Verify; - update(data: string | Buffer, input_encoding: Utf8AsciiLatin1Encoding): Verify; - verify(object: string, signature: Buffer): boolean; - verify(object: string, signature: string, signature_format: HexBase64Latin1Encoding): boolean; - } - export function createDiffieHellman(prime_length: number, generator?: number): DiffieHellman; - export function createDiffieHellman(prime: Buffer): DiffieHellman; - export function createDiffieHellman(prime: string, prime_encoding: HexBase64Latin1Encoding): DiffieHellman; - export function createDiffieHellman(prime: string, prime_encoding: HexBase64Latin1Encoding, generator: number | Buffer): DiffieHellman; - export function createDiffieHellman(prime: string, prime_encoding: HexBase64Latin1Encoding, generator: string, generator_encoding: HexBase64Latin1Encoding): DiffieHellman; - export interface DiffieHellman { - generateKeys(): Buffer; - generateKeys(encoding: HexBase64Latin1Encoding): string; - computeSecret(other_public_key: Buffer): Buffer; - computeSecret(other_public_key: string, input_encoding: HexBase64Latin1Encoding): Buffer; - computeSecret(other_public_key: string, input_encoding: HexBase64Latin1Encoding, output_encoding: HexBase64Latin1Encoding): string; - getPrime(): Buffer; - getPrime(encoding: HexBase64Latin1Encoding): string; - getGenerator(): Buffer; - getGenerator(encoding: HexBase64Latin1Encoding): string; - getPublicKey(): Buffer; - getPublicKey(encoding: HexBase64Latin1Encoding): string; - getPrivateKey(): Buffer; - getPrivateKey(encoding: HexBase64Latin1Encoding): string; - setPublicKey(public_key: Buffer): void; - setPublicKey(public_key: string, encoding: string): void; - setPrivateKey(private_key: Buffer): void; - setPrivateKey(private_key: string, encoding: string): void; - verifyError: number; - } - export function getDiffieHellman(group_name: string): DiffieHellman; - export function pbkdf2(password: string | Buffer, salt: string | Buffer, iterations: number, keylen: number, digest: string, callback: (err: Error, derivedKey: Buffer) => any): void; - export function pbkdf2Sync(password: string | Buffer, salt: string | Buffer, iterations: number, keylen: number, digest: string): Buffer; - export function randomBytes(size: number): Buffer; - export function randomBytes(size: number, callback: (err: Error, buf: Buffer) => void): void; - export function pseudoRandomBytes(size: number): Buffer; - export function pseudoRandomBytes(size: number, callback: (err: Error, buf: Buffer) => void): void; - export interface RsaPublicKey { - key: string; - padding?: number; - } - export interface RsaPrivateKey { - key: string; - passphrase?: string, - padding?: number; - } - export function publicEncrypt(public_key: string | RsaPublicKey, buffer: Buffer): Buffer - export function privateDecrypt(private_key: string | RsaPrivateKey, buffer: Buffer): Buffer - export function privateEncrypt(private_key: string | RsaPrivateKey, buffer: Buffer): Buffer - export function publicDecrypt(public_key: string | RsaPublicKey, buffer: Buffer): Buffer - export function getCiphers(): string[]; - export function getCurves(): string[]; - export function getHashes(): string[]; - export interface ECDH { - generateKeys(): Buffer; - generateKeys(encoding: HexBase64Latin1Encoding): string; - generateKeys(encoding: HexBase64Latin1Encoding, format: ECDHKeyFormat): string; - computeSecret(other_public_key: Buffer): Buffer; - computeSecret(other_public_key: string, input_encoding: HexBase64Latin1Encoding): Buffer; - computeSecret(other_public_key: string, input_encoding: HexBase64Latin1Encoding, output_encoding: HexBase64Latin1Encoding): string; - getPrivateKey(): Buffer; - getPrivateKey(encoding: HexBase64Latin1Encoding): string; - getPublicKey(): Buffer; - getPublicKey(encoding: HexBase64Latin1Encoding): string; - getPublicKey(encoding: HexBase64Latin1Encoding, format: ECDHKeyFormat): string; - setPrivateKey(private_key: Buffer): void; - setPrivateKey(private_key: string, encoding: HexBase64Latin1Encoding): void; - } - export function createECDH(curve_name: string): ECDH; - export var DEFAULT_ENCODING: string; -} - -declare module "stream" { - import * as events from "events"; - - class internal extends events.EventEmitter { - pipe(destination: T, options?: { end?: boolean; }): T; - } - namespace internal { - - export class Stream extends internal { } - - export interface ReadableOptions { - highWaterMark?: number; - encoding?: string; - objectMode?: boolean; - read?: (size?: number) => any; - } - - export class Readable extends events.EventEmitter implements NodeJS.ReadableStream { - readable: boolean; - constructor(opts?: ReadableOptions); - _read(size: number): void; - read(size?: number): any; - setEncoding(encoding: string): void; - pause(): Readable; - resume(): Readable; - pipe(destination: T, options?: { end?: boolean; }): T; - unpipe(destination?: T): void; - unshift(chunk: any): void; - wrap(oldStream: NodeJS.ReadableStream): NodeJS.ReadableStream; - push(chunk: any, encoding?: string): boolean; - - /** - * Event emitter - * The defined events on documents including: - * 1. close - * 2. data - * 3. end - * 4. readable - * 5. error - **/ - addListener(event: string, listener: Function): this; - addListener(event: string, listener: Function): this; - addListener(event: "close", listener: () => void): this; - addListener(event: "data", listener: (chunk: Buffer | string) => void): this; - addListener(event: "end", listener: () => void): this; - addListener(event: "readable", listener: () => void): this; - addListener(event: "error", listener: (err: Error) => void): this; - - emit(event: string, ...args: any[]): boolean; - emit(event: "close"): boolean; - emit(event: "data", chunk: Buffer | string): boolean; - emit(event: "end"): boolean; - emit(event: "readable"): boolean; - emit(event: "error", err: Error): boolean; - - on(event: string, listener: Function): this; - on(event: "close", listener: () => void): this; - on(event: "data", listener: (chunk: Buffer | string) => void): this; - on(event: "end", listener: () => void): this; - on(event: "readable", listener: () => void): this; - on(event: "error", listener: (err: Error) => void): this; - - once(event: string, listener: Function): this; - once(event: "close", listener: () => void): this; - once(event: "data", listener: (chunk: Buffer | string) => void): this; - once(event: "end", listener: () => void): this; - once(event: "readable", listener: () => void): this; - once(event: "error", listener: (err: Error) => void): this; - - prependListener(event: string, listener: Function): this; - prependListener(event: "close", listener: () => void): this; - prependListener(event: "data", listener: (chunk: Buffer | string) => void): this; - prependListener(event: "end", listener: () => void): this; - prependListener(event: "readable", listener: () => void): this; - prependListener(event: "error", listener: (err: Error) => void): this; - - prependOnceListener(event: string, listener: Function): this; - prependOnceListener(event: "close", listener: () => void): this; - prependOnceListener(event: "data", listener: (chunk: Buffer | string) => void): this; - prependOnceListener(event: "end", listener: () => void): this; - prependOnceListener(event: "readable", listener: () => void): this; - prependOnceListener(event: "error", listener: (err: Error) => void): this; - - removeListener(event: string, listener: Function): this; - removeListener(event: "close", listener: () => void): this; - removeListener(event: "data", listener: (chunk: Buffer | string) => void): this; - removeListener(event: "end", listener: () => void): this; - removeListener(event: "readable", listener: () => void): this; - removeListener(event: "error", listener: (err: Error) => void): this; - } - - export interface WritableOptions { - highWaterMark?: number; - decodeStrings?: boolean; - objectMode?: boolean; - write?: (chunk: string | Buffer, encoding: string, callback: Function) => any; - writev?: (chunks: { chunk: string | Buffer, encoding: string }[], callback: Function) => any; - } - - export class Writable extends events.EventEmitter implements NodeJS.WritableStream { - writable: boolean; - constructor(opts?: WritableOptions); - _write(chunk: any, encoding: string, callback: Function): void; - write(chunk: any, cb?: Function): boolean; - write(chunk: any, encoding?: string, cb?: Function): boolean; - end(): void; - end(chunk: any, cb?: Function): void; - end(chunk: any, encoding?: string, cb?: Function): void; - - /** - * Event emitter - * The defined events on documents including: - * 1. close - * 2. drain - * 3. error - * 4. finish - * 5. pipe - * 6. unpipe - **/ - addListener(event: string, listener: Function): this; - addListener(event: "close", listener: () => void): this; - addListener(event: "drain", listener: () => void): this; - addListener(event: "error", listener: (err: Error) => void): this; - addListener(event: "finish", listener: () => void): this; - addListener(event: "pipe", listener: (src: Readable) => void): this; - addListener(event: "unpipe", listener: (src: Readable) => void): this; - - emit(event: string, ...args: any[]): boolean; - emit(event: "close"): boolean; - emit(event: "drain", chunk: Buffer | string): boolean; - emit(event: "error", err: Error): boolean; - emit(event: "finish"): boolean; - emit(event: "pipe", src: Readable): boolean; - emit(event: "unpipe", src: Readable): boolean; - - on(event: string, listener: Function): this; - on(event: "close", listener: () => void): this; - on(event: "drain", listener: () => void): this; - on(event: "error", listener: (err: Error) => void): this; - on(event: "finish", listener: () => void): this; - on(event: "pipe", listener: (src: Readable) => void): this; - on(event: "unpipe", listener: (src: Readable) => void): this; - - once(event: string, listener: Function): this; - once(event: "close", listener: () => void): this; - once(event: "drain", listener: () => void): this; - once(event: "error", listener: (err: Error) => void): this; - once(event: "finish", listener: () => void): this; - once(event: "pipe", listener: (src: Readable) => void): this; - once(event: "unpipe", listener: (src: Readable) => void): this; - - prependListener(event: string, listener: Function): this; - prependListener(event: "close", listener: () => void): this; - prependListener(event: "drain", listener: () => void): this; - prependListener(event: "error", listener: (err: Error) => void): this; - prependListener(event: "finish", listener: () => void): this; - prependListener(event: "pipe", listener: (src: Readable) => void): this; - prependListener(event: "unpipe", listener: (src: Readable) => void): this; - - prependOnceListener(event: string, listener: Function): this; - prependOnceListener(event: "close", listener: () => void): this; - prependOnceListener(event: "drain", listener: () => void): this; - prependOnceListener(event: "error", listener: (err: Error) => void): this; - prependOnceListener(event: "finish", listener: () => void): this; - prependOnceListener(event: "pipe", listener: (src: Readable) => void): this; - prependOnceListener(event: "unpipe", listener: (src: Readable) => void): this; - - removeListener(event: string, listener: Function): this; - removeListener(event: "close", listener: () => void): this; - removeListener(event: "drain", listener: () => void): this; - removeListener(event: "error", listener: (err: Error) => void): this; - removeListener(event: "finish", listener: () => void): this; - removeListener(event: "pipe", listener: (src: Readable) => void): this; - removeListener(event: "unpipe", listener: (src: Readable) => void): this; - } - - export interface DuplexOptions extends ReadableOptions, WritableOptions { - allowHalfOpen?: boolean; - readableObjectMode?: boolean; - writableObjectMode?: boolean; - } - - // Note: Duplex extends both Readable and Writable. - export class Duplex extends Readable implements NodeJS.ReadWriteStream { - // Readable - pause(): Duplex; - resume(): Duplex; - // Writeable - writable: boolean; - constructor(opts?: DuplexOptions); - _write(chunk: any, encoding: string, callback: Function): void; - write(chunk: any, cb?: Function): boolean; - write(chunk: any, encoding?: string, cb?: Function): boolean; - end(): void; - end(chunk: any, cb?: Function): void; - end(chunk: any, encoding?: string, cb?: Function): void; - } - - export interface TransformOptions extends ReadableOptions, WritableOptions { - transform?: (chunk: string | Buffer, encoding: string, callback: Function) => any; - flush?: (callback: Function) => any; - } - - // Note: Transform lacks the _read and _write methods of Readable/Writable. - export class Transform extends events.EventEmitter implements NodeJS.ReadWriteStream { - readable: boolean; - writable: boolean; - constructor(opts?: TransformOptions); - _transform(chunk: any, encoding: string, callback: Function): void; - _flush(callback: Function): void; - read(size?: number): any; - setEncoding(encoding: string): void; - pause(): Transform; - resume(): Transform; - pipe(destination: T, options?: { end?: boolean; }): T; - unpipe(destination?: T): void; - unshift(chunk: any): void; - wrap(oldStream: NodeJS.ReadableStream): NodeJS.ReadableStream; - push(chunk: any, encoding?: string): boolean; - write(chunk: any, cb?: Function): boolean; - write(chunk: any, encoding?: string, cb?: Function): boolean; - end(): void; - end(chunk: any, cb?: Function): void; - end(chunk: any, encoding?: string, cb?: Function): void; - } - - export class PassThrough extends Transform { } - } - - export = internal; -} - -declare module "util" { - export interface InspectOptions { - showHidden?: boolean; - depth?: number; - colors?: boolean; - customInspect?: boolean; - } - - export function format(format: any, ...param: any[]): string; - export function debug(string: string): void; - export function error(...param: any[]): void; - export function puts(...param: any[]): void; - export function print(...param: any[]): void; - export function log(string: string): void; - export function inspect(object: any, showHidden?: boolean, depth?: number, color?: boolean): string; - export function inspect(object: any, options: InspectOptions): string; - export function isArray(object: any): boolean; - export function isRegExp(object: any): boolean; - export function isDate(object: any): boolean; - export function isError(object: any): boolean; - export function inherits(constructor: any, superConstructor: any): void; - export function debuglog(key: string): (msg: string, ...param: any[]) => void; - export function isBoolean(object: any): boolean; - export function isBuffer(object: any): boolean; - export function isFunction(object: any): boolean; - export function isNull(object: any): boolean; - export function isNullOrUndefined(object: any): boolean; - export function isNumber(object: any): boolean; - export function isObject(object: any): boolean; - export function isPrimitive(object: any): boolean; - export function isString(object: any): boolean; - export function isSymbol(object: any): boolean; - export function isUndefined(object: any): boolean; - export function deprecate(fn: Function, message: string): Function; -} - -declare module "assert" { - function internal(value: any, message?: string): void; - namespace internal { - export class AssertionError implements Error { - name: string; - message: string; - actual: any; - expected: any; - operator: string; - generatedMessage: boolean; - - constructor(options?: { - message?: string; actual?: any; expected?: any; - operator?: string; stackStartFunction?: Function - }); - } - - export function fail(actual: any, expected: any, message: string, operator: string): void; - export function ok(value: any, message?: string): void; - export function equal(actual: any, expected: any, message?: string): void; - export function notEqual(actual: any, expected: any, message?: string): void; - export function deepEqual(actual: any, expected: any, message?: string): void; - export function notDeepEqual(acutal: any, expected: any, message?: string): void; - export function strictEqual(actual: any, expected: any, message?: string): void; - export function notStrictEqual(actual: any, expected: any, message?: string): void; - export function deepStrictEqual(actual: any, expected: any, message?: string): void; - export function notDeepStrictEqual(actual: any, expected: any, message?: string): void; - export var throws: { - (block: Function, message?: string): void; - (block: Function, error: Function, message?: string): void; - (block: Function, error: RegExp, message?: string): void; - (block: Function, error: (err: any) => boolean, message?: string): void; - }; - - export var doesNotThrow: { - (block: Function, message?: string): void; - (block: Function, error: Function, message?: string): void; - (block: Function, error: RegExp, message?: string): void; - (block: Function, error: (err: any) => boolean, message?: string): void; - }; - - export function ifError(value: any): void; - } - - export = internal; -} - -declare module "tty" { - import * as net from "net"; - - export function isatty(fd: number): boolean; - export interface ReadStream extends net.Socket { - isRaw: boolean; - setRawMode(mode: boolean): void; - isTTY: boolean; - } - export interface WriteStream extends net.Socket { - columns: number; - rows: number; - isTTY: boolean; - } -} - -declare module "domain" { - import * as events from "events"; - - export class Domain extends events.EventEmitter implements NodeJS.Domain { - run(fn: Function): void; - add(emitter: events.EventEmitter): void; - remove(emitter: events.EventEmitter): void; - bind(cb: (err: Error, data: any) => any): any; - intercept(cb: (data: any) => any): any; - dispose(): void; - members: any[]; - enter(): void; - exit(): void; - } - - export function create(): Domain; -} - -declare module "constants" { - export var E2BIG: number; - export var EACCES: number; - export var EADDRINUSE: number; - export var EADDRNOTAVAIL: number; - export var EAFNOSUPPORT: number; - export var EAGAIN: number; - export var EALREADY: number; - export var EBADF: number; - export var EBADMSG: number; - export var EBUSY: number; - export var ECANCELED: number; - export var ECHILD: number; - export var ECONNABORTED: number; - export var ECONNREFUSED: number; - export var ECONNRESET: number; - export var EDEADLK: number; - export var EDESTADDRREQ: number; - export var EDOM: number; - export var EEXIST: number; - export var EFAULT: number; - export var EFBIG: number; - export var EHOSTUNREACH: number; - export var EIDRM: number; - export var EILSEQ: number; - export var EINPROGRESS: number; - export var EINTR: number; - export var EINVAL: number; - export var EIO: number; - export var EISCONN: number; - export var EISDIR: number; - export var ELOOP: number; - export var EMFILE: number; - export var EMLINK: number; - export var EMSGSIZE: number; - export var ENAMETOOLONG: number; - export var ENETDOWN: number; - export var ENETRESET: number; - export var ENETUNREACH: number; - export var ENFILE: number; - export var ENOBUFS: number; - export var ENODATA: number; - export var ENODEV: number; - export var ENOENT: number; - export var ENOEXEC: number; - export var ENOLCK: number; - export var ENOLINK: number; - export var ENOMEM: number; - export var ENOMSG: number; - export var ENOPROTOOPT: number; - export var ENOSPC: number; - export var ENOSR: number; - export var ENOSTR: number; - export var ENOSYS: number; - export var ENOTCONN: number; - export var ENOTDIR: number; - export var ENOTEMPTY: number; - export var ENOTSOCK: number; - export var ENOTSUP: number; - export var ENOTTY: number; - export var ENXIO: number; - export var EOPNOTSUPP: number; - export var EOVERFLOW: number; - export var EPERM: number; - export var EPIPE: number; - export var EPROTO: number; - export var EPROTONOSUPPORT: number; - export var EPROTOTYPE: number; - export var ERANGE: number; - export var EROFS: number; - export var ESPIPE: number; - export var ESRCH: number; - export var ETIME: number; - export var ETIMEDOUT: number; - export var ETXTBSY: number; - export var EWOULDBLOCK: number; - export var EXDEV: number; - export var WSAEINTR: number; - export var WSAEBADF: number; - export var WSAEACCES: number; - export var WSAEFAULT: number; - export var WSAEINVAL: number; - export var WSAEMFILE: number; - export var WSAEWOULDBLOCK: number; - export var WSAEINPROGRESS: number; - export var WSAEALREADY: number; - export var WSAENOTSOCK: number; - export var WSAEDESTADDRREQ: number; - export var WSAEMSGSIZE: number; - export var WSAEPROTOTYPE: number; - export var WSAENOPROTOOPT: number; - export var WSAEPROTONOSUPPORT: number; - export var WSAESOCKTNOSUPPORT: number; - export var WSAEOPNOTSUPP: number; - export var WSAEPFNOSUPPORT: number; - export var WSAEAFNOSUPPORT: number; - export var WSAEADDRINUSE: number; - export var WSAEADDRNOTAVAIL: number; - export var WSAENETDOWN: number; - export var WSAENETUNREACH: number; - export var WSAENETRESET: number; - export var WSAECONNABORTED: number; - export var WSAECONNRESET: number; - export var WSAENOBUFS: number; - export var WSAEISCONN: number; - export var WSAENOTCONN: number; - export var WSAESHUTDOWN: number; - export var WSAETOOMANYREFS: number; - export var WSAETIMEDOUT: number; - export var WSAECONNREFUSED: number; - export var WSAELOOP: number; - export var WSAENAMETOOLONG: number; - export var WSAEHOSTDOWN: number; - export var WSAEHOSTUNREACH: number; - export var WSAENOTEMPTY: number; - export var WSAEPROCLIM: number; - export var WSAEUSERS: number; - export var WSAEDQUOT: number; - export var WSAESTALE: number; - export var WSAEREMOTE: number; - export var WSASYSNOTREADY: number; - export var WSAVERNOTSUPPORTED: number; - export var WSANOTINITIALISED: number; - export var WSAEDISCON: number; - export var WSAENOMORE: number; - export var WSAECANCELLED: number; - export var WSAEINVALIDPROCTABLE: number; - export var WSAEINVALIDPROVIDER: number; - export var WSAEPROVIDERFAILEDINIT: number; - export var WSASYSCALLFAILURE: number; - export var WSASERVICE_NOT_FOUND: number; - export var WSATYPE_NOT_FOUND: number; - export var WSA_E_NO_MORE: number; - export var WSA_E_CANCELLED: number; - export var WSAEREFUSED: number; - export var SIGHUP: number; - export var SIGINT: number; - export var SIGILL: number; - export var SIGABRT: number; - export var SIGFPE: number; - export var SIGKILL: number; - export var SIGSEGV: number; - export var SIGTERM: number; - export var SIGBREAK: number; - export var SIGWINCH: number; - export var SSL_OP_ALL: number; - export var SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION: number; - export var SSL_OP_CIPHER_SERVER_PREFERENCE: number; - export var SSL_OP_CISCO_ANYCONNECT: number; - export var SSL_OP_COOKIE_EXCHANGE: number; - export var SSL_OP_CRYPTOPRO_TLSEXT_BUG: number; - export var SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS: number; - export var SSL_OP_EPHEMERAL_RSA: number; - export var SSL_OP_LEGACY_SERVER_CONNECT: number; - export var SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER: number; - export var SSL_OP_MICROSOFT_SESS_ID_BUG: number; - export var SSL_OP_MSIE_SSLV2_RSA_PADDING: number; - export var SSL_OP_NETSCAPE_CA_DN_BUG: number; - export var SSL_OP_NETSCAPE_CHALLENGE_BUG: number; - export var SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG: number; - export var SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG: number; - export var SSL_OP_NO_COMPRESSION: number; - export var SSL_OP_NO_QUERY_MTU: number; - export var SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION: number; - export var SSL_OP_NO_SSLv2: number; - export var SSL_OP_NO_SSLv3: number; - export var SSL_OP_NO_TICKET: number; - export var SSL_OP_NO_TLSv1: number; - export var SSL_OP_NO_TLSv1_1: number; - export var SSL_OP_NO_TLSv1_2: number; - export var SSL_OP_PKCS1_CHECK_1: number; - export var SSL_OP_PKCS1_CHECK_2: number; - export var SSL_OP_SINGLE_DH_USE: number; - export var SSL_OP_SINGLE_ECDH_USE: number; - export var SSL_OP_SSLEAY_080_CLIENT_DH_BUG: number; - export var SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG: number; - export var SSL_OP_TLS_BLOCK_PADDING_BUG: number; - export var SSL_OP_TLS_D5_BUG: number; - export var SSL_OP_TLS_ROLLBACK_BUG: number; - export var ENGINE_METHOD_DSA: number; - export var ENGINE_METHOD_DH: number; - export var ENGINE_METHOD_RAND: number; - export var ENGINE_METHOD_ECDH: number; - export var ENGINE_METHOD_ECDSA: number; - export var ENGINE_METHOD_CIPHERS: number; - export var ENGINE_METHOD_DIGESTS: number; - export var ENGINE_METHOD_STORE: number; - export var ENGINE_METHOD_PKEY_METHS: number; - export var ENGINE_METHOD_PKEY_ASN1_METHS: number; - export var ENGINE_METHOD_ALL: number; - export var ENGINE_METHOD_NONE: number; - export var DH_CHECK_P_NOT_SAFE_PRIME: number; - export var DH_CHECK_P_NOT_PRIME: number; - export var DH_UNABLE_TO_CHECK_GENERATOR: number; - export var DH_NOT_SUITABLE_GENERATOR: number; - export var NPN_ENABLED: number; - export var RSA_PKCS1_PADDING: number; - export var RSA_SSLV23_PADDING: number; - export var RSA_NO_PADDING: number; - export var RSA_PKCS1_OAEP_PADDING: number; - export var RSA_X931_PADDING: number; - export var RSA_PKCS1_PSS_PADDING: number; - export var POINT_CONVERSION_COMPRESSED: number; - export var POINT_CONVERSION_UNCOMPRESSED: number; - export var POINT_CONVERSION_HYBRID: number; - export var O_RDONLY: number; - export var O_WRONLY: number; - export var O_RDWR: number; - export var S_IFMT: number; - export var S_IFREG: number; - export var S_IFDIR: number; - export var S_IFCHR: number; - export var S_IFBLK: number; - export var S_IFIFO: number; - export var S_IFSOCK: number; - export var S_IRWXU: number; - export var S_IRUSR: number; - export var S_IWUSR: number; - export var S_IXUSR: number; - export var S_IRWXG: number; - export var S_IRGRP: number; - export var S_IWGRP: number; - export var S_IXGRP: number; - export var S_IRWXO: number; - export var S_IROTH: number; - export var S_IWOTH: number; - export var S_IXOTH: number; - export var S_IFLNK: number; - export var O_CREAT: number; - export var O_EXCL: number; - export var O_NOCTTY: number; - export var O_DIRECTORY: number; - export var O_NOATIME: number; - export var O_NOFOLLOW: number; - export var O_SYNC: number; - export var O_SYMLINK: number; - export var O_DIRECT: number; - export var O_NONBLOCK: number; - export var O_TRUNC: number; - export var O_APPEND: number; - export var F_OK: number; - export var R_OK: number; - export var W_OK: number; - export var X_OK: number; - export var UV_UDP_REUSEADDR: number; - export var SIGQUIT: number; - export var SIGTRAP: number; - export var SIGIOT: number; - export var SIGBUS: number; - export var SIGUSR1: number; - export var SIGUSR2: number; - export var SIGPIPE: number; - export var SIGALRM: number; - export var SIGCHLD: number; - export var SIGSTKFLT: number; - export var SIGCONT: number; - export var SIGSTOP: number; - export var SIGTSTP: number; - export var SIGTTIN: number; - export var SIGTTOU: number; - export var SIGURG: number; - export var SIGXCPU: number; - export var SIGXFSZ: number; - export var SIGVTALRM: number; - export var SIGPROF: number; - export var SIGIO: number; - export var SIGPOLL: number; - export var SIGPWR: number; - export var SIGSYS: number; - export var SIGUNUSED: number; - export var defaultCoreCipherList: string; - export var defaultCipherList: string; - export var ENGINE_METHOD_RSA: number; - export var ALPN_ENABLED: number; -} - -declare module "process" { - export = process; -} - -declare module "v8" { - interface HeapSpaceInfo { - space_name: string; - space_size: number; - space_used_size: number; - space_available_size: number; - physical_space_size: number; - } - export function getHeapStatistics(): { total_heap_size: number, total_heap_size_executable: number, total_physical_size: number, total_avaialble_size: number, used_heap_size: number, heap_size_limit: number }; - export function getHeapSpaceStatistics(): HeapSpaceInfo[]; - export function setFlagsFromString(flags: string): void; -} - -declare module "timers" { - export function setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): NodeJS.Timer; - export function clearTimeout(timeoutId: NodeJS.Timer): void; - export function setInterval(callback: (...args: any[]) => void, ms: number, ...args: any[]): NodeJS.Timer; - export function clearInterval(intervalId: NodeJS.Timer): void; - export function setImmediate(callback: (...args: any[]) => void, ...args: any[]): any; - export function clearImmediate(immediateId: any): void; -} - -declare module "console" { - export = console; -} \ No newline at end of file diff --git a/Tasks/XamarinLicense/typings/globals/node/typings.json b/Tasks/XamarinLicense/typings/globals/node/typings.json deleted file mode 100644 index 98c1869d1d0a..000000000000 --- a/Tasks/XamarinLicense/typings/globals/node/typings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "resolution": "main", - "tree": { - "src": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/ab8d917787092fdfb16390f2bee6de8ab5c1783c/node/node.d.ts", - "raw": "registry:dt/node#6.0.0+20160920093002", - "typings": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/ab8d917787092fdfb16390f2bee6de8ab5c1783c/node/node.d.ts" - } -} diff --git a/Tasks/XamarinLicense/typings/globals/q/index.d.ts b/Tasks/XamarinLicense/typings/globals/q/index.d.ts deleted file mode 100644 index 4449c31841ff..000000000000 --- a/Tasks/XamarinLicense/typings/globals/q/index.d.ts +++ /dev/null @@ -1,357 +0,0 @@ -// Generated by typings -// Source: https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/623f30ab194a3486e014ca39bc7f2089897d6ce4/q/Q.d.ts -declare function Q(promise: Q.IPromise): Q.Promise; -/** - * If value is not a promise, returns a promise that is fulfilled with value. - */ -declare function Q(value: T): Q.Promise; - -declare namespace Q { - interface IPromise { - then(onFulfill?: (value: T) => U | IPromise, onReject?: (error: any) => U | IPromise): IPromise; - } - - interface Deferred { - promise: Promise; - resolve(value?: T): void; - resolve(value?: IPromise): void; - reject(reason: any): void; - notify(value: any): void; - makeNodeResolver(): (reason: any, value: T) => void; - } - - interface Promise { - /** - * Like a finally clause, allows you to observe either the fulfillment or rejection of a promise, but to do so without modifying the final value. This is useful for collecting resources regardless of whether a job succeeded, like closing a database connection, shutting a server down, or deleting an unneeded key from an object. - - * finally returns a promise, which will become resolved with the same fulfillment value or rejection reason as promise. However, if callback returns a promise, the resolution of the returned promise will be delayed until the promise returned from callback is finished. - */ - fin(finallyCallback: () => any): Promise; - /** - * Like a finally clause, allows you to observe either the fulfillment or rejection of a promise, but to do so without modifying the final value. This is useful for collecting resources regardless of whether a job succeeded, like closing a database connection, shutting a server down, or deleting an unneeded key from an object. - - * finally returns a promise, which will become resolved with the same fulfillment value or rejection reason as promise. However, if callback returns a promise, the resolution of the returned promise will be delayed until the promise returned from callback is finished. - */ - finally(finallyCallback: () => any): Promise; - - /** - * The then method from the Promises/A+ specification, with an additional progress handler. - */ - then(onFulfill?: (value: T) => U | IPromise, onReject?: (error: any) => U | IPromise, onProgress?: Function): Promise; - - /** - * Like then, but "spreads" the array into a variadic fulfillment handler. If any of the promises in the array are rejected, instead calls onRejected with the first rejected promise's rejection reason. - * - * This is especially useful in conjunction with all - */ - spread(onFulfill: (...args: any[]) => IPromise | U, onReject?: (reason: any) => IPromise | U): Promise; - - fail(onRejected: (reason: any) => U | IPromise): Promise; - - /** - * A sugar method, equivalent to promise.then(undefined, onRejected). - */ - catch(onRejected: (reason: any) => U | IPromise): Promise; - - /** - * A sugar method, equivalent to promise.then(undefined, undefined, onProgress). - */ - progress(onProgress: (progress: any) => any): Promise; - - /** - * Much like then, but with different behavior around unhandled rejection. If there is an unhandled rejection, either because promise is rejected and no onRejected callback was provided, or because onFulfilled or onRejected threw an error or returned a rejected promise, the resulting rejection reason is thrown as an exception in a future turn of the event loop. - * - * This method should be used to terminate chains of promises that will not be passed elsewhere. Since exceptions thrown in then callbacks are consumed and transformed into rejections, exceptions at the end of the chain are easy to accidentally, silently ignore. By arranging for the exception to be thrown in a future turn of the event loop, so that it won't be caught, it causes an onerror event on the browser window, or an uncaughtException event on Node.js's process object. - * - * Exceptions thrown by done will have long stack traces, if Q.longStackSupport is set to true. If Q.onerror is set, exceptions will be delivered there instead of thrown in a future turn. - * - * The Golden Rule of done vs. then usage is: either return your promise to someone else, or if the chain ends with you, call done to terminate it. - */ - done(onFulfilled?: (value: T) => any, onRejected?: (reason: any) => any, onProgress?: (progress: any) => any): void; - - /** - * If callback is a function, assumes it's a Node.js-style callback, and calls it as either callback(rejectionReason) when/if promise becomes rejected, or as callback(null, fulfillmentValue) when/if promise becomes fulfilled. If callback is not a function, simply returns promise. - */ - nodeify(callback: (reason: any, value: any) => void): Promise; - - /** - * Returns a promise to get the named property of an object. Essentially equivalent to - * - * promise.then(function (o) { - * return o[propertyName]; - * }); - */ - get(propertyName: String): Promise; - set(propertyName: String, value: any): Promise; - delete(propertyName: String): Promise; - /** - * Returns a promise for the result of calling the named method of an object with the given array of arguments. The object itself is this in the function, just like a synchronous method call. Essentially equivalent to - * - * promise.then(function (o) { - * return o[methodName].apply(o, args); - * }); - */ - post(methodName: String, args: any[]): Promise; - /** - * Returns a promise for the result of calling the named method of an object with the given variadic arguments. The object itself is this in the function, just like a synchronous method call. - */ - invoke(methodName: String, ...args: any[]): Promise; - fapply(args: any[]): Promise; - fcall(...args: any[]): Promise; - - /** - * Returns a promise for an array of the property names of an object. Essentially equivalent to - * - * promise.then(function (o) { - * return Object.keys(o); - * }); - */ - keys(): Promise; - - /** - * A sugar method, equivalent to promise.then(function () { return value; }). - */ - thenResolve(value: U): Promise; - /** - * A sugar method, equivalent to promise.then(function () { throw reason; }). - */ - thenReject(reason: any): Promise; - - /** - * Attaches a handler that will observe the value of the promise when it becomes fulfilled, returning a promise for that same value, perhaps deferred but not replaced by the promise returned by the onFulfilled handler. - */ - tap(onFulfilled: (value: T) => any): Promise; - - timeout(ms: number, message?: string): Promise; - /** - * Returns a promise that will have the same result as promise, but will only be fulfilled or rejected after at least ms milliseconds have passed. - */ - delay(ms: number): Promise; - - /** - * Returns whether a given promise is in the fulfilled state. When the static version is used on non-promises, the result is always true. - */ - isFulfilled(): boolean; - /** - * Returns whether a given promise is in the rejected state. When the static version is used on non-promises, the result is always false. - */ - isRejected(): boolean; - /** - * Returns whether a given promise is in the pending state. When the static version is used on non-promises, the result is always false. - */ - isPending(): boolean; - - valueOf(): any; - - /** - * Returns a "state snapshot" object, which will be in one of three forms: - * - * - { state: "pending" } - * - { state: "fulfilled", value: } - * - { state: "rejected", reason: } - */ - inspect(): PromiseState; - } - - interface PromiseState { - /** - * "fulfilled", "rejected", "pending" - */ - state: string; - value?: T; - reason?: any; - } - - // If no value provided, returned promise will be of void type - export function when(): Promise; - - // if no fulfill, reject, or progress provided, returned promise will be of same type - export function when(value: T | IPromise): Promise; - - // If a non-promise value is provided, it will not reject or progress - export function when(value: T | IPromise, onFulfilled: (val: T) => U | IPromise, onRejected?: (reason: any) => U | IPromise, onProgress?: (progress: any) => any): Promise; - - /** - * Currently "impossible" (and I use the term loosely) to implement due to TypeScript limitations as it is now. - * See: https://github.com/Microsoft/TypeScript/issues/1784 for discussion on it. - */ - // export function try(method: Function, ...args: any[]): Promise; - - export function fbind(method: (...args: any[]) => T | IPromise, ...args: any[]): (...args: any[]) => Promise; - - export function fcall(method: (...args: any[]) => T, ...args: any[]): Promise; - - export function send(obj: any, functionName: string, ...args: any[]): Promise; - export function invoke(obj: any, functionName: string, ...args: any[]): Promise; - export function mcall(obj: any, functionName: string, ...args: any[]): Promise; - - export function denodeify(nodeFunction: Function, ...args: any[]): (...args: any[]) => Promise; - export function nbind(nodeFunction: Function, thisArg: any, ...args: any[]): (...args: any[]) => Promise; - export function nfbind(nodeFunction: Function, ...args: any[]): (...args: any[]) => Promise; - export function nfcall(nodeFunction: Function, ...args: any[]): Promise; - export function nfapply(nodeFunction: Function, args: any[]): Promise; - - export function ninvoke(nodeModule: any, functionName: string, ...args: any[]): Promise; - export function npost(nodeModule: any, functionName: string, args: any[]): Promise; - export function nsend(nodeModule: any, functionName: string, ...args: any[]): Promise; - export function nmcall(nodeModule: any, functionName: string, ...args: any[]): Promise; - - /** - * Returns a promise that is fulfilled with an array containing the fulfillment value of each promise, or is rejected with the same rejection reason as the first promise to be rejected. - */ - export function all(promises: [IPromise, IPromise, IPromise, IPromise, IPromise, IPromise]): Promise<[A, B, C, D, E, F]>; - /** - * Returns a promise that is fulfilled with an array containing the fulfillment value of each promise, or is rejected with the same rejection reason as the first promise to be rejected. - */ - export function all(promises: [IPromise, IPromise, IPromise, IPromise, IPromise]): Promise<[A, B, C, D, E]>; - /** - * Returns a promise that is fulfilled with an array containing the fulfillment value of each promise, or is rejected with the same rejection reason as the first promise to be rejected. - */ - export function all(promises: [IPromise, IPromise, IPromise, IPromise]): Promise<[A, B, C, D]>; - /** - * Returns a promise that is fulfilled with an array containing the fulfillment value of each promise, or is rejected with the same rejection reason as the first promise to be rejected. - */ - export function all(promises: [IPromise, IPromise, IPromise]): Promise<[A, B, C]>; - /** - * Returns a promise that is fulfilled with an array containing the fulfillment value of each promise, or is rejected with the same rejection reason as the first promise to be rejected. - */ - export function all(promises: [IPromise, IPromise]): Promise<[A, B]>; - /** - * Returns a promise that is fulfilled with an array containing the fulfillment value of each promise, or is rejected with the same rejection reason as the first promise to be rejected. - */ - export function all(promises: IPromise[]): Promise; - - /** - * Returns a promise for the first of an array of promises to become settled. - */ - export function race(promises: IPromise[]): Promise; - - /** - * Returns a promise that is fulfilled with an array of promise state snapshots, but only after all the original promises have settled, i.e. become either fulfilled or rejected. - */ - export function allSettled(promises: IPromise[]): Promise[]>; - - export function allResolved(promises: IPromise[]): Promise[]>; - - /** - * Like then, but "spreads" the array into a variadic fulfillment handler. If any of the promises in the array are rejected, instead calls onRejected with the first rejected promise's rejection reason. - * This is especially useful in conjunction with all. - */ - export function spread(promises: IPromise[], onFulfilled: (...args: T[]) => U | IPromise, onRejected?: (reason: any) => U | IPromise): Promise; - - /** - * Returns a promise that will have the same result as promise, except that if promise is not fulfilled or rejected before ms milliseconds, the returned promise will be rejected with an Error with the given message. If message is not supplied, the message will be "Timed out after " + ms + " ms". - */ - export function timeout(promise: Promise, ms: number, message?: string): Promise; - - /** - * Returns a promise that will have the same result as promise, but will only be fulfilled or rejected after at least ms milliseconds have passed. - */ - export function delay(promise: Promise, ms: number): Promise; - /** - * Returns a promise that will have the same result as promise, but will only be fulfilled or rejected after at least ms milliseconds have passed. - */ - export function delay(value: T, ms: number): Promise; - /** - * Returns a promise that will be fulfilled with undefined after at least ms milliseconds have passed. - */ - export function delay(ms: number): Promise ; - /** - * Returns whether a given promise is in the fulfilled state. When the static version is used on non-promises, the result is always true. - */ - export function isFulfilled(promise: Promise): boolean; - /** - * Returns whether a given promise is in the rejected state. When the static version is used on non-promises, the result is always false. - */ - export function isRejected(promise: Promise): boolean; - /** - * Returns whether a given promise is in the pending state. When the static version is used on non-promises, the result is always false. - */ - export function isPending(promise: Promise): boolean; - - /** - * Returns a "deferred" object with a: - * promise property - * resolve(value) method - * reject(reason) method - * notify(value) method - * makeNodeResolver() method - */ - export function defer(): Deferred; - - /** - * Returns a promise that is rejected with reason. - */ - export function reject(reason?: any): Promise; - - export function Promise(resolver: (resolve: (val: T | IPromise) => void , reject: (reason: any) => void , notify: (progress: any) => void ) => void ): Promise; - - /** - * Creates a new version of func that accepts any combination of promise and non-promise values, converting them to their fulfillment values before calling the original func. The returned version also always returns a promise: if func does a return or throw, then Q.promised(func) will return fulfilled or rejected promise, respectively. - * - * This can be useful for creating functions that accept either promises or non-promise values, and for ensuring that the function always returns a promise even in the face of unintentional thrown exceptions. - */ - export function promised(callback: (...args: any[]) => T): (...args: any[]) => Promise; - - /** - * Returns whether the given value is a Q promise. - */ - export function isPromise(object: any): boolean; - /** - * Returns whether the given value is a promise (i.e. it's an object with a then function). - */ - export function isPromiseAlike(object: any): boolean; - /** - * Returns whether a given promise is in the pending state. When the static version is used on non-promises, the result is always false. - */ - export function isPending(object: any): boolean; - /** - * If an object is not a promise, it is as "near" as possible. - * If a promise is rejected, it is as "near" as possible too. - * If it’s a fulfilled promise, the fulfillment value is nearer. - * If it’s a deferred promise and the deferred has been resolved, the - * resolution is "nearer". - */ - export function nearer(promise: Promise): T; - - /** - * This is an experimental tool for converting a generator function into a deferred function. This has the potential of reducing nested callbacks in engines that support yield. - */ - export function async(generatorFunction: any): (...args: any[]) => Promise; - export function nextTick(callback: Function): void; - - /** - * A settable property that will intercept any uncaught errors that would otherwise be thrown in the next tick of the event loop, usually as a result of done. Can be useful for getting the full stack trace of an error in browsers, which is not usually possible with window.onerror. - */ - export var onerror: (reason: any) => void; - /** - * A settable property that lets you turn on long stack trace support. If turned on, "stack jumps" will be tracked across asynchronous promise operations, so that if an uncaught error is thrown by done or a rejection reason's stack property is inspected in a rejection callback, a long stack trace is produced. - */ - export var longStackSupport: boolean; - - /** - * Calling resolve with a pending promise causes promise to wait on the passed promise, becoming fulfilled with its fulfillment value or rejected with its rejection reason (or staying pending forever, if the passed promise does). - * Calling resolve with a rejected promise causes promise to be rejected with the passed promise's rejection reason. - * Calling resolve with a fulfilled promise causes promise to be fulfilled with the passed promise's fulfillment value. - * Calling resolve with a non-promise value causes promise to be fulfilled with that value. - */ - export function resolve(object: IPromise): Promise; - /** - * Calling resolve with a pending promise causes promise to wait on the passed promise, becoming fulfilled with its fulfillment value or rejected with its rejection reason (or staying pending forever, if the passed promise does). - * Calling resolve with a rejected promise causes promise to be rejected with the passed promise's rejection reason. - * Calling resolve with a fulfilled promise causes promise to be fulfilled with the passed promise's fulfillment value. - * Calling resolve with a non-promise value causes promise to be fulfilled with that value. - */ - export function resolve(object: T): Promise; - - /** - * Resets the global "Q" variable to the value it has before Q was loaded. - * This will either be undefined if there was no version or the version of Q which was already loaded before. - * @returns { The last version of Q. } - */ - export function noConflict(): typeof Q; -} - -declare module "q" { - export = Q; -} \ No newline at end of file diff --git a/Tasks/XamarinLicense/typings/globals/q/typings.json b/Tasks/XamarinLicense/typings/globals/q/typings.json deleted file mode 100644 index 3d59355a87e8..000000000000 --- a/Tasks/XamarinLicense/typings/globals/q/typings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "resolution": "main", - "tree": { - "src": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/623f30ab194a3486e014ca39bc7f2089897d6ce4/q/Q.d.ts", - "raw": "registry:dt/q#0.0.0+20160613154756", - "typings": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/623f30ab194a3486e014ca39bc7f2089897d6ce4/q/Q.d.ts" - } -} diff --git a/Tasks/XamarinLicense/typings/index.d.ts b/Tasks/XamarinLicense/typings/index.d.ts deleted file mode 100644 index ed0373e4db67..000000000000 --- a/Tasks/XamarinLicense/typings/index.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -/// -/// -// TODO: remove after moving to latest task lib -/// diff --git a/Tasks/XamarinLicense/typings/vsts-task-lib.d.ts b/Tasks/XamarinLicense/typings/vsts-task-lib.d.ts deleted file mode 100644 index bfa38b71031a..000000000000 --- a/Tasks/XamarinLicense/typings/vsts-task-lib.d.ts +++ /dev/null @@ -1,579 +0,0 @@ -declare module 'vsts-task-lib/taskcommand' { - export class TaskCommand { - constructor(command: any, properties: any, message: any); - command: string; - message: string; - properties: { - [key: string]: string; - }; - toString(): string; - } - export function commandFromString(commandLine: any): TaskCommand; - -} -declare module 'vsts-task-lib/toolrunner' { - import Q = require('q'); - import events = require('events'); - import stream = require('stream'); - /** - * Interface for exec options - * - * @param cwd optional working directory. defaults to current - * @param env optional envvar dictionary. defaults to current processes env - * @param silent optional. defaults to false - * @param failOnStdErr optional. whether to fail if output to stderr. defaults to false - * @param ignoreReturnCode optional. defaults to failing on non zero. ignore will not fail leaving it up to the caller - */ - export interface IExecOptions { - cwd?: string; - env?: { - [key: string]: string; - }; - silent?: boolean; - failOnStdErr?: boolean; - ignoreReturnCode?: boolean; - outStream?: stream.Writable; - errStream?: stream.Writable; - } - /** - * Interface for exec results returned from synchronous exec functions - * - * @param stdout standard output - * @param stderr error output - * @param code return code - * @param error Error on failure - */ - export interface IExecResult { - stdout: string; - stderr: string; - code: number; - error: Error; - } - export function debug(message: any): void; - export class ToolRunner extends events.EventEmitter { - constructor(toolPath: any); - toolPath: string; - args: string[]; - silent: boolean; - private _debug(message); - private _argStringToArray(argString); - /** - * Add argument - * Append an argument or an array of arguments - * - * @param val string cmdline or array of strings - * @returns void - */ - arg(val: string | string[]): void; - /** - * Append argument command line string - * e.g. '"arg one" two -z' would append args[]=['arg one', 'two', '-z'] - * - * @param val string cmdline - * @returns void - */ - argString(val: string): void; - /** - * Append argument command line string - * e.g. '"arg one" two -z' would append args[]=['arg one', 'two', '-z'] - * returns ToolRunner for chaining - * - * @param val string cmdline - * @returns ToolRunner - */ - line(val: string): void; - /** - * Append argument command line string - * e.g. '"arg one" two -z' would append args[]=['arg one', 'two', '-z'] - * returns ToolRunner for chaining - * - * @param val string cmdline - * @returns ToolRunner - */ - line(val: string): ToolRunner; - /** - * Add path argument - * Add path string to argument, path string should not contain double quoted - * This will call arg(val, literal?) with literal equal 'true' - * - * @param val path argument string - * @returns void - */ - pathArg(val: string): void; - /** - * Add argument(s) if a condition is met - * Wraps arg(). See arg for details - * - * @param condition boolean condition - * @param val string cmdline or array of strings - * @returns void - */ - argIf(condition: any, val: any): void; - /** - * Pipe output of exec() to another tool - * @param tool - * @returns {ToolRunner} - */ - public pipeExecOutputToTool(tool: ToolRunner) : ToolRunner; - /** - * Exec a tool. - * Output will be streamed to the live console. - * Returns promise with return code - * - * @param tool path to tool to exec - * @param options optional exec options. See IExecOptions - * @returns number - */ - exec(options?: IExecOptions): Q.Promise; - /** - * Exec a tool synchronously. - * Output will be *not* be streamed to the live console. It will be returned after execution is complete. - * Appropriate for short running tools - * Returns IExecResult with output and return code - * - * @param tool path to tool to exec - * @param options optionalexec options. See IExecOptions - * @returns IExecResult - */ - execSync(options?: IExecOptions): IExecResult; - } - -} -declare module 'vsts-task-lib/vault' { - export class Vault { - constructor(); - private _keyFile; - private _store; - initialize(): void; - storeSecret(name: string, data: string): boolean; - retrieveSecret(name: string): string; - private getKey(); - private genKey(); - } - -} -declare module 'vsts-task-lib/task' { - /// - import Q = require('q'); - import fs = require('fs'); - import trm = require('vsts-task-lib/toolrunner'); - export enum TaskResult { - Succeeded = 0, - Failed = 1, - } - export var _outStream: any; - export var _errStream: any; - export function _writeError(str: string): void; - export function _writeLine(str: string): void; - export function setStdStream(stdStream: any): void; - export function setErrStream(errStream: any): void; - /** - * Sets the result of the task. - * If the result is Failed (1), then execution will halt. - * - * @param result TaskResult enum of Success or Failed. If the result is Failed (1), then execution will halt. - * @param messages A message which will be logged and added as an issue if an failed - * @returns void - */ - export function setResult(result: TaskResult, message: string): void; - export function handlerError(errMsg: string, continueOnError: boolean): void; - export function exitOnCodeIf(code: number, condition: boolean): void; - export function exit(code: number): void; - /** - * Sets the location of the resources json. This is typically the task.json file. - * Call once at the beginning of the script before any calls to loc. - * - * @param path Full path to the json. - * @returns void - */ - export function setResourcePath(path: string): void; - /** - * Gets the localized string from the json resource file. Optionally formats with additional params. - * - * @param key key of the resources string in the resource file - * @param param additional params for formatting the string - * @returns string - */ - export function loc(key: string, ...param: any[]): string; - /** - * Gets a variables value which is defined on the build definition or set at runtime. - * - * @param name name of the variable to get - * @returns string - */ - export function getVariable(name: string): string; - /** - * Sets a variables which will be available to subsequent tasks as well. - * - * @param name name of the variable to set - * @param val value to set - * @returns void - */ - export function setVariable(name: string, val: string): void; - /** - * Gets the value of an input. The value is also trimmed. - * If required is true and the value is not set, the task will fail with an error. Execution halts. - * - * @param name name of the input to get - * @param required whether input is required. optional, defaults to false - * @returns string - */ - export function getInput(name: string, required?: boolean): string; - /** - * Gets the value of an input and converts to a bool. Convenience. - * If required is true and the value is not set, the task will fail with an error. Execution halts. - * - * @param name name of the bool input to get - * @param required whether input is required. optional, defaults to false - * @returns string - */ - export function getBoolInput(name: string, required?: boolean): boolean; - export function setEnvVar(name: string, val: string): void; - /** - * Gets the value of an input and splits the values by a delimiter (space, comma, etc...) - * Useful for splitting an input with simple list of items like targets - * IMPORTANT: Do not use for splitting additional args! Instead use arg() - it will split and handle - * If required is true and the value is not set, the task will fail with an error. Execution halts. - * - * @param name name of the input to get - * @param delim delimiter to split on - * @param required whether input is required. optional, defaults to false - * @returns string[] - */ - export function getDelimitedInput(name: string, delim: string, required?: boolean): string[]; - /** - * Checks whether a path inputs value was supplied by the user - * File paths are relative with a picker, so an empty path is the root of the repo. - * Useful if you need to condition work (like append an arg) if a value was supplied - * - * @param name name of the path input to check - * @returns boolean - */ - export function filePathSupplied(name: string): boolean; - /** - * Gets the value of a path input - * It will be quoted for you if it isn't already and contains spaces - * If required is true and the value is not set, the task will fail with an error. Execution halts. - * If check is true and the path does not exist, the task will fail with an error. Execution halts. - * - * @param name name of the input to get - * @param required whether input is required. optional, defaults to false - * @param check whether path is checked. optional, defaults to false - * @returns string - */ - export function getPathInput(name: string, required?: boolean, check?: boolean): string; - /** - * Gets the url for a service endpoint - * If the url was not set and is not optional, the task will fail with an error message. Execution will halt. - * - * @param id name of the service endpoint - * @param optional whether the url is optional - * @returns string - */ - export function getEndpointUrl(id: string, optional: boolean): string; - export function getEndpointDataParameter(id: string, key: string, optional: boolean): string; - /** - * Gets the endpoint authorization scheme for a service endpoint - * If the endpoint authorization scheme is not set and is not optional, the task will fail with an error message. Execution will halt. - * - * @param id name of the service endpoint - * @param optional whether the endpoint authorization scheme is optional - * @returns {string} value of the endpoint authorization scheme - */ - export function getEndpointAuthorizationScheme(id: string, optional: boolean): string; - /** - * Gets the endpoint authorization parameter value for a service endpoint with specified key - * If the endpoint authorization parameter is not set and is not optional, the task will fail with an error message. Execution will halt. - * - * @param id name of the service endpoint - * @param key key to find the endpoint authorization parameter - * @param optional optional whether the endpoint authorization scheme is optional - * @returns {string} value of the endpoint authorization parameter value - */ - export function getEndpointAuthorizationParameter(id: string, key: string, optional: boolean): string; - /** - * Interface for EndpointAuthorization - * Contains a schema and a string/string dictionary of auth data - * - * @param parameters string string dictionary of auth data - * @param scheme auth scheme such as OAuth or username/password etc... - */ - export interface EndpointAuthorization { - parameters: { - [key: string]: string; - }; - scheme: string; - } - /** - * Gets the authorization details for a service endpoint - * If the authorization was not set and is not optional, the task will fail with an error message. Execution will halt. - * - * @param id name of the service endpoint - * @param optional whether the url is optional - * @returns string - */ - export function getEndpointAuthorization(id: string, optional: boolean): EndpointAuthorization; - /* - * Gets the endpoint data parameter value with specified key for a service endpoint - * If the endpoint data parameter was not set and is not optional, the task will fail with an error message. Execution will halt. - * - * @param id name of the service endpoint - * @param key of the parameter - * @param optional whether the endpoint data is optional - * @returns {string} value of the endpoint data parameter - */ - export function getEndpointDataParameter(id: string, key: string, optional: boolean): string; - /** - * Gets the endpoint authorization scheme for a service endpoint - * If the endpoint authorization scheme is not set and is not optional, the task will fail with an error message. Execution will halt. - * - * @param id name of the service endpoint - * @param optional whether the endpoint authorization scheme is optional - * @returns {string} value of the endpoint authorization scheme - */ - export function getEndpointAuthorizationScheme(id: string, optional: boolean): string; - /** - * Gets the endpoint authorization parameter value for a service endpoint with specified key - * If the endpoint authorization parameter is not set and is not optional, the task will fail with an error message. Execution will halt. - * - * @param id name of the service endpoint - * @param key key to find the endpoint authorization parameter - * @param optional optional whether the endpoint authorization scheme is optional - * @returns {string} value of the endpoint authorization parameter value - */ - export function getEndpointAuthorizationParameter(id: string, key: string, optional: boolean): string; - export function command(command: string, properties: any, message: string): void; - export function warning(message: string): void; - export function error(message: string): void; - export function debug(message: string): void; - export interface FsStats extends fs.Stats { - } - - /** - * Get's stat on a path. - * Useful for checking whether a file or directory. Also getting created, modified and accessed time. - * see [fs.stat](https://nodejs.org/api/fs.html#fs_class_fs_stats) - * - * @param path path to check - * @returns fsStat - */ - export function stats(path: string): FsStats; - /** - * Returns whether a path exists. - * - * @param path path to check - * @returns boolean - */ - export function exist(path: string): boolean; - - /** - * Interface to wrap file options - */ - export interface FsOptions {} - - /** - * Synchronously writes data to a file, replacing the file if it already exists. - * @param file - * @param data - * @param options - */ - export function writeFile(file: string, data:string|Buffer, options?:string|FsOptions); - /** - * Useful for determining the host operating system. - * see [os.type](https://nodejs.org/api/os.html#os_os_type) - * - * @return the name of the operating system - */ - export function osType(): string; - /** - * Returns the process's current working directory. - * see [process.cwd](https://nodejs.org/api/process.html#process_process_cwd) - * - * @return the path to the current working directory of the process - */ - export function cwd(): string; - /** - * Checks whether a path exists. - * If the path does not exist, the task will fail with an error message. Execution will halt. - * - * @param p path to check - * @param name name only used in error message to identify the path - * @returns void - */ - export function checkPath(p: string, name: string): void; - /** - * Change working directory. - * - * @param path new working directory path - * @returns void - */ - export function cd(path: string): void; - /** - * Change working directory and push it on the stack - * - * @param path new working directory path - * @returns void - */ - export function pushd(path: string): void; - /** - * Change working directory back to previously pushed directory - * - * @returns void - */ - export function popd(): void; - /** - * Resolves a sequence of paths or path segments into an absolute path. - * Calls node.js path.resolve() - * Allows L0 testing with consistent path formats on Mac/Linux and Windows in the mock implementation - * @param pathSegments - * @returns {string} - */ - export function resolve(...pathSegments: any[]): string; - /** - * Make a directory. Creates the full path with folders in between - * Returns whether it was successful or not - * - * @param p path to create - * @returns boolean - */ - export function mkdirP(p: any): boolean; - /** - * Returns path of a tool had the tool actually been invoked. Resolves via paths. - * If you check and the tool does not exist, the task will fail with an error message and halt execution. - * - * @param tool name of the tool - * @param check whether to check if tool exists - * @returns string - */ - export function which(tool: string, check?: boolean): string; - /** - * Returns array of files in the given path, or in current directory if no path provided. See shelljs.ls - * @param {string} options Available options: -R (recursive), -A (all files, include files beginning with ., except for . and ..) - * @param {string[]} paths Paths to search. - * @return {string[]} An array of files in the given path(s). - */ - export function ls(options: string, paths: string[]): string[]; - /** - * Returns path of a tool had the tool actually been invoked. Resolves via paths. - * If you check and the tool does not exist, the task will fail with an error message and halt execution. - * Returns whether the copy was successful - * - * @param options string -r, -f or -rf for recursive and force - * @param source source path - * @param dest destination path - * @param continueOnError optional. whether to continue on error - * @returns boolean - */ - export function cp(options: any, source: string, dest: string, continueOnError?: boolean): boolean; - /** - * Moves a path. - * Returns whether the copy was successful - * - * @param source source path - * @param dest destination path - * @param force whether to force and overwrite - * @param continueOnError optional. whether to continue on error - * @returns boolean - */ - export function mv(source: string, dest: string, force: boolean, continueOnError?: boolean): boolean; - /** - * Interface for FindOptions - * Contains properties to control whether to follow symlinks - * - * @param followSpecifiedSymbolicLink Equivalent to the -H command line option. Indicates whether to traverse descendants if the specified path is a symbolic link directory. Does not cause nested symbolic link directories to be traversed. - * @param followSymbolicLinks Equivalent to the -L command line option. Indicates whether to traverse descendants of symbolic link directories. - */ - export interface FindOptions { - /** - * Equivalent to the -H command line option. Indicates whether to traverse descendants if - * the specified path is a symbolic link directory. Does not cause nested symbolic link - * directories to be traversed. - */ - followSpecifiedSymbolicLink: boolean; - - /** - * Equivalent to the -L command line option. Indicates whether to traverse descendants of - * symbolic link directories. - */ - followSymbolicLinks: boolean; - } - /** - * Find all files under a give path - * Returns an array of full paths - * - * @param findPath path to find files under - * @returns string[] - */ - export function find(findPath: string, options?: FindOptions): string[]; - /** - * Remove a path recursively with force - * Returns whether it succeeds - * - * @param path path to remove - * @param continueOnError optional. whether to continue on error - * @returns string[] - */ - export function rmRF(path: string, continueOnError?: boolean): boolean; - export function glob(pattern: string): string[]; - export function globFirst(pattern: string): string; - /** - * Exec a tool. Convenience wrapper over ToolRunner to exec with args in one call. - * Output will be streamed to the live console. - * Returns promise with return code - * - * @param tool path to tool to exec - * @param args an arg string or array of args - * @param options optional exec options. See IExecOptions - * @returns number - */ - export function exec(tool: string, args: any, options?: trm.IExecOptions): Q.Promise; - /** - * Exec a tool synchronously. Convenience wrapper over ToolRunner to execSync with args in one call. - * Output will be *not* be streamed to the live console. It will be returned after execution is complete. - * Appropriate for short running tools - * Returns IExecResult with output and return code - * - * @param tool path to tool to exec - * @param args an arg string or array of args - * @param options optionalexec options. See IExecOptions - * @returns IExecResult - */ - export function execSync(tool: string, args: string | string[], options?: trm.IExecOptions): trm.IExecResult; - /** - * Convenience factory to create a ToolRunner. - * - * @param tool path to tool to exec - * @returns ToolRunner - */ - export function createToolRunner(tool: string): trm.ToolRunner; - - /** - * Convenience factory to create a ToolRunner. - * - * @param tool path to tool to exec - * @returns ToolRunner - */ - export function tool(tool: string) : trm.ToolRunner; - - export function match(list: any, pattern: any, options: any): string[]; - export function filter(pattern: any, options: any): (element: string, indexed: number, array: string[]) => boolean; - export class TestPublisher { - constructor(testRunner: any); - testRunner: string; - publish(resultFiles: any, mergeResults: any, platform: any, config: any, runTitle: any, publishRunAttachments: any): void; - } - export class CodeCoveragePublisher { - constructor(); - publish(codeCoverageTool: any, summaryFileLocation: any, reportDirectory: any, additionalCodeCoverageFiles: any): void; - } - export class CodeCoverageEnabler { - private buildTool; - private ccTool; - constructor(buildTool: string, ccTool: string); - enableCodeCoverage(buildProps: { - [key: string]: string; - }): void; - } - export function _loadData(): void; - -} diff --git a/Tasks/XamarinLicense/xamarinlicense.ts b/Tasks/XamarinLicense/xamarinlicense.ts deleted file mode 100644 index 9e20b8de9d7c..000000000000 --- a/Tasks/XamarinLicense/xamarinlicense.ts +++ /dev/null @@ -1,361 +0,0 @@ -/* - Copyright (c) Microsoft. All rights reserved. - Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ - -import fs = require('fs'); -import path = require('path'); -import os = require('os'); -import https = require('https'); -import http = require('http'); -import tl = require('vsts-task-lib/task'); - -// Get inputs -var action = tl.getInput('action', true); -var email = tl.getInput('email', true); -var password = tl.getInput('password', true); -var activateAndroid = tl.getInput('activateAndroid', false); -var product = tl.getInput('product', false); -var timeout = tl.getInput('timeout', false); - -// Output debug information for inputs -tl.debug('action: ' + action); -tl.debug('email: ' + email); -tl.debug('product: ' + product); -tl.debug('activateAndroid: ' + activateAndroid); -tl.debug('timeout: ' + timeout); - -// Function for error handling -var onFailedExecution = function (err) { - // Error executing - tl.error(err); - tl.exit(1); -} - -//validate inputs -if (!product) { - //older task.json - if (activateAndroid == 'true') { - product = 'MA'; - } -} - -if (!product) { - onFailedExecution('No product selected to activate.'); -} - -if (isNaN(Number(timeout))) { - timeout = '30'; -} -var timeoutInSecs = Number(timeout); - -var getLicenseLocation = function (product) { - var licenseLocation; - if (product == 'MA' && os.platform() == 'darwin') { - licenseLocation = process.env.HOME + '/Library/MonoAndroid/License'; - } else if (product == 'MT' && os.platform() == 'darwin') { - licenseLocation = process.env.HOME + '/Library/MonoTouch/License.v2'; - } else if (product == 'MM' && os.platform() == 'darwin') { - licenseLocation = process.env.HOME + '/Library/Xamarin.Mac/License' - } else if (product == 'MA' && os.platform() == 'win32') { - licenseLocation = process.env.PROGRAMDATA + '\\Mono For Android\\License\\monoandroid.licx'; - } else if (product == 'MT' && os.platform() == 'win32') { - licenseLocation = process.env.PROGRAMDATA + '\\MonoTouch\\License\\monotouch.licx'; - } - - return licenseLocation; -} - -if (!getLicenseLocation(product)) { - onFailedExecution('The xamarin product: ' + product + ' is not supported on this os: ' + os.platform()); -} - -//xamarin data file -var getDataFileLocation = function (product) { - var dataFileLocation = process.env.HOME + '/vsts_generated_' + product + '.dat'; - if (os.platform() == 'win32') { - dataFileLocation = process.env.USERPROFILE + '\\vsts_generated_' + product + '.dat'; - } - return dataFileLocation; -} - -var doHttpRequest = function (options, requestBody, timeout, callback) { - var reqData; - var socket; - - if (requestBody) { - reqData = requestBody; - options.headers["Content-Length"] = Buffer.byteLength(reqData, 'utf8'); - } - - var req = https.request(options, function (res) { - var output = ''; - - res.on('data', function (chunk) { - output += chunk; - }); - - res.on('end', function () { - callback(null, res, output); - }); - }); - - req.on('socket', function (sock) { - socket = sock; - }); - - req.setTimeout(timeout, function () { - if (socket) { - socket.end(); - } - }); - - req.on('error', function (err) { - callback(err, null, null); - }); - - if (reqData) { - req.write(reqData, 'utf8'); - } - - req.end(); -} - -var loginToXamarin = function (email, password, callback) { - var apiKey = '96cae35ce8a9b0244178bf28e4966c2ce1b8385723a96a6b838858cdd6ca0a1e'; - //Login as user - tl.debug('Login as ' + email); - var loginRequestBody = 'email=' + encodeURIComponent(email) + '&password=' + encodeURIComponent(password); - var options = { - host: 'auth.xamarin.com', - path: '/api/v1/auth', - method: 'POST', - headers: { - 'Host': 'auth.xamarin.com', - 'User-Agent': 'vso-agent-tasks-Xamarin-License', - 'Authorization': 'Basic ' + new Buffer(apiKey + ':').toString('base64'), - 'Content-Type': 'application/x-www-form-urlencoded' - }, - }; - doHttpRequest(options, loginRequestBody, timeoutInSecs, function (err, res, output) { - if (err) { - tl.debug('Login failed: ' + err); - callback('Failed to login to Xamarin with specified email and password.', null, null); - } - - if (!output) { - tl.debug('Login failed. HTTP response code: ' + res.ResponseCode); - callback('Failed to login to Xamarin with specified email and password.', null, null); - } - - var responseJson = JSON.parse(output); - if (!responseJson || !responseJson.token || !responseJson.user || !responseJson.user.Guid) { - tl.debug('Login failed. Json response: ' + output); - callback('Failed to login to Xamarin with specified email and password.', null, null); - } - - //Login succeeded - callback(null, responseJson.token, responseJson.user.Guid); - }); -} - -var activateLicense = function (email, password, product, callback) { - loginToXamarin(email, password, function (err, token, userGuid) { - if (err) { - callback(err); - } - if (!token || !userGuid) { - callback('Failed to login to Xamarin with specified email and password.'); - } - - tl.debug('Activate Xamarin license'); - - //Provision the machine - var mToolPath; - if (product == 'MA') { - //find path to mandroid - var programFiles = 'C:\\Program Files (x86)'; - if (os.platform() == 'win32' && os.arch() == 'x64') { - programFiles = process.env['PROGRAMFILES(X86)']; - } else if (os.platform() == 'win32' && os.arch() == 'ia32') { - programFiles = process.env.PROGRAMFILES; - } - - if (os.platform() == 'darwin') { - mToolPath = '/Library/Frameworks/Xamarin.Android.framework/Commands/mandroid'; - } else if (os.platform() == 'win32') { - mToolPath = programFiles + '\\MSBuild\\Xamarin\\Android\\mandroid.exe'; - } - if (!fs.existsSync(mToolPath)) { - tl.debug('The path to mandroid does not exist: ' + mToolPath); - callback('Failed to activate Xamarin license.'); - } - } else if (product == 'MT' || product == 'MM') { - //find path to mtouch - if (os.platform() == 'darwin') { - mToolPath = '/Library/Frameworks/Xamarin.iOS.framework/Versions/Current/bin/mtouch'; - } else { - mToolPath = programFiles + '\\MSBuild\\Xamarin\\iOS\\mtouch.exe'; - } - if (!fs.existsSync(mToolPath)) { - tl.debug('The path to mtouch does not exist: ' + mToolPath); - callback('Failed to activate Xamarin license.'); - } - } - - var dataFileLocation = getDataFileLocation(product); - tl.cd(path.dirname(mToolPath)); - var mToolRunner = tl.createToolRunner(mToolPath); - mToolRunner.arg('--datafile'); - var toolOutput = mToolRunner.execSync(null); //We need the stdout, so use the sync version - if (!toolOutput || !toolOutput.stdout) { - tl.debug('Failed to generate data file using: ' + mToolPath); - callback('Failed to activate Xamarin license.'); - } - fs.writeFile(dataFileLocation, toolOutput.stdout, function (err) { - if (err) { - tl.debug('Failed to write data file: ' + err); - callback('Failed to activate Xamarin license.'); - } - - //Read the xamarin.dat file - fs.readFile(dataFileLocation, function (err, data) { - if (err) { - tl.debug('Failed to read datafile: ' + err); - callback('Failed to activate Xamarin license.'); - } - - //Call Xamarin activation endpoint - var options = { - host: 'activation.xamarin.com', - path: '/api/studio.ashx?guid=' + decodeURI(userGuid) + '&token=' + encodeURI(token) + '&product=' + encodeURI(product), - method: 'POST', - headers: { - 'Host': 'activation.xamarin.com', - 'User-Agent': 'vso-agent-tasks-Xamarin-License', - 'Content-Type': 'application/x-www-form-urlencoded' - }, - }; - - doHttpRequest(options, data, timeoutInSecs, function (err, res, output) { - if (err) { - callback('Failed to activate Xamarin license. ' + err); - } - if (!output) { - tl.debug('License activation failed. Response code = ' + res.ResponseCode); - callback('Failed to activate Xamarin license.'); - } - - var jsonResponse = JSON.parse(output); - if (!jsonResponse || !jsonResponse.license) { - callback('Failed to activate Xamarin license. ' + output); - } - - //Activation succeeded - var licenseDecoded = new Buffer(jsonResponse.license, 'base64'); - - //Save license file - var licenseLocation = getLicenseLocation(product); - tl.mkdirP(path.dirname(licenseLocation)); - fs.writeFile(licenseLocation, licenseDecoded, function (err) { - if (err) { - callback('Failed to save Xamarin license. ' + err); - } - callback(null); - }); //writeFile - }); //doHttpRequest - }); //read .dat file - }); //toolrunner exec - }); //login -} - -var deactivateLicense = function (email, password, product, callback) { - loginToXamarin(email, password, function (err, token, userGuid) { - if (err) { - callback(err); - } - - if (!token || !userGuid) { - callback('Failed to login to Xamarin with specified email and password.'); - } - - tl.debug('Deactivate Xamarin License'); - - //Read the xamarin.dat file - var dataFileLocation = getDataFileLocation(product); - fs.readFile(dataFileLocation, function (err, data) { - if (err) { - tl.debug('Failed to read datafile: ' + err); - callback('Failed to deactivate license, only license activated by this task can be deactivated.'); - } - - //Call Xamarin activation endpoint - var options = { - host: 'activation.xamarin.com', - path: '/api/deactivate.ashx?guid=' + decodeURI(userGuid) + '&token=' + encodeURI(token), - method: 'POST', - headers: { - 'Host': 'activation.xamarin.com', - 'User-Agent': 'vso-agent-tasks-Xamarin-License', - 'Content-Type': 'application/x-www-form-urlencoded' - }, - }; - - doHttpRequest(options, data, timeoutInSecs, function (err, res, output) { - if (err) { - callback('Failed to deactivate Xamarin license. ' + err); - } - if (!output) { - tl.debug('License deactivation failed. Response code = ' + res.ResponseCode); - callback('Failed to deactivate Xamarin license.'); - } - - var jsonResponse = JSON.parse(output); - if (!jsonResponse || !jsonResponse.success) { - callback('Failed to deactivate Xamarin license. ' + output); - } - - //Deactivation succeeded - - //delete license file - var licenseLocation = getLicenseLocation(product); - fs.exists(licenseLocation, function (exists) { - if (exists) { - fs.unlink(licenseLocation, function (err) { - if (err) { - tl.debug('Failed to delete license file on disk: ' + err); - tl.warning('Failed to delete license file on disk: ' + licenseLocation); - } - }); - } - }); - }); - }); - }); -} - -if (action == 'Activate') { - //check if already activated - var licenseLocation = getLicenseLocation(product); - if (fs.existsSync(licenseLocation)) { - tl.debug('License file already exists: ' + licenseLocation); - tl.exit(0); //return success - } else { - activateLicense(email, password, product, function (err) { - if (err) { - onFailedExecution(err); - } - tl.exit(0); - }); - } -} else if (action == 'Deactivate') { - deactivateLicense(email, password, product, function (err) { - if (err) { - onFailedExecution(err); - } - tl.exit(0); - }); -} else { - tl.error('Unknown action: ' + action); - tl.exit(1); -} \ No newline at end of file diff --git a/Tasks/cURLUploader/task.json b/Tasks/cURLUploader/task.json index f58c7fd18018..50530a6a96fe 100644 --- a/Tasks/cURLUploader/task.json +++ b/Tasks/cURLUploader/task.json @@ -9,8 +9,12 @@ "version": { "Major": 1, "Minor": 0, - "Patch": 20 + "Patch": 21 }, + "runsOn": [ + "Agent", + "MachineGroup" + ], "demands": [ "curl" ], diff --git a/Tasks/cURLUploader/task.loc.json b/Tasks/cURLUploader/task.loc.json index f431d68d0a07..d1c3e24197d0 100644 --- a/Tasks/cURLUploader/task.loc.json +++ b/Tasks/cURLUploader/task.loc.json @@ -9,8 +9,12 @@ "version": { "Major": 1, "Minor": 0, - "Patch": 20 + "Patch": 21 }, + "runsOn": [ + "Agent", + "MachineGroup" + ], "demands": [ "curl" ], diff --git a/Tests/L0/ServiceFabricDeploy/AadDeploy.ps1 b/Tests/L0/ServiceFabricDeploy/AadDeploy.ps1 index 3e4f5cf75f87..6c59a39d8b27 100644 --- a/Tests/L0/ServiceFabricDeploy/AadDeploy.ps1 +++ b/Tests/L0/ServiceFabricDeploy/AadDeploy.ps1 @@ -84,7 +84,7 @@ Register-Mock Get-ApplicationNameFromApplicationParameterFile { $appName } -- "$ # Indicate that the application does not exist on cluster Register-Mock Get-ServiceFabricApplication { $null } -- -ApplicationName $appName -$publishArgs = @("-ApplicationPackagePath", $applicationPackagePath, "-ApplicationParameterFilePath", "$PSScriptRoot\data\ApplicationParameters.xml", "-Action", "RegisterAndCreate", "-OverwriteBehavior", "SameAppTypeAndVersion", "-ErrorAction", "Stop") +$publishArgs = @("-ApplicationParameterFilePath:", "$PSScriptRoot\data\ApplicationParameters.xml", "-ErrorAction:", "Stop", "-ApplicationPackagePath:", $applicationPackagePath, "-Action:", "RegisterAndCreate", "-OverwriteBehavior:", "SameAppTypeAndVersion") Register-Mock Publish-NewServiceFabricApplication -Arguments $publishArgs # Act diff --git a/Tests/L0/ServiceFabricDeploy/CertDeploy.ps1 b/Tests/L0/ServiceFabricDeploy/CertDeploy.ps1 index 925c34e953cc..186a5cc72e29 100644 --- a/Tests/L0/ServiceFabricDeploy/CertDeploy.ps1 +++ b/Tests/L0/ServiceFabricDeploy/CertDeploy.ps1 @@ -54,8 +54,7 @@ Register-Mock Get-ApplicationNameFromApplicationParameterFile { $appName } -- "$ # Indicate that the application does not exist on cluster Register-Mock Get-ServiceFabricApplication { $null } -- -ApplicationName $appName - -$publishArgs = @("-ApplicationPackagePath", $applicationPackagePath, "-ApplicationParameterFilePath", "$PSScriptRoot\data\ApplicationParameters.xml", "-Action", "RegisterAndCreate", "-OverwriteBehavior", "SameAppTypeAndVersion", "-ErrorAction", "Stop") +$publishArgs = @("-ApplicationParameterFilePath:", "$PSScriptRoot\data\ApplicationParameters.xml", "-ErrorAction:", "Stop", "-ApplicationPackagePath:", $applicationPackagePath, "-Action:", "RegisterAndCreate", "-OverwriteBehavior:", "SameAppTypeAndVersion") Register-Mock Publish-NewServiceFabricApplication -Arguments $publishArgs try diff --git a/Tests/L0/ServiceFabricDeploy/NoAuthDeploy.ps1 b/Tests/L0/ServiceFabricDeploy/NoAuthDeploy.ps1 index 439e38d35bac..77374816faae 100644 --- a/Tests/L0/ServiceFabricDeploy/NoAuthDeploy.ps1 +++ b/Tests/L0/ServiceFabricDeploy/NoAuthDeploy.ps1 @@ -42,9 +42,8 @@ Register-Mock Get-ApplicationNameFromApplicationParameterFile { $appName } -- "$ # Indicate that the application does not exist on cluster Register-Mock Get-ServiceFabricApplication { $null } -- -ApplicationName $appName - -$publishArgs = @("-ApplicationPackagePath", $applicationPackagePath, "-ApplicationParameterFilePath", "$PSScriptRoot\data\ApplicationParameters.xml", "-Action", "RegisterAndCreate", "-OverwriteBehavior", "SameAppTypeAndVersion", "-ErrorAction", "Stop") -Register-Mock Publish-NewServiceFabricApplication -Arguments $publishArgs +$publishArgs = @("-ApplicationParameterFilePath:", "$PSScriptRoot\data\ApplicationParameters.xml", "-ErrorAction:", "Stop", "-ApplicationPackagePath:", $applicationPackagePath, "-Action:", "RegisterAndCreate", "-OverwriteBehavior:", "SameAppTypeAndVersion") +Register-Mock Publish-NewServiceFabricApplication -Arguments $publishArgs # Act @( & $PSScriptRoot/../../../Tasks/ServiceFabricDeploy/deploy.ps1 ) diff --git a/Tests/L0/VsTest/_suite.ts b/Tests/L0/VsTest/_suite.ts index e58413969069..2425067d5840 100644 --- a/Tests/L0/VsTest/_suite.ts +++ b/Tests/L0/VsTest/_suite.ts @@ -1,7 +1,6 @@ /// /// /// -/// import Q = require('q'); import assert = require('assert'); @@ -12,46 +11,13 @@ import os = require('os'); import mockHelper = require('../../lib/mockHelper'); import fs = require('fs'); import shell = require('shelljs'); -import uuid = require('node-uuid'); + var ps = shell.which('powershell.exe'); var psr = null; -const tmpFileName = path.join(os.tmpdir(), uuid.v1() + ".json"); -const testDllPath = path.join(__dirname, "data", "testDlls"); const sysVstestLocation = "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe"; -function setResponseFile(name: string, vstestCmd?: string, isPass?: boolean) { - let fileName = path.join(__dirname, name); - if (typeof vstestCmd !== "undefined") { - if (typeof isPass === "undefined") { - isPass = true; - } - let fileContent: string = fs.readFileSync(fileName, 'utf8'); - let fileJson = JSON.parse(fileContent); - let errCode: number = isPass ? 0 : 1; - let stdErr: string = isPass ? "" : "Error string"; - - fileJson.exec[vstestCmd] = { "code": errCode, "stdout": "vstest", "stderr": stdErr }; - fs.writeFileSync(tmpFileName, JSON.stringify(fileJson)); - fileName = tmpFileName; - } - process.env['MOCK_RESPONSES'] = fileName; -} - -function posixFormat(p: string): string { - let path_regex = /\/\//; - p = p.replace(/\\/g, '/'); - while (p.match(path_regex)) { - p = p.replace(path_regex, '/'); - } - return p; -} - -function getTestDllString(testDlls: string[]): string { - let dllString: string = ""; - testDlls.forEach(function (part, index) { - testDlls[index] = posixFormat(path.join(testDllPath, testDlls[index])); - }); - return testDlls.join(" "); +function setResponseFile(name: string) { + process.env['MOCK_RESPONSES'] = path.join(__dirname, name); } describe('VsTest Suite', function () { @@ -62,17 +28,11 @@ describe('VsTest Suite', function () { psr = new psm.PSRunner(); psr.start(); } - done(); }); after(function () { psr.kill(); - fs.unlink(tmpFileName, function (err) { - if (err) { - console.log("Error encountered deleting temp file: " + err); - } - }); }); if (ps) { @@ -196,15 +156,11 @@ describe('VsTest Suite', function () { it('Vstest task with test results files filter', (done) => { - let filePattern = getTestDllString(["testAssembly1.dll", "testAssembly2.dll"]); - let vstestCmd = [sysVstestLocation, filePattern, "/logger:trx"].join(" "); - - setResponseFile('vstestGood.json', vstestCmd); + let vstestCmd = [sysVstestLocation, "/source/dir/someFile2 /source/dir/someFile1", "/logger:trx"].join(" "); + setResponseFile('vstestGood.json'); let tr = new trm.TaskRunner('VSTest'); - let assemblyPattern = path.join(__dirname, "data", "testDlls", "*.dll"); - - tr.setInput('testAssembly', assemblyPattern); + tr.setInput('testAssemblyVer2', '/source/dir/some/*pattern'); tr.setInput('vstestLocationMethod', 'version'); tr.setInput('vsTestVersion', '14.0'); @@ -224,15 +180,11 @@ describe('VsTest Suite', function () { it('Vstest task with test results files filter and exclude filter', (done) => { - let filePattern = getTestDllString(["testAssembly1.dll"]); - let vstestCmd = [sysVstestLocation, filePattern, "/logger:trx"].join(" "); - - setResponseFile('vstestGood.json', vstestCmd); + let vstestCmd = [sysVstestLocation, "/source/dir/someFile1", "/logger:trx"].join(" "); + setResponseFile('vstestGood.json'); let tr = new trm.TaskRunner('VSTest'); - let assemblyPattern = path.join(__dirname, "data", "testDlls", "*1.dll") + ";-:" + path.join(__dirname, "data", "testDlls", "*2.dll"); - - tr.setInput('testAssembly', assemblyPattern); + tr.setInput('testAssemblyVer2', '/source/dir/some/*pattern\n!/source/dir/some/*excludePattern'); tr.setInput('vstestLocationMethod', 'version'); tr.setInput('vsTestVersion', '14.0'); @@ -252,13 +204,11 @@ describe('VsTest Suite', function () { it('Vstest task with test results files as path', (done) => { - let filePattern = getTestDllString(["testAssembly1.dll"]); - let vstestCmd = [sysVstestLocation, filePattern, "/logger:trx"].join(" "); - - setResponseFile('vstestGood.json', vstestCmd); + let vstestCmd = [sysVstestLocation, '/source/dir/someFile1', "/logger:trx"].join(" "); + setResponseFile('vstestGood.json'); let tr = new trm.TaskRunner('VSTest'); - tr.setInput('testAssembly', filePattern); + tr.setInput('testAssemblyVer2', '/source/dir/someFile1'); tr.setInput('vstestLocationMethod', 'version'); tr.setInput('vsTestVersion', '14.0'); @@ -278,15 +228,11 @@ describe('VsTest Suite', function () { it('Vstest task when vstest fails', (done) => { - let filePattern = getTestDllString(["testAssembly1.dll", "testAssembly2.dll"]); - let vstestCmd = [sysVstestLocation, filePattern, "/logger:trx"].join(" "); - - setResponseFile('vstestFails.json', vstestCmd, false); + let vstestCmd = [sysVstestLocation, '/source/dir/someFile2 /source/dir/someFile1', "/logger:trx"].join(" "); + setResponseFile('vstestFails.json'); let tr = new trm.TaskRunner('VSTest'); - let assemblyPattern = path.join(__dirname, "data", "testDlls", "*.dll"); - - tr.setInput('testAssembly', assemblyPattern); + tr.setInput('testAssemblyVer2', '/source/dir/some/*pattern'); tr.setInput('vstestLocationMethod', 'version'); tr.setInput('vsTestVersion', '14.0'); @@ -306,15 +252,11 @@ describe('VsTest Suite', function () { it('Vstest task when vstest of specified version is not found', (done) => { - let filePattern = getTestDllString(["testAssembly1.dll"]); - let vstestCmd = [sysVstestLocation, filePattern, "/logger:trx"].join(" "); - - setResponseFile('vstestFails.json', vstestCmd, false); // this response file does not have vs 2013 + let vstestCmd = [sysVstestLocation, '/source/dir/someFile1', "/logger:trx"].join(" "); + setResponseFile('vstestFails.json'); // this response file does not have vs 2013 let tr = new trm.TaskRunner('VSTest'); - let assemblyPattern = path.join(__dirname, "data", "testDlls", "*1.dll"); - - tr.setInput('testAssembly', assemblyPattern); + tr.setInput('testAssemblyVer2', '/source/dir/someFile1'); tr.setInput('vstestLocationMethod', 'version'); tr.setInput('vsTestVersion', '12.0'); @@ -335,15 +277,11 @@ describe('VsTest Suite', function () { it('Vstest task with test case filter', (done) => { - let filePattern = getTestDllString(["testAssembly1.dll"]); - let vstestCmd = [sysVstestLocation, filePattern, "/TestCaseFilter:testFilter", "/logger:trx"].join(" "); - - setResponseFile('vstestGood.json', vstestCmd); + let vstestCmd = [sysVstestLocation, '/source/dir/someFile1', "/TestCaseFilter:testFilter", "/logger:trx"].join(" "); + setResponseFile('vstestGood.json'); let tr = new trm.TaskRunner('VSTest'); - let assemblyPattern = path.join(__dirname, "data", "testDlls", "*1.dll"); - - tr.setInput('testAssembly', assemblyPattern); + tr.setInput('testAssemblyVer2', '/source/dir/someFile1'); tr.setInput('testFiltercriteria', 'testFilter'); tr.setInput('vstestLocationMethod', 'version'); tr.setInput('vsTestVersion', '14.0'); @@ -363,15 +301,12 @@ describe('VsTest Suite', function () { }) it('Vstest task with enable code coverage', (done) => { - let filePattern = getTestDllString(["testAssembly1.dll"]); - let vstestCmd = [sysVstestLocation, filePattern, "/EnableCodeCoverage", "/logger:trx"].join(" "); - setResponseFile('vstestGood.json', vstestCmd); + let vstestCmd = [sysVstestLocation, '/source/dir/someFile1', "/EnableCodeCoverage", "/logger:trx"].join(" "); + setResponseFile('vstestGood.json'); let tr = new trm.TaskRunner('VSTest'); - let assemblyPattern = path.join(__dirname, "data", "testDlls", "*1.dll"); - - tr.setInput('testAssembly', assemblyPattern); + tr.setInput('testAssemblyVer2', '/source/dir/someFile1'); tr.setInput('codeCoverageEnabled', 'true'); tr.setInput('vstestLocationMethod', 'version'); tr.setInput('vsTestVersion', '14.0'); @@ -392,15 +327,11 @@ describe('VsTest Suite', function () { it('Vstest task with other console options', (done) => { - let filePattern = getTestDllString(["testAssembly1.dll"]); - let vstestCmd = [sysVstestLocation, filePattern, "consoleOptions", "/logger:trx"].join(" "); - - setResponseFile('vstestGood.json', vstestCmd); + let vstestCmd = [sysVstestLocation, '/source/dir/someFile1', "consoleOptions", "/logger:trx"].join(" "); + setResponseFile('vstestGood.json'); let tr = new trm.TaskRunner('VSTest'); - let assemblyPattern = path.join(__dirname, "data", "testDlls", "*1.dll"); - - tr.setInput('testAssembly', assemblyPattern); + tr.setInput('testAssemblyVer2', '/source/dir/someFile1'); tr.setInput('otherConsoleOptions', 'consoleOptions'); tr.setInput('vstestLocationMethod', 'version'); tr.setInput('vsTestVersion', '14.0'); @@ -421,15 +352,11 @@ describe('VsTest Suite', function () { it('Vstest task with settings file', (done) => { - let filePattern = getTestDllString(["testAssembly1.dll"]); - let vstestCmd = [sysVstestLocation, filePattern, "/Settings:settings.runsettings", "/logger:trx"].join(" "); - - setResponseFile('vstestGood.json', vstestCmd); + let vstestCmd = [sysVstestLocation, '/source/dir/someFile1', "/Settings:settings.runsettings", "/logger:trx"].join(" "); + setResponseFile('vstestGood.json'); let tr = new trm.TaskRunner('VSTest'); - let assemblyPattern = path.join(__dirname, "data", "testDlls", "*1.dll"); - - tr.setInput('testAssembly', assemblyPattern); + tr.setInput('testAssemblyVer2', '/source/dir/someFile1'); tr.setInput('vstestLocationMethod', 'version'); tr.setInput('vsTestVersion', '14.0'); tr.setInput('runSettingsFile', "settings.runsettings"); @@ -450,15 +377,11 @@ describe('VsTest Suite', function () { it('Vstest task with run in parallel and vs 2013', (done) => { - let filePattern = getTestDllString(["testAssembly1.dll"]); - let vstestCmd = [sysVstestLocation, filePattern, "/logger:trx"].join(" "); - - setResponseFile('vstestGood.json', vstestCmd); + let vstestCmd = [sysVstestLocation, '/source/dir/someFile1', "/logger:trx"].join(" "); + setResponseFile('vstestGood.json'); let tr = new trm.TaskRunner('VSTest'); - let assemblyPattern = path.join(__dirname, "data", "testDlls", "*1.dll"); - - tr.setInput('testAssembly', assemblyPattern); + tr.setInput('testAssemblyVer2', '/source/dir/someFile1'); tr.setInput('vstestLocationMethod', 'version'); tr.setInput('vsTestVersion', '12.0'); tr.setInput('runInParallel', 'true'); @@ -480,15 +403,11 @@ describe('VsTest Suite', function () { it('Vstest task with run in parallel and vs 2014 below update1', (done) => { - let filePattern = getTestDllString(["testAssembly1.dll"]); - let vstestCmd = [sysVstestLocation, filePattern, "/logger:trx"].join(" "); - - setResponseFile('vstestGood.json', vstestCmd); + let vstestCmd = [sysVstestLocation, '/source/dir/someFile1', "/logger:trx"].join(" "); + setResponseFile('vstestGood.json'); let tr = new trm.TaskRunner('VSTest'); - let assemblyPattern = path.join(__dirname, "data", "testDlls", "*1.dll"); - - tr.setInput('testAssembly', assemblyPattern); + tr.setInput('testAssemblyVer2', '/source/dir/someFile1'); tr.setInput('vstestLocationMethod', 'version'); tr.setInput('vsTestVersion', '14.0'); // response file sets below update1 tr.setInput('runInParallel', 'true'); @@ -510,15 +429,11 @@ describe('VsTest Suite', function () { it('Vstest task with run in parallel and vs 2015', (done) => { - let filePattern = getTestDllString(["testAssembly1.dll"]); - let vstestCmd = [sysVstestLocation, filePattern, "/logger:trx"].join(" "); - - setResponseFile('vstestGood.json', vstestCmd); + let vstestCmd = [sysVstestLocation, '/source/dir/someFile1', "/logger:trx"].join(" "); + setResponseFile('vstestGood.json'); let tr = new trm.TaskRunner('VSTest'); - let assemblyPattern = path.join(__dirname, "data", "testDlls", "*1.dll"); - - tr.setInput('testAssembly', assemblyPattern); + tr.setInput('testAssemblyVer2', '/source/dir/someFile1'); tr.setInput('vstestLocationMethod', 'version'); tr.setInput('vsTestVersion', '15.0'); tr.setInput('runInParallel', 'true'); @@ -540,15 +455,11 @@ describe('VsTest Suite', function () { it('Vstest task with run in parallel and vs 2014 update1 or higher', (done) => { - let filePattern = getTestDllString(["testAssembly1.dll"]); - let vstestCmd = [sysVstestLocation, filePattern, "/logger:trx"].join(" "); - - setResponseFile('vstestRunInParallel.json', vstestCmd); + let vstestCmd = [sysVstestLocation, '/source/dir/someFile1', "/logger:trx"].join(" "); + setResponseFile('vstestRunInParallel.json'); let tr = new trm.TaskRunner('VSTest'); - let assemblyPattern = path.join(__dirname, "data", "testDlls", "*1.dll"); - - tr.setInput('testAssembly', assemblyPattern); + tr.setInput('testAssemblyVer2', '/source/dir/someFile1'); tr.setInput('vstestLocationMethod', 'version'); tr.setInput('vsTestVersion', '14.0'); // response file sets above update1 tr.setInput('runInParallel', 'true'); @@ -570,15 +481,11 @@ describe('VsTest Suite', function () { it('Vstest task with custom adapter path', (done) => { - let filePattern = getTestDllString(["testAssembly1.dll"]); - let vstestCmd = [sysVstestLocation, filePattern, "/logger:trx", "/TestAdapterPath:path/to/customadapters"].join(" "); - - setResponseFile('vstestGood.json', vstestCmd); + let vstestCmd = [sysVstestLocation, '/source/dir/someFile1', "/logger:trx", "/TestAdapterPath:path/to/customadapters"].join(" "); + setResponseFile('vstestGood.json'); let tr = new trm.TaskRunner('VSTest'); - let assemblyPattern = path.join(__dirname, "data", "testDlls", "*1.dll"); - - tr.setInput('testAssembly', assemblyPattern); + tr.setInput('testAssemblyVer2', '/source/dir/someFile1'); tr.setInput('vstestLocationMethod', 'version'); tr.setInput('vsTestVersion', '14.0'); tr.setInput('pathtoCustomTestAdapters', "path/to/customadapters"); @@ -599,15 +506,11 @@ describe('VsTest Suite', function () { it('Vstest task with runsettings file and tia.enabled set to false', (done) => { - let filePattern = getTestDllString(["testAssembly1.dll"]); - let vstestCmd = [sysVstestLocation, filePattern, "/Settings:settings.runsettings", "/logger:trx"].join(" "); - - setResponseFile('vstestGoodWithTiaDisabled.json', vstestCmd); + let vstestCmd = [sysVstestLocation, '/source/dir/someFile1', "/Settings:settings.runsettings", "/logger:trx"].join(" "); + setResponseFile('vstestGoodWithTiaDisabled.json'); let tr = new trm.TaskRunner('VSTest'); - let assemblyPattern = path.join(__dirname, "data", "testDlls", "*1.dll"); - - tr.setInput('testAssembly', assemblyPattern); + tr.setInput('testAssemblyVer2', '/source/dir/someFile1'); tr.setInput('vstestLocationMethod', 'version'); tr.setInput('vsTestVersion', '14.0'); tr.setInput('runSettingsFile', "settings.runsettings"); @@ -629,15 +532,11 @@ describe('VsTest Suite', function () { it('Vstest task with runsettings file and tia.enabled undefined', (done) => { - let filePattern = getTestDllString(["testAssembly1.dll"]); - let vstestCmd = [sysVstestLocation, filePattern, "/Settings:settings.runsettings", "/logger:trx"].join(" "); - - setResponseFile('vstestGood.json', vstestCmd); + let vstestCmd = [sysVstestLocation, '/source/dir/someFile1', "/Settings:settings.runsettings", "/logger:trx"].join(" "); + setResponseFile('vstestGood.json'); let tr = new trm.TaskRunner('VSTest'); - let assemblyPattern = path.join(__dirname, "data", "testDlls", "*1.dll"); - - tr.setInput('testAssembly', assemblyPattern); + tr.setInput('testAssemblyVer2', '/source/dir/someFile1'); tr.setInput('vstestLocationMethod', 'version'); tr.setInput('vsTestVersion', '14.0'); tr.setInput('runSettingsFile', "settings.runsettings"); @@ -668,15 +567,12 @@ describe('VsTest Suite', function () { var newResponseFilePath: string = path.join(__dirname, 'newresponse.json'); fs.writeFileSync(newResponseFilePath, JSON.stringify(responseJsonContent)); - let filePattern = getTestDllString(["testAssembly1.dll"]); - let vstestCmd = [sysVstestLocation, filePattern, "/logger:trx"].join(" "); + let vstestCmd = [sysVstestLocation, '/source/dir/someFile1', "/logger:trx"].join(" "); - setResponseFile(path.basename(newResponseFilePath), vstestCmd); + setResponseFile(path.basename(newResponseFilePath)); let tr = new trm.TaskRunner('VSTest'); - let assemblyPattern = path.join(__dirname, "data", "testDlls", "*1.dll"); - - tr.setInput('testAssembly', assemblyPattern); + tr.setInput('testAssemblyVer2', '/source/dir/someFile1'); tr.setInput('vstestLocationMethod', 'version'); tr.setInput('vsTestVersion', '14.0'); tr.setInput('runSettingsFile', settingsFilePath); @@ -702,15 +598,11 @@ describe('VsTest Suite', function () { let newResponseFilePath: string = path.join(__dirname, 'newresponse.json'); fs.writeFileSync(newResponseFilePath, JSON.stringify(responseJsonContent)); - let filePattern = getTestDllString(["testAssembly1.dll"]); - let vstestCmd = [sysVstestLocation, filePattern, "/logger:trx"].join(" "); - - setResponseFile(path.basename(newResponseFilePath), vstestCmd); + let vstestCmd = [sysVstestLocation, '/source/dir/someFile1', "/logger:trx"].join(" "); + setResponseFile(path.basename(newResponseFilePath)); let tr = new trm.TaskRunner('VSTest'); - let assemblyPattern = path.join(__dirname, "data", "testDlls", "*1.dll"); - - tr.setInput('testAssembly', assemblyPattern); + tr.setInput('testAssemblyVer2', '/source/dir/someFile1'); tr.setInput('vstestLocationMethod', 'version'); tr.setInput('vsTestVersion', '14.0'); tr.setInput('runSettingsFile', settingsFilePath); @@ -737,15 +629,11 @@ describe('VsTest Suite', function () { let newResponseFilePath: string = path.join(__dirname, 'newresponse.json'); fs.writeFileSync(newResponseFilePath, JSON.stringify(responseJsonContent)); - let filePattern = getTestDllString(["testAssembly1.dll"]); - let vstestCmd = [sysVstestLocation, filePattern, "/logger:trx"].join(" "); - - setResponseFile(path.basename(newResponseFilePath), vstestCmd); + let vstestCmd = [sysVstestLocation, '/source/dir/someFile1', "/logger:trx"].join(" "); + setResponseFile(path.basename(newResponseFilePath)); let tr = new trm.TaskRunner('VSTest'); - let assemblyPattern = path.join(__dirname, "data", "testDlls", "*1.dll"); - - tr.setInput('testAssembly', assemblyPattern); + tr.setInput('testAssemblyVer2', '/source/dir/someFile1'); tr.setInput('vstestLocationMethod', 'version'); tr.setInput('vsTestVersion', '14.0'); tr.setInput('runSettingsFile', settingsFilePath); @@ -763,15 +651,11 @@ describe('VsTest Suite', function () { it('Vstest task with custom vstest.console.exe path', (done) => { - let filePattern = getTestDllString(["testAssembly1.dll"]); - let vstestCmd = ["some\\path\\to\\vstest.console.exe", filePattern, "/logger:trx"].join(" "); - - setResponseFile('vstestGood.json', vstestCmd); + let vstestCmd = ["some\\path\\to\\vstest.console.exe", '/source/dir/someFile1', "/logger:trx"].join(" "); + setResponseFile('vstestGood.json'); let tr = new trm.TaskRunner('VSTest'); - let assemblyPattern = path.join(__dirname, "data", "testDlls", "*1.dll"); - - tr.setInput('testAssembly', assemblyPattern); + tr.setInput('testAssemblyVer2', '/source/dir/someFile1'); tr.setInput('vstestLocationMethod', 'location'); tr.setInput('vstestLocation', 'some\\path\\to\\vstest.console.exe'); tr.setInput('vsTestVersion', '14.0'); @@ -789,15 +673,11 @@ describe('VsTest Suite', function () { it('Vstest task with custom vstest.console.exe path should throw on illegal path', (done) => { - let filePattern = getTestDllString(["testAssembly1.dll"]); - let vstestCmd = ["some\\illegal\\path\\to\\vstest.console.exe", filePattern, "/logger:trx"].join(" "); - - setResponseFile('vstestGood.json', vstestCmd); + let vstestCmd = ["some\\illegal\\path\\to\\vstest.console.exe", '/source/dir/someFile1', "/logger:trx"].join(" "); + setResponseFile('vstestGood.json'); let tr = new trm.TaskRunner('VSTest'); - let assemblyPattern = path.join(__dirname, "data", "testDlls", "*1.dll"); - - tr.setInput('testAssembly', assemblyPattern); + tr.setInput('testAssemblyVer2', '/source/dir/someFile1'); tr.setInput('vstestLocationMethod', 'location'); tr.setInput('vstestLocation', 'some\\illegal\\path\\to\\vstest.console.exe'); tr.setInput('vsTestVersion', '14.0'); @@ -813,15 +693,11 @@ describe('VsTest Suite', function () { it('Vstest task specifying vstest.console directory in vstest location', (done) => { - let filePattern = getTestDllString(["testAssembly1.dll"]); - let vstestCmd = ["\\path\\to\\vstest\\directory\\vstest.console.exe", filePattern, "/logger:trx"].join(" "); - - setResponseFile('vstestGood.json', vstestCmd); + let vstestCmd = ["\\path\\to\\vstest\\directory\\vstest.console.exe", '/source/dir/someFile1', "/logger:trx"].join(" "); + setResponseFile('vstestGood.json'); let tr = new trm.TaskRunner('VSTest'); - let assemblyPattern = path.join(__dirname, "data", "testDlls", "*1.dll"); - - tr.setInput('testAssembly', assemblyPattern); + tr.setInput('testAssemblyVer2', '/source/dir/someFile1'); tr.setInput('vstestLocationMethod', 'location'); tr.setInput('vstestLocation', '\\path\\to\\vstest\\directory'); tr.setInput('vsTestVersion', '14.0'); @@ -839,15 +715,11 @@ describe('VsTest Suite', function () { it('Vstest task should not use diag option when system.debug is not set', (done) => { - let filePattern = getTestDllString(["testAssembly1.dll"]); - let vstestCmd = ["\\path\\to\\vstest\\directory\\vstest.console.exe", filePattern, "/logger:trx"].join(" "); - - setResponseFile('vstestGood.json', vstestCmd); + let vstestCmd = ["\\path\\to\\vstest\\directory\\vstest.console.exe", '/source/dir/someFile1', "/logger:trx"].join(" "); + setResponseFile('vstestGood.json'); let tr = new trm.TaskRunner('VSTest'); - let assemblyPattern = path.join(__dirname, "data", "testDlls", "*1.dll"); - - tr.setInput('testAssembly', assemblyPattern); + tr.setInput('testAssemblyVer2', '/source/dir/someFile1'); tr.setInput('vstestLocationMethod', 'location'); tr.setInput('vstestLocation', '\\path\\to\\vstest\\directory'); tr.setInput('vsTestVersion', '14.0'); @@ -866,15 +738,11 @@ describe('VsTest Suite', function () { it('Vstest task should not use diag option when system.debug is set to false', (done) => { - let filePattern = getTestDllString(["testAssembly1.dll"]); - let vstestCmd = ["\\path\\to\\vstest\\directory\\vstest.console.exe", filePattern, "/logger:trx"].join(" "); - - setResponseFile('vstestGoodSysDebugFalse.json', vstestCmd); + let vstestCmd = ["\\path\\to\\vstest\\directory\\vstest.console.exe", '/source/dir/someFile1', "/logger:trx"].join(" "); + setResponseFile('vstestGoodSysDebugFalse.json'); let tr = new trm.TaskRunner('VSTest'); - let assemblyPattern = path.join(__dirname, "data", "testDlls", "*1.dll"); - - tr.setInput('testAssembly', assemblyPattern); + tr.setInput('testAssemblyVer2', '/source/dir/someFile1'); tr.setInput('vstestLocationMethod', 'location'); tr.setInput('vstestLocation', '\\path\\to\\vstest\\directory'); tr.setInput('vsTestVersion', '14.0'); @@ -893,15 +761,11 @@ describe('VsTest Suite', function () { it('Vstest task verify test results are dropped at correct location in case of release', (done) => { - let filePattern = getTestDllString(["testAssembly1.dll"]); - let vstestCmd = [sysVstestLocation, filePattern, "/logger:trx"].join(" "); - - setResponseFile('vstestRM.json', vstestCmd); + let vstestCmd = [sysVstestLocation, '/artifacts/dir/someFile1', "/logger:trx"].join(" "); + setResponseFile('vstestRM.json'); let tr = new trm.TaskRunner('VSTest'); - let assemblyPattern = path.join(__dirname, "data", "testDlls", "*1.dll"); - - tr.setInput('testAssembly', assemblyPattern); + tr.setInput('testAssemblyVer2', '/artifacts/dir/someFile1'); tr.setInput('vstestLocationMethod', 'version'); tr.setInput('vsTestVersion', '14.0'); @@ -917,5 +781,28 @@ describe('VsTest Suite', function () { .fail((err) => { done(err); }); - }) + }); + + it('Vstest task with serach directory input', (done) => { + + let vstestCmd = [sysVstestLocation, '/search/dir/someFile1', "/logger:trx"].join(" "); + setResponseFile('vstestGood.json'); + + let tr = new trm.TaskRunner('VSTest'); + tr.setInput('testAssemblyVer2', '/search/dir/someFile1'); + tr.setInput('vstestLocationMethod', 'version'); + tr.setInput('vsTestVersion', '14.0'); + tr.setInput('searchDirectory', '/search/dir') + tr.run() + .then(() => { + assert(tr.stderr.length == 0, 'should not have written to stderr. error: ' + tr.stderr); + assert(tr.succeeded, 'task should have succeeded'); + assert(tr.ran(vstestCmd), 'should have run vstest'); + assert(tr.stdout.indexOf('/diag') < 0, '/diag option should not be used for vstest.console.exe'); + done(); + }) + .fail((err) => { + done(err); + }); + }); }); \ No newline at end of file diff --git a/Tests/L0/VsTest/data/testDlls/testAssembly1.dll b/Tests/L0/VsTest/data/testDlls/testAssembly1.dll deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/Tests/L0/VsTest/data/testDlls/testAssembly2.dll b/Tests/L0/VsTest/data/testDlls/testAssembly2.dll deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/Tests/L0/VsTest/vstestFails.json b/Tests/L0/VsTest/vstestFails.json index 283f32be1562..6942f31847b9 100644 --- a/Tests/L0/VsTest/vstestFails.json +++ b/Tests/L0/VsTest/vstestFails.json @@ -5,21 +5,20 @@ "VS140COMNTools": "/vs/path", "VSTest_14.0": "/vs/IDE/CommonExtensions/Microsoft/TestWindow" }, - "find": { - "/source/dir": [ - "someDir/someFile2", - "/someDir/someFile1" - ] - }, "match": { - "\\source\\dir\\some\\*pattern": [ - "some/path/one", - "some/path/two" - ], "**\\packages\\**\\*TestAdapter.dll": [] }, + "findMatch": { + "/source/dir/some/*pattern": [ + "/source/dir/someFile2", + "/source/dir/someFile1" + ], + "/source/dir/someFile1": [ + "/source/dir/someFile1" + ] + }, "exec": { - "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe some/path/one some/path/two /logger:trx": { + "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe /source/dir/someFile2 /source/dir/someFile1 /logger:trx": { "code": 1, "stdout": "running vstest", "stderr": "error occured while running vstest" diff --git a/Tests/L0/VsTest/vstestGood.json b/Tests/L0/VsTest/vstestGood.json index 5ccdcc65d949..3d8da46697b5 100644 --- a/Tests/L0/VsTest/vstestGood.json +++ b/Tests/L0/VsTest/vstestGood.json @@ -6,64 +6,66 @@ "VS140COMNTools": "/vs/path", "VS120COMNTools": "/vs/path" }, - "find": { - "/source/dir": [ - "someDir/someFile2", - "/someDir/someFile1" - ] - }, "match": { - "\\source\\dir\\some\\*pattern": [ - "some/path/one", - "some/path/two" + "**\\packages\\**\\*TestAdapter.dll": [] + }, + "findMatch": { + "/source/dir/some/*pattern": [ + "/source/dir/someFile2", + "/source/dir/someFile1" ], - "\\source\\dir\\exclude\\*pattern": [ - "some/path/two", - "some/path/three" + "/source/dir/some/*pattern,!/source/dir/some/*excludePattern": [ + "/source/dir/someFile1" ], "\\source\\dir\\TestResults\\*.trx": [ "a.trx" ], - "**\\packages\\**\\*TestAdapter.dll": [] + "**\\packages\\**\\*TestAdapter.dll": [], + "/source/dir/someFile1": [ + "/source/dir/someFile1" + ], + "/search/dir/someFile1": [ + "/search/dir/someFile1" + ] }, "exec": { - "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe some/path/one some/path/two /logger:trx": { + "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe /source/dir/someFile2 /source/dir/someFile1 /logger:trx": { "code": 0, "stdout": "vstest" }, - "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe some/path/one /logger:trx": { + "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe /source/dir/someFile1 /logger:trx": { "code": 0, "stdout": "vstest" }, - "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe path/to/file /logger:trx": { + "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe /source/dir/someFile1 /TestCaseFilter:testFilter /logger:trx": { "code": 0, "stdout": "vstest" }, - "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe path/to/file /TestCaseFilter:testFilter /logger:trx": { + "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe /source/dir/someFile1 /EnableCodeCoverage /logger:trx": { "code": 0, "stdout": "vstest" }, - "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe path/to/file /EnableCodeCoverage /logger:trx": { + "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe /source/dir/someFile1 consoleOptions /logger:trx": { "code": 0, "stdout": "vstest" }, - "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe path/to/file consoleOptions /logger:trx": { + "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe /source/dir/someFile1 /Settings:settings.runsettings /logger:trx": { "code": 0, "stdout": "vstest" }, - "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe path/to/file /Settings:settings.runsettings /logger:trx": { + "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe /source/dir/someFile1 /logger:trx /TestAdapterPath:path/to/customadapters": { "code": 0, "stdout": "vstest" }, - "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe path/to/file /logger:trx /TestAdapterPath:path/to/customadapters": { + "some\\path\\to\\vstest.console.exe /source/dir/someFile1 /logger:trx": { "code": 0, "stdout": "vstest" }, - "some\\path\\to\\vstest.console.exe path/to/file /logger:trx": { + "\\path\\to\\vstest\\directory\\vstest.console.exe /source/dir/someFile1 /logger:trx": { "code": 0, "stdout": "vstest" }, - "\\path\\to\\vstest\\directory\\vstest.console.exe path/to/file /logger:trx": { + "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe /search/dir/someFile1 /logger:trx": { "code": 0, "stdout": "vstest" } diff --git a/Tests/L0/VsTest/vstestGoodSysDebugFalse.json b/Tests/L0/VsTest/vstestGoodSysDebugFalse.json index 2ae97c481d6d..72ceffc7af74 100644 --- a/Tests/L0/VsTest/vstestGoodSysDebugFalse.json +++ b/Tests/L0/VsTest/vstestGoodSysDebugFalse.json @@ -7,13 +7,10 @@ "VS120COMNTools": "/vs/path", "System.Debug": "false" }, - "find": { - "/source/dir": [ - "someDir/someFile2", - "/someDir/someFile1" - ] - }, "match": { + "**\\packages\\**\\*TestAdapter.dll": [] + }, + "findMatch": { "\\source\\dir\\some\\*pattern": [ "some/path/one", "some/path/two" @@ -25,46 +22,12 @@ "*.trx": [ "a.trx" ], - "**\\packages\\**\\*TestAdapter.dll": [] + "/source/dir/someFile1": [ + "/source/dir/someFile1" + ] }, "exec": { - "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe some/path/one some/path/two /logger:trx": { - "code": 0, - "stdout": "vstest" - }, - "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe some/path/one /logger:trx": { - "code": 0, - "stdout": "vstest" - }, - "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe path/to/file /logger:trx": { - "code": 0, - "stdout": "vstest" - }, - "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe path/to/file /TestCaseFilter:testFilter /logger:trx": { - "code": 0, - "stdout": "vstest" - }, - "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe path/to/file /EnableCodeCoverage /logger:trx": { - "code": 0, - "stdout": "vstest" - }, - "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe path/to/file consoleOptions /logger:trx": { - "code": 0, - "stdout": "vstest" - }, - "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe path/to/file /Settings:settings.runsettings /logger:trx": { - "code": 0, - "stdout": "vstest" - }, - "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe path/to/file /logger:trx /TestAdapterPath:path/to/customadapters": { - "code": 0, - "stdout": "vstest" - }, - "some\\path\\to\\vstest.console.exe path/to/file /logger:trx": { - "code": 0, - "stdout": "vstest" - }, - "\\path\\to\\vstest\\directory\\vstest.console.exe path/to/file /logger:trx": { + "\\path\\to\\vstest\\directory\\vstest.console.exe /source/dir/someFile1 /logger:trx": { "code": 0, "stdout": "vstest" } diff --git a/Tests/L0/VsTest/vstestGoodWithTiaDisabled.json b/Tests/L0/VsTest/vstestGoodWithTiaDisabled.json index f2e9516fa695..bc0d2b669abf 100644 --- a/Tests/L0/VsTest/vstestGoodWithTiaDisabled.json +++ b/Tests/L0/VsTest/vstestGoodWithTiaDisabled.json @@ -3,25 +3,22 @@ "System.DefaultWorkingDirectory": "/source/dir", "build.sourcesdirectory": "/source/dir", "VS140COMNTools": "/vs/path", - "tia.enabled": "false" + "tia.enabled": "false" }, - "find": { - "/source/dir": [ - "someDir/someFile2", - "/someDir/someFile1" - ] - }, - "match": { + "findMatch": { "*.trx": [ "a.trx" + ], + "/source/dir/someFile1": [ + "/source/dir/someFile1" ] }, "exec": { - "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe path/to/file /logger:trx": { + "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe /source/dir/someFile1 /logger:trx": { "code": 0, "stdout": "vstest" }, - "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe path/to/file /Settings:settings.runsettings /logger:trx": { + "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe /source/dir/someFile1 /Settings:settings.runsettings /logger:trx": { "code": 0, "stdout": "vstest" } @@ -34,17 +31,17 @@ }, "exist": { "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\TE.TestModes.dll": true, - "settings.runsettings": true, - "settings.testsettings": true + "settings.runsettings": true, + "settings.testsettings": true }, "stats": { "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\TE.TestModes.dll": { "isFile": true }, - "settings.runsettings": { + "settings.runsettings": { "isFile": true }, - "settings.testsettings": { + "settings.testsettings": { "isFile": true } } diff --git a/Tests/L0/VsTest/vstestGoodWithTiaEnabled.json b/Tests/L0/VsTest/vstestGoodWithTiaEnabled.json index 44e60774b1cf..b8124b922756 100644 --- a/Tests/L0/VsTest/vstestGoodWithTiaEnabled.json +++ b/Tests/L0/VsTest/vstestGoodWithTiaEnabled.json @@ -2,15 +2,9 @@ "getVariable": { "System.DefaultWorkingDirectory": "/source/dir", "VS140COMNTools": "/vs/path", - "tia.enabled": "true" + "tia.enabled": "true" }, - "find": { - "/source/dir": [ - "someDir/someFile2", - "/someDir/someFile1" - ] - }, - "match": { + "findMatch": { "*.trx": [ "a.trx" ] @@ -29,17 +23,17 @@ }, "exist": { "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\TE.TestModes.dll": true, - "settings.runsettings": true, - "settings.testsettings": true + "settings.runsettings": true, + "settings.testsettings": true }, "stats": { "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\TE.TestModes.dll": { "isFile": true }, - "settings.runsettings": { + "settings.runsettings": { "isFile": true }, - "settings.testsettings": { + "settings.testsettings": { "isFile": true } } diff --git a/Tests/L0/VsTest/vstestRM.json b/Tests/L0/VsTest/vstestRM.json index e83bb2bccdc3..93a2b2cfc1dd 100644 --- a/Tests/L0/VsTest/vstestRM.json +++ b/Tests/L0/VsTest/vstestRM.json @@ -1,69 +1,24 @@ { "getVariable": { - "System.DefaultWorkingDirectory": "/source/dir", - "System.ArtifactsDirectory": "/artifacts/dir", + "System.DefaultWorkingDirectory": "\\artifacts\\dir", + "System.ArtifactsDirectory": "\\artifacts\\dir", "VS150COMNTools": "/vs/path", "VS140COMNTools": "/vs/path", "VS120COMNTools": "/vs/path" }, - "find": { - "/source/dir": [ - "someDir/someFile2", - "/someDir/someFile1" - ] - }, "match": { - "\\source\\dir\\some\\*pattern": [ - "some/path/one", - "some/path/two" - ], - "\\source\\dir\\exclude\\*pattern": [ - "some/path/two", - "some/path/three" + "**\\packages\\**\\*TestAdapter.dll": [] + }, + "findMatch": { + "/artifacts/dir/someFile1": [ + "/artifacts/dir/someFile1" ], "\\artifacts\\dir\\TestResults\\*.trx": [ "\\artifacts\\dir\\TestResults\\a.trx" - ], - "**\\packages\\**\\*TestAdapter.dll": [] + ] }, "exec": { - "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe some/path/one some/path/two /logger:trx": { - "code": 0, - "stdout": "vstest" - }, - "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe some/path/one /logger:trx": { - "code": 0, - "stdout": "vstest" - }, - "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe path/to/file /logger:trx": { - "code": 0, - "stdout": "vstest" - }, - "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe path/to/file /TestCaseFilter:testFilter /logger:trx": { - "code": 0, - "stdout": "vstest" - }, - "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe path/to/file /EnableCodeCoverage /logger:trx": { - "code": 0, - "stdout": "vstest" - }, - "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe path/to/file consoleOptions /logger:trx": { - "code": 0, - "stdout": "vstest" - }, - "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe path/to/file /Settings:settings.runsettings /logger:trx": { - "code": 0, - "stdout": "vstest" - }, - "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe path/to/file /logger:trx /TestAdapterPath:path/to/customadapters": { - "code": 0, - "stdout": "vstest" - }, - "some\\path\\to\\vstest.console.exe path/to/file /logger:trx": { - "code": 0, - "stdout": "vstest" - }, - "\\path\\to\\vstest\\directory\\vstest.console.exe path/to/file /logger:trx": { + "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe /artifacts/dir/someFile1 /logger:trx": { "code": 0, "stdout": "vstest" } @@ -96,4 +51,4 @@ "isDirectory": true } } -} +} \ No newline at end of file diff --git a/Tests/L0/VsTest/vstestRunInParallel.json b/Tests/L0/VsTest/vstestRunInParallel.json index fcf5f911f575..8306d1d3ec57 100644 --- a/Tests/L0/VsTest/vstestRunInParallel.json +++ b/Tests/L0/VsTest/vstestRunInParallel.json @@ -4,19 +4,16 @@ "build.sourcesdirectory": "/source/dir", "VS140COMNTools": "/vs/path" }, - "find": { - "/source/dir": [ - "someDir/someFile2", - "/someDir/someFile1" - ] - }, - "match": { + "findMatch": { "\\source\\dir\\TestResults\\*.trx": [ "a.trx" + ], + "/source/dir/someFile1": [ + "/source/dir/someFile1" ] }, "exec": { - "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe path/to/file /logger:trx": { + "\\vs\\IDE\\CommonExtensions\\Microsoft\\TestWindow\\vstest.console.exe /source/dir/someFile1 /logger:trx": { "code": 0, "stdout": "vstest" } diff --git a/Tests/L0/XamarinLicense/_suite.ts b/Tests/L0/XamarinLicense/_suite.ts deleted file mode 100644 index 52872ebe6315..000000000000 --- a/Tests/L0/XamarinLicense/_suite.ts +++ /dev/null @@ -1,209 +0,0 @@ -/// -/// - -import assert = require('assert'); -import trm = require('../../lib/taskRunner'); -import path = require('path'); -import os = require('os'); - -function setResponseFile(name: string) { - process.env['MOCK_RESPONSES'] = path.join(__dirname, name); -} - -describe('XamarinLicense Suite', function() { - this.timeout(20000); - - before((done) => { - // init here - done(); - }); - - after(function() { - - }); - - // Unfortunately, this task is not just a wrapper around an EXE - // For this reason, we can't really mock what it does to handle all the - // interesting test cases. Here we test to make sure the inputs are checked - // and that the we don't fail until the first step of work is attempted - - it('Activate XamarinLicense with all default inputs', (done) => { - setResponseFile('responseEmpty.json'); - - var tr = new trm.TaskRunner('XamarinLicense', true, true); - tr.setInput('action', 'Activate'); - tr.setInput('email', 'me@ms.com'); - tr.setInput('password', 'mypass'); - tr.setInput('product', 'MA'); - tr.setInput('timeout', '30'); - - tr.run() - .then(() => { - assert(tr.invokedToolCount == 0, 'should not have run any tools'); - assert(tr.resultWasSet, 'task should have set a result'); - assert(tr.stderr.length > 0, 'should have written to stderr'); - assert(tr.failed, 'task should have failed'); - if(os.platform() === 'darwin' || os.platform() === 'win32') { - assert(tr.stdout.indexOf('##vso[task.issue type=error;]Failed to login to Xamarin with specified email and password.') >= 0, 'wrong error message'); - } else { - assert(tr.stdout.indexOf('##vso[task.issue type=error;]The xamarin product: ' + 'MA' + ' is not supported on this os: ') >= 0, 'wrong error message'); - } - done(); - }) - .fail((err) => { - done(err); - }); - }) - - it('Deactivate XamarinLicense with all default inputs', (done) => { - setResponseFile('responseEmpty.json'); - - var tr = new trm.TaskRunner('XamarinLicense', true, true); - tr.setInput('action', 'Deactivate'); - tr.setInput('email', 'me@ms.com'); - tr.setInput('password', 'mypass'); - tr.setInput('product', 'MA'); - tr.setInput('timeout', '30'); - - tr.run() - .then(() => { - assert(tr.invokedToolCount == 0, 'should not have run any tools'); - assert(tr.resultWasSet, 'task should have set a result'); - assert(tr.stderr.length > 0, 'should have written to stderr'); - assert(tr.failed, 'task should have failed'); - if(os.platform() === 'darwin' || os.platform() === 'win32') { - assert(tr.stdout.indexOf('##vso[task.issue type=error;]Failed to login to Xamarin with specified email and password.') >= 0, 'wrong error message'); - } else { - assert(tr.stdout.indexOf('##vso[task.issue type=error;]The xamarin product: ' + 'MA' + ' is not supported on this os: ') >= 0, 'wrong error message'); - } - done(); - }) - .fail((err) => { - done(err); - }); - }) - - it('Fails for missing action', (done) => { - setResponseFile('responseEmpty.json'); - - var tr = new trm.TaskRunner('XamarinLicense', true, true); - //tr.setInput('action', ''); - tr.setInput('email', 'me@ms.com'); - tr.setInput('password', 'mypass'); - tr.setInput('product', 'MA'); - tr.setInput('timeout', '30'); - - tr.run() - .then(() => { - assert(tr.invokedToolCount == 0, 'should not have run any tools'); - assert(tr.resultWasSet, 'task should have set a result'); - assert(tr.stderr.length > 0, 'should have written to stderr'); - assert(tr.failed, 'task should have failed'); - assert(tr.stderr.indexOf('Input required: action') >= 0, 'wrong error message: "' + tr.stderr + '"'); - done(); - }) - .fail((err) => { - done(err); - }); - }) - - it('Fails for unknown action', (done) => { - setResponseFile('responseEmpty.json'); - - var tr = new trm.TaskRunner('XamarinLicense', true, true); - tr.setInput('action', 'unknown'); - tr.setInput('email', 'me@ms.com'); - tr.setInput('password', 'mypass'); - tr.setInput('product', 'MA'); - tr.setInput('timeout', '30'); - - tr.run() - .then(() => { - assert(tr.invokedToolCount == 0, 'should not have run any tools'); - assert(tr.resultWasSet, 'task should have set a result'); - assert(tr.stderr.length > 0, 'should have written to stderr'); - assert(tr.failed, 'task should have failed'); - if(os.platform() === 'darwin' || os.platform() === 'win32') { - assert(tr.stdout.indexOf('##vso[task.issue type=error;]Unknown action: unknown') >= 0, 'wrong error message'); - } else { - assert(tr.stdout.indexOf('##vso[task.issue type=error;]The xamarin product: ' + 'MA' + ' is not supported on this os: ') >= 0, 'wrong error message'); - } - done(); - }) - .fail((err) => { - done(err); - }); - }) - - it('Fails for missing email', (done) => { - setResponseFile('responseEmpty.json'); - - var tr = new trm.TaskRunner('XamarinLicense', true, true); - tr.setInput('action', 'Activate'); - //tr.setInput('email', 'me@ms.com'); - tr.setInput('password', 'mypass'); - tr.setInput('product', 'MA'); - tr.setInput('timeout', '30'); - - tr.run() - .then(() => { - assert(tr.invokedToolCount == 0, 'should not have run any tools'); - assert(tr.resultWasSet, 'task should have set a result'); - assert(tr.stderr.length > 0, 'should have written to stderr'); - assert(tr.failed, 'task should have failed'); - assert(tr.stderr.indexOf('Input required: email') >= 0, 'wrong error message: "' + tr.stderr + '"'); - done(); - }) - .fail((err) => { - done(err); - }); - }) - - it('Fails for missing password', (done) => { - setResponseFile('responseEmpty.json'); - - var tr = new trm.TaskRunner('XamarinLicense', true, true); - tr.setInput('action', 'Activate'); - tr.setInput('email', 'me@ms.com'); - //tr.setInput('password', 'mypass'); - tr.setInput('product', 'MA'); - tr.setInput('timeout', '30'); - - tr.run() - .then(() => { - assert(tr.invokedToolCount == 0, 'should not have run any tools'); - assert(tr.resultWasSet, 'task should have set a result'); - assert(tr.stderr.length > 0, 'should have written to stderr'); - assert(tr.failed, 'task should have failed'); - assert(tr.stderr.indexOf('Input required: password') >= 0, 'wrong error message: "' + tr.stderr + '"'); - done(); - }) - .fail((err) => { - done(err); - }); - }) - - it('Fails for missing product', (done) => { - setResponseFile('responseEmpty.json'); - - var tr = new trm.TaskRunner('XamarinLicense', true, true); - tr.setInput('action', 'Activate'); - tr.setInput('email', 'me@ms.com'); - tr.setInput('password', 'mypass'); - //tr.setInput('product', 'MA'); - tr.setInput('timeout', '30'); - - tr.run() - .then(() => { - assert(tr.invokedToolCount == 0, 'should not have run any tools'); - assert(tr.resultWasSet, 'task should have set a result'); - assert(tr.stderr.length > 0, 'should have written to stderr'); - assert(tr.failed, 'task should have failed'); - assert(tr.stdout.indexOf('##vso[task.issue type=error;]No product selected to activate.') >= 0, 'wrong error message'); - done(); - }) - .fail((err) => { - done(err); - }); - }) -}); \ No newline at end of file diff --git a/Tests/L0/XamarinLicense/responseEmpty.json b/Tests/L0/XamarinLicense/responseEmpty.json deleted file mode 100644 index 7a73a41bfdf7..000000000000 --- a/Tests/L0/XamarinLicense/responseEmpty.json +++ /dev/null @@ -1,2 +0,0 @@ -{ -} \ No newline at end of file diff --git a/Tests/lib/vsts-task-lib/task.ts b/Tests/lib/vsts-task-lib/task.ts index 92fabb8d07cc..9e4e5fadba8c 100644 --- a/Tests/lib/vsts-task-lib/task.ts +++ b/Tests/lib/vsts-task-lib/task.ts @@ -14,6 +14,25 @@ export enum TaskResult { Failed = 1 } +export interface MatchOptions { + debug?: boolean; + nobrace?: boolean; + noglobstar?: boolean; + dot?: boolean; + noext?: boolean; + nocase?: boolean; + nonull?: boolean; + matchBase?: boolean; + nocomment?: boolean; + nonegate?: boolean; + flipNegate?: boolean; +} + +export interface FindOptions { + followSpecifiedSymbolicLink: boolean; + followSymbolicLinks: boolean; +} + //----------------------------------------------------- // String convenience //----------------------------------------------------- @@ -295,7 +314,7 @@ export function getEndpointUrl(id: string, optional: boolean): string { return urlval; } -export function getEndpointDataParameter(id: string, key: string, optional: boolean) : string { +export function getEndpointDataParameter(id: string, key: string, optional: boolean): string { var dataParam = getVariable('ENDPOINT_DATA_' + id + '_' + key.toUpperCase()); debug(id + '=' + dataParam); @@ -307,7 +326,7 @@ export function getEndpointDataParameter(id: string, key: string, optional: bool return dataParam; } -export function getEndpointAuthorizationScheme(id: string, optional: boolean) : string { +export function getEndpointAuthorizationScheme(id: string, optional: boolean): string { var authScheme = getVariable('ENDPOINT_AUTH_SCHEME_' + id); debug(id + '=' + authScheme); @@ -319,7 +338,7 @@ export function getEndpointAuthorizationScheme(id: string, optional: boolean) : return authScheme; } -export function getEndpointAuthorizationParameter(id: string, key: string, optional: boolean) : string { +export function getEndpointAuthorizationParameter(id: string, key: string, optional: boolean): string { var authParam = getVariable('ENDPOINT_AUTH_PARAMETER_' + id + '_' + key.toUpperCase()); debug(id + '=' + authParam); @@ -449,12 +468,12 @@ export function exist(path: string): boolean { } export interface FsOptions { - encoding?:string; - mode?:number; - flag?:string; + encoding?: string; + mode?: number; + flag?: string; } -export function writeFile(file: string, data: string|Buffer, options?: string|FsOptions) { +export function writeFile(file: string, data: string | Buffer, options?: string | FsOptions) { //do nothing } @@ -486,7 +505,7 @@ export function debug(message: string): void { command('task.debug', null, message); } -var _argStringToArray = function(argString: string): string[] { +var _argStringToArray = function (argString: string): string[] { var args = argString.match(/([^" ]*("[^"]*")[^" ]*)|[^" ]+/g); for (var i = 0; i < args.length; i++) { @@ -547,7 +566,7 @@ export function which(tool: string, check?: boolean): string { export function ls(options: string, paths: string[]): string[] { var response = mock.getResponse('ls', paths[0]); - if(!response){ + if (!response) { return []; } return response; @@ -655,22 +674,31 @@ export function match(list: string[], pattern: any, options): string[] { patterns = pattern; } else { - patterns = [ pattern ]; + patterns = [pattern]; } let key: string = patterns.join(','); return mock.getResponse('match', key) || []; } +export function findMatch(defaultRoot: string, patterns: string, findOptions?: FindOptions, matchOptions?: MatchOptions): string[]; +export function findMatch(defaultRoot: string, patterns: string[], findOptions?: FindOptions, matchOptions?: MatchOptions): string[] +export function findMatch(defaultRoot: string, patterns: any, findOptions?: FindOptions, matchOptions?: MatchOptions): string[] { + patterns = patterns || []; + patterns = typeof patterns == 'string' ? [patterns] as string[] : patterns; + let key: string = patterns.join(','); + return mock.getResponse('findMatch', key) || []; +} + export function matchFile(list, pattern, options): string[] { return mock.getResponse('match', pattern) || []; } export function filter(pattern, options): any { - var filterList = mock.getResponse('filter', pattern) || []; - return function(pattern, i, arr) { - return filterList.indexOf(pattern) >= 0; - } + var filterList = mock.getResponse('filter', pattern) || []; + return function (pattern, i, arr) { + return filterList.indexOf(pattern) >= 0; + } } //----------------------------------------------------- @@ -742,7 +770,7 @@ export class CodeCoveragePublisher { properties['additionalcodecoveragefiles'] = additionalCodeCoverageFiles; } - command('codecoverage.publish', properties, ""); + command('codecoverage.publish', properties, ""); } } diff --git a/make-options.json b/make-options.json index 7bad817eb385..0d29caf07a0f 100644 --- a/make-options.json +++ b/make-options.json @@ -1,6 +1,5 @@ { "tasks": [ - "AndroidBuild", "AndroidSigning", "ANT", "ArchiveFiles", @@ -10,7 +9,6 @@ "AzureFileCopy", "AzurePowerShell", "AzureRmWebAppDeployment", - "AzureWebPowerShellDeployment", "BatchScript", "Chef", "ChefKnife", @@ -31,7 +29,6 @@ "Gradle", "Grunt", "Gulp", - "IISWebAppDeployment", "IISWebAppDeploymentOnMachineGroup", "JenkinsDownloadArtifacts", "JenkinsQueueJob", @@ -58,7 +55,7 @@ "SonarQubePostTest", "SonarQubePreBuild", "SqlAzureDacpacDeployment", - "SqlServerDacpacDeployment", + "SqlDacpacDeploymentOnMachineGroup", "SSH", "VSBuild", "VsTest", @@ -66,7 +63,6 @@ "XamarinAndroid", "XamarinComponentRestore", "XamariniOS", - "XamarinLicense", "XamarinTestCloud", "Xcode", "XcodePackageiOS"