Merge pull request #14438 from dotnet-maestro-bot/merge/release/3.1-to-master

[automated] Merge branch 'release/3.1' => 'master'
This commit is contained in:
Justin Kotalik 2019-10-02 07:52:21 +09:00 committed by GitHub
commit cd2983bf41
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 597 additions and 117 deletions

View File

@ -55,6 +55,7 @@ parameters:
artifacts: []
buildDirectory: ''
buildScript: ''
installTar: true
installNodeJs: true
installJdk: true
timeoutInMinutes: 180
@ -151,6 +152,9 @@ jobs:
Write-Host "##vso[task.setvariable variable=SeleniumProcessTrackingFolder]$(BuildDirectory)\artifacts\tmp\selenium\"
./eng/scripts/InstallGoogleChrome.ps1
displayName: Install Chrome
- ${{ if and(eq(parameters.installTar, 'true'), eq(parameters.agentOs, 'Windows')) }}:
- powershell: ./eng/scripts/InstallTar.ps1
displayName: Find or install Tar
- ${{ parameters.beforeBuild }}

View File

@ -307,6 +307,8 @@ if (-not $foundJdk -and $RunBuild -and ($All -or $BuildJava) -and -not $NoBuildJ
# Initialize global variables need to be set before the import of Arcade is imported
$restore = $RunRestore
# Though VS Code may indicate $nodeReuse, $warnAsError and $msbuildEngine are unused, tools.ps1 uses them.
# Disable node reuse - Workaround perpetual issues in node reuse and custom task assemblies
$nodeReuse = $false
$env:MSBUILDDISABLENODEREUSE=1
@ -328,10 +330,10 @@ if ($CI) {
}
# tools.ps1 corrupts global state, so reset these values in case they carried over from a previous build
rm variable:global:_BuildTool -ea Ignore
rm variable:global:_DotNetInstallDir -ea Ignore
rm variable:global:_ToolsetBuildProj -ea Ignore
rm variable:global:_MSBuildExe -ea Ignore
Remove-Item variable:global:_BuildTool -ea Ignore
Remove-Item variable:global:_DotNetInstallDir -ea Ignore
Remove-Item variable:global:_ToolsetBuildProj -ea Ignore
Remove-Item variable:global:_MSBuildExe -ea Ignore
# Import Arcade
. "$PSScriptRoot/eng/common/tools.ps1"
@ -391,10 +393,10 @@ finally {
}
# tools.ps1 corrupts global state, so reset these values so they don't carry between invocations of build.ps1
rm variable:global:_BuildTool -ea Ignore
rm variable:global:_DotNetInstallDir -ea Ignore
rm variable:global:_ToolsetBuildProj -ea Ignore
rm variable:global:_MSBuildExe -ea Ignore
Remove-Item variable:global:_BuildTool -ea Ignore
Remove-Item variable:global:_DotNetInstallDir -ea Ignore
Remove-Item variable:global:_ToolsetBuildProj -ea Ignore
Remove-Item variable:global:_MSBuildExe -ea Ignore
if ($DumpProcesses -or $ci) {
Stop-Job -Name DumpProcesses

View File

@ -27,6 +27,7 @@ Building ASP.NET Core on Windows requires:
```ps1
PS> ./eng/scripts/InstallJdk.ps1
```
* Chrome - Selenium-based tests require a version of Chrome to be installed. Download and install it from [https://www.google.com/chrome]
### macOS/Linux

View File

@ -2,7 +2,7 @@
<Project>
<PropertyGroup>
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
<AspNetCoreBaselineVersion>2.2.6</AspNetCoreBaselineVersion>
<AspNetCoreBaselineVersion>2.2.7</AspNetCoreBaselineVersion>
</PropertyGroup>
<!-- Package: dotnet-dev-certs-->
<PropertyGroup Condition=" '$(PackageId)' == 'dotnet-dev-certs' ">
@ -77,12 +77,12 @@
</ItemGroup>
<!-- Package: Microsoft.AspNetCore.AspNetCoreModule-->
<PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.AspNetCoreModule' ">
<BaselinePackageVersion>2.2.6</BaselinePackageVersion>
<BaselinePackageVersion>2.2.7</BaselinePackageVersion>
</PropertyGroup>
<ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.AspNetCoreModule' AND '$(TargetFramework)' == 'netcoreapp2.2' " />
<!-- Package: Microsoft.AspNetCore.AspNetCoreModuleV2-->
<PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.AspNetCoreModuleV2' ">
<BaselinePackageVersion>2.2.6</BaselinePackageVersion>
<BaselinePackageVersion>2.2.7</BaselinePackageVersion>
</PropertyGroup>
<ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.AspNetCoreModuleV2' AND '$(TargetFramework)' == 'netcoreapp2.2' " />
<!-- Package: Microsoft.AspNetCore.Authentication.Abstractions-->
@ -303,10 +303,11 @@
</ItemGroup>
<!-- Package: Microsoft.AspNetCore.DataProtection.AzureStorage-->
<PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.DataProtection.AzureStorage' ">
<BaselinePackageVersion>2.2.0</BaselinePackageVersion>
<BaselinePackageVersion>2.2.7</BaselinePackageVersion>
</PropertyGroup>
<ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.DataProtection.AzureStorage' AND '$(TargetFramework)' == 'netstandard2.0' ">
<BaselinePackageReference Include="Microsoft.AspNetCore.DataProtection" Version="[2.2.0, )" />
<BaselinePackageReference Include="Microsoft.Data.OData" Version="[5.8.4, )" />
<BaselinePackageReference Include="WindowsAzure.Storage" Version="[8.1.4, )" />
</ItemGroup>
<!-- Package: Microsoft.AspNetCore.DataProtection.EntityFrameworkCore-->
@ -434,21 +435,21 @@
</ItemGroup>
<!-- Package: Microsoft.AspNetCore.Hosting-->
<PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Hosting' ">
<BaselinePackageVersion>2.2.0</BaselinePackageVersion>
<BaselinePackageVersion>2.2.7</BaselinePackageVersion>
</PropertyGroup>
<ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.Hosting' AND '$(TargetFramework)' == 'netstandard2.0' ">
<BaselinePackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="[2.2.0, )" />
<BaselinePackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="[2.2.0, )" />
<BaselinePackageReference Include="Microsoft.AspNetCore.Http" Version="[2.2.0, )" />
<BaselinePackageReference Include="Microsoft.AspNetCore.Http.Extensions" Version="[2.2.0, )" />
<BaselinePackageReference Include="Microsoft.Extensions.Configuration" Version="[2.2.0, )" />
<BaselinePackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="[2.2.0, )" />
<BaselinePackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="[2.2.4, )" />
<BaselinePackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="[2.2.0, )" />
<BaselinePackageReference Include="Microsoft.Extensions.DependencyInjection" Version="[2.2.0, )" />
<BaselinePackageReference Include="Microsoft.Extensions.FileProviders.Physical" Version="[2.2.0, )" />
<BaselinePackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="[2.2.0, )" />
<BaselinePackageReference Include="Microsoft.Extensions.Logging" Version="[2.2.0, )" />
<BaselinePackageReference Include="Microsoft.Extensions.Options" Version="[2.2.0, )" />
<BaselinePackageReference Include="System.Diagnostics.DiagnosticSource" Version="[4.5.0, )" />
<BaselinePackageReference Include="System.Diagnostics.DiagnosticSource" Version="[4.5.1, )" />
<BaselinePackageReference Include="System.Reflection.Metadata" Version="[1.6.0, )" />
</ItemGroup>
<!-- Package: Microsoft.AspNetCore.Html.Abstractions-->
@ -1197,12 +1198,12 @@
</ItemGroup>
<!-- Package: Microsoft.AspNetCore.SpaServices-->
<PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.SpaServices' ">
<BaselinePackageVersion>2.2.0</BaselinePackageVersion>
<BaselinePackageVersion>2.2.7</BaselinePackageVersion>
</PropertyGroup>
<ItemGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.SpaServices' AND '$(TargetFramework)' == 'netstandard2.0' ">
<BaselinePackageReference Include="Microsoft.AspNetCore.NodeServices" Version="[2.2.0, )" />
<BaselinePackageReference Include="Microsoft.AspNetCore.Mvc.TagHelpers" Version="[2.2.0, )" />
<BaselinePackageReference Include="Microsoft.AspNetCore.Mvc.ViewFeatures" Version="[2.2.0, )" />
<BaselinePackageReference Include="Microsoft.AspNetCore.NodeServices" Version="[2.2.0, )" />
</ItemGroup>
<!-- Package: Microsoft.AspNetCore.StaticFiles-->
<PropertyGroup Condition=" '$(PackageId)' == 'Microsoft.AspNetCore.StaticFiles' ">

View File

@ -4,7 +4,7 @@ This file contains a list of all the packages and their versions which were rele
build of ASP.NET Core 2.2.x. Update this list when preparing for a new patch.
-->
<Baseline Version="2.2.6">
<Baseline Version="2.2.7">
<Package Id="dotnet-dev-certs" Version="2.2.0" />
<Package Id="dotnet-sql-cache" Version="2.2.0" />
<Package Id="dotnet-user-secrets" Version="2.2.0" />
@ -12,8 +12,8 @@ build of ASP.NET Core 2.2.x. Update this list when preparing for a new patch.
<Package Id="Microsoft.AspNetCore.Antiforgery" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.ApiAuthorization.IdentityServer" Version="2.2.0-preview-35687" />
<Package Id="Microsoft.AspNetCore.ApplicationInsights.HostingStartup" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.AspNetCoreModule" Version="2.2.6" />
<Package Id="Microsoft.AspNetCore.AspNetCoreModuleV2" Version="2.2.6" />
<Package Id="Microsoft.AspNetCore.AspNetCoreModule" Version="2.2.7" />
<Package Id="Microsoft.AspNetCore.AspNetCoreModuleV2" Version="2.2.7" />
<Package Id="Microsoft.AspNetCore.Authentication.Abstractions" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Authentication.AzureAD.UI" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Authentication.AzureADB2C.UI" Version="2.2.0" />
@ -39,7 +39,7 @@ build of ASP.NET Core 2.2.x. Update this list when preparing for a new patch.
<Package Id="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.DataProtection.Abstractions" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.DataProtection.AzureKeyVault" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.DataProtection.AzureStorage" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.DataProtection.AzureStorage" Version="2.2.7" />
<Package Id="Microsoft.AspNetCore.DataProtection.EntityFrameworkCore" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.DataProtection.Extensions" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="2.2.5" />
@ -53,7 +53,7 @@ build of ASP.NET Core 2.2.x. Update this list when preparing for a new patch.
<Package Id="Microsoft.AspNetCore.Hosting.Abstractions" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Hosting.Server.Abstractions" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Hosting.WindowsServices" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Hosting" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Hosting" Version="2.2.7" />
<Package Id="Microsoft.AspNetCore.Html.Abstractions" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.Http.Connections.Client" Version="1.1.0" />
@ -122,7 +122,7 @@ build of ASP.NET Core 2.2.x. Update this list when preparing for a new patch.
<Package Id="Microsoft.AspNetCore.SignalR.StackExchangeRedis" Version="1.1.5" />
<Package Id="Microsoft.AspNetCore.SignalR" Version="1.1.0" />
<Package Id="Microsoft.AspNetCore.SpaServices.Extensions" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.SpaServices" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.SpaServices" Version="2.2.7" />
<Package Id="Microsoft.AspNetCore.StaticFiles" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.TestHost" Version="2.2.0" />
<Package Id="Microsoft.AspNetCore.WebSockets" Version="2.2.1" />

View File

@ -29,10 +29,6 @@ Later on, this will be checked using this condition:
java:signalr;
</PackagesInPatch>
</PropertyGroup>
<PropertyGroup Condition=" '$(VersionPrefix)' == '2.2.3' ">
<PackagesInPatch>
</PackagesInPatch>
</PropertyGroup>
<PropertyGroup Condition=" '$(VersionPrefix)' == '2.2.4' ">
<PackagesInPatch>
@aspnet/signalr;
@ -70,4 +66,8 @@ Later on, this will be checked using this condition:
Microsoft.AspNetCore.SpaServices;
</PackagesInPatch>
</PropertyGroup>
<PropertyGroup Condition=" '$(VersionPrefix)' == '2.2.8' ">
<PackagesInPatch>
</PackagesInPatch>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,74 @@
<#
.SYNOPSIS
Finds or installs the Tar command on this system.
.DESCRIPTION
This script searches for Tar on this system. If not found, downloads and extracts Git to use its tar.exe. Prefers
global installation locations even if Git has been downloaded into this repo.
.PARAMETER GitVersion
The version of the Git to install. If not set, the default value is read from global.json.
.PARAMETER Force
Overwrite the existing installation if one exists in this repo and Tar isn't installed globally.
#>
param(
[string]$GitVersion,
[switch]$Force
)
$ErrorActionPreference = 'Stop'
$ProgressPreference = 'SilentlyContinue' # Workaround PowerShell/PowerShell#2138
Set-StrictMode -Version 1
# Find tar. If not found, install Git to get it.
$repoRoot = (Join-Path $PSScriptRoot "..\.." -Resolve)
$installDir = "$repoRoot\.tools\Git\win-x64"
$tarCommand = "$installDir\usr\bin\tar.exe"
$finalCommand = "$repoRoot\.tools\tar.exe"
Write-Host "Windows version and other information..."
cmd.exe /c ver
systeminfo.exe
Write-Host "Processor Architecture: $env:PROCESSOR_ARCHITECTURE"
Write-Host "Checking $env:SystemRoot\System32\tar.exe"
Get-ChildItem "$env:SystemRoot\System32\ta*.exe"
if (Test-Path "$env:SystemRoot\System32\tar.exe") {
Write-Host "Found $env:SystemRoot\System32\tar.exe"
$tarCommand = "$env:SystemRoot\System32\tar.exe"
}
elseif (Test-Path "$env:ProgramFiles\Git\usr\bin\tar.exe") {
$tarCommand = "$env:ProgramFiles\Git\usr\bin\tar.exe"
}
elseif (Test-Path "${env:ProgramFiles(x86)}\Git\usr\bin\tar.exe") {
$tarCommand = "${env:ProgramFiles(x86)}\Git\usr\bin\tar.exe"
}
elseif (Test-Path "$env:AGENT_HOMEDIRECTORY\externals\git\usr\bin\tar.exe") {
$tarCommand = "$env:AGENT_HOMEDIRECTORY\externals\git\usr\bin\tar.exe"
}
elseif ((Test-Path $tarCommand) -And (-Not $Force)) {
Write-Verbose "Repo-local Git installation and $tarCommand already exist, skipping Git install."
}
else {
if (-not $GitVersion) {
$globalJson = Get-Content "$repoRoot\global.json" | ConvertFrom-Json
$GitVersion = $globalJson.tools.Git
}
$Uri = "https://netcorenativeassets.blob.core.windows.net/resource-packages/external/windows/git/Git-${GitVersion}-64-bit.zip"
Import-Module -Name (Join-Path $PSScriptRoot "..\common\native\CommonLibrary.psm1" -Resolve)
$InstallStatus = CommonLibrary\DownloadAndExtract -Uri $Uri -InstallDirectory "$installDir\" -Force:$Force -Verbose
if ($InstallStatus -Eq $False) {
Write-Error "Installation failed"
exit 1
}
}
New-Item "$repoRoot\.tools\" -ErrorAction SilentlyContinue -ItemType Directory
Copy-Item "$tarCommand" "$finalCommand" -Verbose
Write-Host "Tar now available at '$finalCommand'"
if ($tarCommand -like '*\Git\*') {
$null >.\.tools\tar.fromGit
}

View File

@ -61,15 +61,21 @@
</ItemGroup>
<PropertyGroup>
<_GenApiFile>$([MSBuild]::NormalizePath('$(ArtifactsDir)', 'log', 'GenAPI.rsp'))</_GenApiFile>
<_GenAPICommand Condition="'$(MSBuildRuntimeType)' == 'core'">"$(DotNetTool)" --roll-forward-on-no-candidate-fx 2 "$(_GenAPIPath)"</_GenAPICommand>
<_GenAPICmd>$(_GenAPICommand)</_GenAPICmd>
<_GenAPICmd>$(_GenAPICmd) "$(TargetPath)"</_GenAPICmd>
<_GenAPICmd>$(_GenAPICmd) --lib-path "@(_ReferencePathDirectories)"</_GenAPICmd>
<_GenAPICmd>$(_GenAPICmd) --out "$(_RefSourceFileOutputPath)"</_GenAPICmd>
<_GenAPICmd>$(_GenAPICmd) --header-file "$(RepoRoot)/eng/LicenseHeader.txt"</_GenAPICmd>
<_GenAPICmd>$(_GenAPICmd) --exclude-api-list "$(RepoRoot)/eng/GenAPI.exclusions.txt"</_GenAPICmd>
<_GenAPICmd>$(_GenAPICommand) @"$(_GenApiFile)"</_GenAPICmd>
<_GenApiArguments><![CDATA[
"$(TargetPath)"
--lib-path "@(_ReferencePathDirectories, '%3B')"
--out "$(_RefSourceFileOutputPath)"
--header-file "$(RepoRoot)/eng/LicenseHeader.txt"
--exclude-api-list "$(RepoRoot)/eng/GenAPI.exclusions.txt"
]]>
</_GenApiArguments>
</PropertyGroup>
<WriteLinesToFile File="$(_GenApiFile)" Lines="$(_GenApiArguments)" Overwrite="true" />
<MakeDir Directories="$(_RefSourceOutputPath)" />
<Message Importance="High" Text="Generating $(_RefSourceFileOutputPath)" />
<Exec Command="$(_GenAPICmd)" />
@ -96,4 +102,4 @@
</ItemGroup>
</Target>
</Project>
</Project>

View File

@ -12,6 +12,7 @@
"$(MicrosoftNETCoreAppRuntimeVersion)"
]
},
"Git": "2.22.0",
"jdk": "11.0.3",
"vs": {
"version": "16.0",

View File

@ -88,7 +88,7 @@ namespace Ignitor
public Task<CapturedRenderBatch> PrepareForNextBatch(TimeSpan? timeout)
{
if (NextBatchReceived?.Completion != null)
if (NextBatchReceived != null && !NextBatchReceived.Disposed)
{
throw new InvalidOperationException("Invalid state previous task not completed");
}
@ -100,7 +100,7 @@ namespace Ignitor
public Task<CapturedJSInteropCall> PrepareForNextJSInterop(TimeSpan? timeout)
{
if (NextJSInteropReceived?.Completion != null)
if (NextJSInteropReceived != null && !NextJSInteropReceived.Disposed)
{
throw new InvalidOperationException("Invalid state previous task not completed");
}
@ -112,7 +112,7 @@ namespace Ignitor
public Task<string> PrepareForNextDotNetInterop(TimeSpan? timeout)
{
if (NextDotNetInteropCompletionReceived?.Completion != null)
if (NextDotNetInteropCompletionReceived != null && !NextDotNetInteropCompletionReceived.Disposed)
{
throw new InvalidOperationException("Invalid state previous task not completed");
}
@ -124,7 +124,7 @@ namespace Ignitor
public Task<string> PrepareForNextCircuitError(TimeSpan? timeout)
{
if (NextErrorReceived?.Completion != null)
if (NextErrorReceived != null && !NextErrorReceived.Disposed)
{
throw new InvalidOperationException("Invalid state previous task not completed");
}
@ -136,7 +136,7 @@ namespace Ignitor
public Task<Exception> PrepareForNextDisconnect(TimeSpan? timeout)
{
if (NextDisconnect?.Completion != null)
if (NextDisconnect != null && !NextDisconnect.Disposed)
{
throw new InvalidOperationException("Invalid state previous task not completed");
}
@ -499,56 +499,6 @@ namespace Ignitor
return element;
}
private class CancellableOperation<TResult>
{
public CancellableOperation(TimeSpan? timeout)
{
Timeout = timeout;
Initialize();
}
public TimeSpan? Timeout { get; }
public TaskCompletionSource<TResult> Completion { get; set; }
public CancellationTokenSource Cancellation { get; set; }
public CancellationTokenRegistration CancellationRegistration { get; set; }
private void Initialize()
{
Completion = new TaskCompletionSource<TResult>(TaskContinuationOptions.RunContinuationsAsynchronously);
Completion.Task.ContinueWith(
(task, state) =>
{
var operation = (CancellableOperation<TResult>)state;
operation.Dispose();
},
this,
TaskContinuationOptions.ExecuteSynchronously); // We need to execute synchronously to clean-up before anything else continues
if (Timeout != null && Timeout != System.Threading.Timeout.InfiniteTimeSpan && Timeout != TimeSpan.MaxValue)
{
Cancellation = new CancellationTokenSource(Timeout.Value);
CancellationRegistration = Cancellation.Token.Register(
(self) =>
{
var operation = (CancellableOperation<TResult>)self;
operation.Completion.TrySetCanceled(operation.Cancellation.Token);
operation.Cancellation.Dispose();
operation.CancellationRegistration.Dispose();
},
this);
}
}
private void Dispose()
{
Completion = null;
Cancellation.Dispose();
CancellationRegistration.Dispose();
}
}
private string[] ReadMarkers(string content)
{
content = content.Replace("\r\n", "").Replace("\n", "");

View File

@ -0,0 +1,64 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Ignitor
{
internal class CancellableOperation<TResult>
{
public CancellableOperation(TimeSpan? timeout)
{
Timeout = timeout;
Completion = new TaskCompletionSource<TResult>(TaskContinuationOptions.RunContinuationsAsynchronously);
Completion.Task.ContinueWith(
(task, state) =>
{
var operation = (CancellableOperation<TResult>)state;
operation.Dispose();
},
this,
TaskContinuationOptions.ExecuteSynchronously); // We need to execute synchronously to clean-up before anything else continues
if (Timeout != null && Timeout != System.Threading.Timeout.InfiniteTimeSpan && Timeout != TimeSpan.MaxValue)
{
Cancellation = new CancellationTokenSource(Timeout.Value);
CancellationRegistration = Cancellation.Token.Register(
(self) =>
{
var operation = (CancellableOperation<TResult>)self;
operation.Completion.TrySetCanceled(operation.Cancellation.Token);
operation.Cancellation.Dispose();
operation.CancellationRegistration.Dispose();
},
this);
}
}
public TimeSpan? Timeout { get; }
public TaskCompletionSource<TResult> Completion { get; }
public CancellationTokenSource Cancellation { get; }
public CancellationTokenRegistration CancellationRegistration { get; }
public bool Disposed { get; private set; }
private void Dispose()
{
if (Disposed)
{
return;
}
Disposed = true;
Completion.TrySetCanceled(Cancellation.Token);
Cancellation.Dispose();
CancellationRegistration.Dispose();
}
}
}

View File

@ -171,14 +171,26 @@ This package is an internal implementation of the .NET Core SDK and is not meant
Inputs="@(RefPackContent)"
Outputs="$(ZipArchiveOutputPath);$(TarArchiveOutputPath)"
Condition="'$(IsPackable)' == 'true'">
<PropertyGroup>
<_TarCommand>tar</_TarCommand>
<_TarCommand Condition="Exists('$(RepoRoot).tools\tar.exe')">$(RepoRoot).tools\tar.exe</_TarCommand>
<!-- For the tar packed with git, transform e.g. "C:\root\AspNetCore\File.tar.gz" to "/C/root/AspNetCore/File.tar.gz". -->
<_TarArchiveOutputPath>$(TarArchiveOutputPath)</_TarArchiveOutputPath>
<_TarArchiveOutputPath
Condition="Exists('$(repoRoot)\.tools\tar.fromGit')">/$(TarArchiveOutputPath.Replace('\','/').Replace(':',''))</_TarArchiveOutputPath>
</PropertyGroup>
<ZipDirectory
SourceDirectory="$(TargetingPackLayoutRoot)"
DestinationFile="$(ZipArchiveOutputPath)"
Overwrite="true" />
<!-- Requires Windows 10 version 1803 or newer -->
<Exec
Command="tar -czf $(TarArchiveOutputPath) ."
WorkingDirectory="$(TargetingPackLayoutRoot)" />
<Message Importance="High" Text="Executing: $(_TarCommand) -czf $(_TarArchiveOutputPath) ." />
<Exec Command="$(_TarCommand) -czf $(_TarArchiveOutputPath) ."
WorkingDirectory="$(TargetingPackLayoutRoot)" />
<Message Importance="High" Text="$(MSBuildProjectName) -> $(TarArchiveOutputPath)" />
</Target>

View File

@ -108,7 +108,7 @@ namespace Microsoft.AspNetCore.E2ETesting
var instance = await SeleniumStandaloneServer.GetInstanceAsync(output);
var attempt = 0;
var maxAttempts = 3;
const int maxAttempts = 3;
do
{
try
@ -132,18 +132,16 @@ namespace Microsoft.AspNetCore.E2ETesting
return (driver, logs);
}
catch
catch (Exception ex)
{
if (attempt >= maxAttempts)
{
throw new InvalidOperationException("Couldn't create a Selenium remote driver client. The server is irresponsive");
}
output.WriteLine($"Error initializing RemoteWebDriver: {ex.Message}");
}
attempt++;
} while (attempt < maxAttempts);
// We will never get here. Keeping the compiler happy.
throw new InvalidOperationException("Couldn't create a Selenium remote driver client. The server is unresponsive");
throw new InvalidOperationException("Couldn't create a Selenium remote driver client. The server is irresponsive");
}
}
}

View File

@ -13,7 +13,7 @@ namespace Microsoft.Extensions.ApiDescription.Client
public void Execute_ReturnsExpectedItem()
{
// Arrange
string input = "Identity=../files/azureMonitor.json|ClassName=azureMonitorClient|" +
var input = "Identity=../files/azureMonitor.json|ClassName=azureMonitorClient|" +
"CodeGenerator=NSwagCSharp|Namespace=ConsoleClient|Options=|OutputPath=" +
"C:\\dd\\dnx\\AspNetCore\\artifacts\\obj\\ConsoleClient\\azureMonitorClient.cs|" +
"OriginalItemSpec=../files/azureMonitor.json|FirstForGenerator=true";
@ -22,8 +22,8 @@ namespace Microsoft.Extensions.ApiDescription.Client
Input = input,
};
string expectedIdentity = "../files/azureMonitor.json";
IDictionary<string, string> expectedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal)
var expectedIdentity = "../files/azureMonitor.json";
var expectedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal)
{
{ "ClassName", "azureMonitorClient" },
{ "CodeGenerator", "NSwagCSharp" },

View File

@ -27,7 +27,7 @@ namespace Microsoft.Extensions.ApiDescription.Client
OutputDirectory = "obj",
};
IDictionary<string, string> expectedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal)
var expectedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal)
{
{ "ClassName", "NSwagClient" },
{ "CodeGenerator", "NSwagCSharp" },
@ -85,7 +85,7 @@ namespace Microsoft.Extensions.ApiDescription.Client
OutputDirectory = "obj",
};
IDictionary<string, string> expectedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal)
var expectedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal)
{
{ "ClassName", className },
{ "CodeGenerator", "NSwagCSharp" },
@ -143,7 +143,7 @@ namespace Microsoft.Extensions.ApiDescription.Client
OutputDirectory = "obj",
};
IDictionary<string, string> expectedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal)
var expectedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal)
{
{ "ClassName", "NSwagClient" },
{ "CodeGenerator", "NSwagCSharp" },
@ -201,7 +201,7 @@ namespace Microsoft.Extensions.ApiDescription.Client
OutputDirectory = "bin",
};
IDictionary<string, string> expectedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal)
var expectedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal)
{
{ "ClassName", className },
{ "CodeGenerator", "NSwagCSharp" },
@ -351,7 +351,7 @@ namespace Microsoft.Extensions.ApiDescription.Client
OutputDirectory = "bin",
};
IDictionary<string, string> expectedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal)
var expectedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal)
{
{ "ClassName", className },
{ "CodeGenerator", "NSwagCSharp" },
@ -414,7 +414,7 @@ namespace Microsoft.Extensions.ApiDescription.Client
OutputDirectory = "bin",
};
IDictionary<string, string> expectedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal)
var expectedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal)
{
{ "ClassName", className },
{ "CodeGenerator", "NSwagCSharp" },
@ -481,7 +481,7 @@ namespace Microsoft.Extensions.ApiDescription.Client
OutputDirectory = "obj",
};
IDictionary<string, string> expectedMetadata1 = new SortedDictionary<string, string>(StringComparer.Ordinal)
var expectedMetadata1 = new SortedDictionary<string, string>(StringComparer.Ordinal)
{
{ "ClassName", className12 },
{ "CodeGenerator", codeGenerator13 },
@ -496,7 +496,7 @@ namespace Microsoft.Extensions.ApiDescription.Client
$"OutputPath={outputPath1}|ClassName={className12}|Namespace={@namespace}"
},
};
IDictionary<string, string> expectedMetadata2 = new SortedDictionary<string, string>(StringComparer.Ordinal)
var expectedMetadata2 = new SortedDictionary<string, string>(StringComparer.Ordinal)
{
{ "ClassName", className12 },
{ "CodeGenerator", codeGenerator2 },
@ -511,7 +511,7 @@ namespace Microsoft.Extensions.ApiDescription.Client
$"OutputPath={outputPath2}|ClassName={className12}|Namespace={@namespace}"
},
};
IDictionary<string, string> expectedMetadata3 = new SortedDictionary<string, string>(StringComparer.Ordinal)
var expectedMetadata3 = new SortedDictionary<string, string>(StringComparer.Ordinal)
{
{ "ClassName", className3 },
{ "CodeGenerator", codeGenerator13 },

View File

@ -0,0 +1,314 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Moq;
using Xunit;
namespace Microsoft.Extensions.ApiDescription.Client
{
// ItemSpec values always have '\\' converted to '/' on input when running on non-Windows. It is not possible to
// retrieve the original (unconverted) item spec value. In other respects, item spec values are treated identically
// to custom metadata values.
//
// ITaskItem members aka the implicitly-implemented methods and properties in TaskItem expect _escaped_ values on
// input and return _literal_ values. This includes TaskItem constructors and CloneCustomMetadata() (which returns
// a new dictionary containing literal values). TaskItem stores all values in their escaped form.
//
// Added ITaskItem2 members e.g. CloneCustomMetadataEscaped(), GetMetadataValueEscaped(...) and
// EvaluatedIncludeEscaped return escaped values. Of all TaskItem methods, only SetMetadataValueLiteral(...)
// accepts a literal input value.
//
// Metadata names are never escaped.
//
// MetadataSerializer expects literal values on input.
public class MetadataSerializerTest
{
// Maps literal to escaped values.
public static TheoryData<string, string> EscapedValuesMapping { get; } = new TheoryData<string, string>
{
{ "No escaping necessary for =.", "No escaping necessary for =." },
{ "Value needs escaping? (yes)", "Value needs escaping%3f %28yes%29" },
{ "$ comes earlier; @ comes later.", "%24 comes earlier%3b %40 comes later." },
{
"A '%' *character* needs escaping %-escaping.",
"A %27%25%27 %2acharacter%2a needs escaping %25-escaping."
},
};
public static TheoryData<string> EscapedValues
{
get
{
var result = new TheoryData<string>();
foreach (var entry in EscapedValuesMapping)
{
result.Add((string)entry[1]);
}
return result;
}
}
public static TheoryData<string> LiteralValues
{
get
{
var result = new TheoryData<string>();
foreach (var entry in EscapedValuesMapping)
{
result.Add((string)entry[0]);
}
return result;
}
}
[Theory]
[MemberData(nameof(LiteralValues))]
public void SetMetadata_UpdatesTaskAsExpected(string value)
{
// Arrange
var item = new TaskItem("My Identity");
var key = "My key";
// Act
MetadataSerializer.SetMetadata(item, key, value);
// Assert
Assert.Equal(value, item.GetMetadata(key));
}
[Theory]
[MemberData(nameof(EscapedValuesMapping))]
public void SetMetadata_UpdatesTaskAsExpected_WithLegacyItem(string value, string escapedValue)
{
// Arrange
var item = new Mock<ITaskItem>(MockBehavior.Strict);
var key = "My key";
item.Setup(i => i.SetMetadata(key, escapedValue)).Verifiable();
// Act
MetadataSerializer.SetMetadata(item.Object, key, value);
// Assert
item.Verify(i => i.SetMetadata(key, escapedValue), Times.Once);
}
[Fact]
public void DeserializeMetadata_ReturnsExpectedTask()
{
// Arrange
var identity = "../files/azureMonitor.json";
var input = $"Identity={identity}|ClassName=azureMonitorClient|" +
"CodeGenerator=NSwagCSharp|FirstForGenerator=true|Namespace=ConsoleClient|" +
"Options=|OriginalItemSpec=../files/azureMonitor.json|" +
"OutputPath=C:\\dd\\dnx\\AspNetCore\\artifacts\\obj\\ConsoleClient\\azureMonitorClient.cs";
var expectedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal)
{
{ "ClassName", "azureMonitorClient" },
{ "CodeGenerator", "NSwagCSharp" },
{ "FirstForGenerator", "true" },
{ "Namespace", "ConsoleClient" },
{ "Options", "" },
{ "OriginalItemSpec", identity },
{ "OutputPath", "C:\\dd\\dnx\\AspNetCore\\artifacts\\obj\\ConsoleClient\\azureMonitorClient.cs" },
};
// Act
var item = MetadataSerializer.DeserializeMetadata(input);
// Assert
Assert.Equal(identity, item.ItemSpec);
var metadata = Assert.IsAssignableFrom<IDictionary<string, string>>(item.CloneCustomMetadata());
// The dictionary CloneCustomMetadata returns doesn't provide a useful KeyValuePair enumerator.
var orderedMetadata = new SortedDictionary<string, string>(StringComparer.Ordinal);
foreach (var key in metadata.Keys)
{
orderedMetadata.Add(key, metadata[key]);
}
Assert.Equal(expectedMetadata, orderedMetadata);
}
[Theory]
[MemberData(nameof(EscapedValuesMapping))]
public void DeserializeMetadata_ReturnsExpectedTask_WhenEscaping(string value, string escapedValue)
{
// Arrange
var identity = "../files/azureMonitor.json";
var input = $"Identity={identity}|Value={escapedValue}";
// Act
var item = MetadataSerializer.DeserializeMetadata(input);
// Assert
Assert.Equal(identity, item.ItemSpec);
Assert.Equal(value, item.GetMetadata("Value"));
}
[Theory]
[MemberData(nameof(EscapedValuesMapping))]
public void DeserializeMetadata_ReturnsExpectedTask_WhenEscapingIdentity(string value, string escapedValue)
{
// Arrange
var input = $"Identity={escapedValue}|Value=a value";
// Act
var item = MetadataSerializer.DeserializeMetadata(input);
// Assert
Assert.Equal(value, item.ItemSpec);
Assert.Equal("a value", item.GetMetadata("Value"));
}
[Fact]
public void SerializeMetadata_ReturnsExpectedString()
{
// Arrange
var identity = "../files/azureMonitor.json";
var metadata = new SortedDictionary<string, string>(StringComparer.Ordinal)
{
{ "ClassName", "azureMonitorClient" },
{ "CodeGenerator", "NSwagCSharp" },
{ "FirstForGenerator", "true" },
{ "Namespace", "ConsoleClient" },
{ "Options", "" },
{ "OriginalItemSpec", identity },
{ "OutputPath", "C:\\dd\\dnx\\AspNetCore\\artifacts\\obj\\ConsoleClient\\azureMonitorClient.cs" },
};
var input = new TaskItem(identity, metadata);
var expectedResult = $"Identity={identity}|ClassName=azureMonitorClient|" +
"CodeGenerator=NSwagCSharp|FirstForGenerator=true|Namespace=ConsoleClient|" +
"Options=|OriginalItemSpec=../files/azureMonitor.json|" +
"OutputPath=C:\\dd\\dnx\\AspNetCore\\artifacts\\obj\\ConsoleClient\\azureMonitorClient.cs";
// Act
var result = MetadataSerializer.SerializeMetadata(input);
// Assert
Assert.Equal(expectedResult, result);
}
[Theory]
[MemberData(nameof(EscapedValues))]
public void SerializeMetadata_ReturnsExpectedString_WhenEscaping(string escapedValue)
{
// Arrange
var identity = "../files/azureMonitor.json";
var expectedResult = $"Identity={identity}|Value={escapedValue}";
var metadata = new SortedDictionary<string, string>(StringComparer.Ordinal) { { "Value", escapedValue } };
var input = new TaskItem(identity, metadata);
// Act
var result = MetadataSerializer.SerializeMetadata(input);
// Assert
Assert.Equal(expectedResult, result);
}
[Theory]
[MemberData(nameof(EscapedValues))]
public void SerializeMetadata_ReturnsExpectedString_WhenEscapingIdentity(string escapedValue)
{
// Arrange
var metadata = new SortedDictionary<string, string>(StringComparer.Ordinal) { { "Value", "a value" } };
var expectedResult = $"Identity={escapedValue}|Value=a value";
var input = new TaskItem(escapedValue, metadata);
// Act
var result = MetadataSerializer.SerializeMetadata(input);
// Assert
Assert.Equal(expectedResult, result);
}
[Fact]
public void SerializeMetadata_ReturnsExpectedString_WithLegacyItem()
{
// Arrange
var identity = "../files/azureMonitor.json";
var metadata = new SortedDictionary<string, string>(StringComparer.Ordinal)
{
{ "ClassName", "azureMonitorClient" },
{ "CodeGenerator", "NSwagCSharp" },
{ "FirstForGenerator", "true" },
{ "Namespace", "ConsoleClient" },
{ "Options", "" },
{ "OriginalItemSpec", identity },
{ "OutputPath", "C:\\dd\\dnx\\AspNetCore\\artifacts\\obj\\ConsoleClient\\azureMonitorClient.cs" },
};
var input = new Mock<ITaskItem>(MockBehavior.Strict);
input.SetupGet(i => i.ItemSpec).Returns(identity).Verifiable();
input.Setup(i => i.CloneCustomMetadata()).Returns(metadata).Verifiable();
var expectedResult = $"Identity={identity}|ClassName=azureMonitorClient|" +
"CodeGenerator=NSwagCSharp|FirstForGenerator=true|Namespace=ConsoleClient|" +
"Options=|OriginalItemSpec=../files/azureMonitor.json|" +
"OutputPath=C:\\dd\\dnx\\AspNetCore\\artifacts\\obj\\ConsoleClient\\azureMonitorClient.cs";
// Act
var result = MetadataSerializer.SerializeMetadata(input.Object);
// Assert
Assert.Equal(expectedResult, result);
input.VerifyGet(i => i.ItemSpec, Times.Once);
input.Verify(i => i.CloneCustomMetadata(), Times.Once);
}
[Theory]
[MemberData(nameof(EscapedValuesMapping))]
public void SerializeMetadata_ReturnsExpectedString_WithLegacyItem_WhenEscaping(
string value,
string escapedValue)
{
// Arrange
var identity = "../files/azureMonitor.json";
var metadata = new SortedDictionary<string, string>(StringComparer.Ordinal) { { "Value", value } };
var input = new Mock<ITaskItem>(MockBehavior.Strict);
input.SetupGet(i => i.ItemSpec).Returns(identity).Verifiable();
input.Setup(i => i.CloneCustomMetadata()).Returns(metadata).Verifiable();
var expectedResult = $"Identity={identity}|Value={escapedValue}";
// Act
var result = MetadataSerializer.SerializeMetadata(input.Object);
// Assert
Assert.Equal(expectedResult, result);
input.VerifyGet(i => i.ItemSpec, Times.Once);
input.Verify(i => i.CloneCustomMetadata(), Times.Once);
}
[Theory]
[MemberData(nameof(EscapedValuesMapping))]
public void SerializeMetadata_ReturnsExpectedString_WithLegacyItem_WhenEscapingIdentity(
string value,
string escapedValue)
{
// Arrange
var metadata = new SortedDictionary<string, string>(StringComparer.Ordinal) { { "Value", "a value" } };
var input = new Mock<ITaskItem>(MockBehavior.Strict);
input.SetupGet(i => i.ItemSpec).Returns(value).Verifiable();
input.Setup(i => i.CloneCustomMetadata()).Returns(metadata).Verifiable();
var expectedResult = $"Identity={escapedValue}|Value=a value";
// Act
var result = MetadataSerializer.SerializeMetadata(input.Object);
// Assert
Assert.Equal(expectedResult, result);
input.VerifyGet(i => i.ItemSpec, Times.Once);
input.Verify(i => i.CloneCustomMetadata(), Times.Once);
}
}
}

View File

@ -6,9 +6,12 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Reflection;
using System.Security.Cryptography;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Build.Evaluation;
using Microsoft.DotNet.Openapi.Tools;
@ -240,13 +243,13 @@ namespace Microsoft.DotNet.OpenApi.Commands
internal async Task DownloadToFileAsync(string url, string destinationPath, bool overwrite)
{
using var response = await _httpClient.GetResponseAsync(url);
using var response = await RetryRequest(() => _httpClient.GetResponseAsync(url));
await WriteToFileAsync(await response.Stream, destinationPath, overwrite);
}
internal async Task<string> DownloadGivenOption(string url, CommandOption fileOption)
{
using var response = await _httpClient.GetResponseAsync(url);
using var response = await RetryRequest(() => _httpClient.GetResponseAsync(url));
if (response.IsSuccessCode())
{
@ -272,6 +275,56 @@ namespace Microsoft.DotNet.OpenApi.Commands
}
}
/// <summary>
/// Retries every 1 sec for 60 times by default.
/// </summary>
/// <param name="retryBlock"></param>
/// <param name="logger"></param>
/// <param name="cancellationToken"></param>
/// <param name="retryCount"></param>
private static async Task<IHttpResponseMessageWrapper> RetryRequest(
Func<Task<IHttpResponseMessageWrapper>> retryBlock,
CancellationToken cancellationToken = default,
int retryCount = 60)
{
for (var retry = 0; retry < retryCount; retry++)
{
if (cancellationToken.IsCancellationRequested)
{
throw new OperationCanceledException("Failed to connect, retry canceled.", cancellationToken);
}
try
{
var response = await retryBlock().ConfigureAwait(false);
if (response.StatusCode == HttpStatusCode.ServiceUnavailable)
{
// Automatically retry on 503. May be application is still booting.
continue;
}
return response; // Went through successfully
}
catch (Exception exception)
{
if (retry == retryCount - 1)
{
throw;
}
else
{
if (exception is HttpRequestException || exception is WebException)
{
await Task.Delay(1 * 1000); //Wait for a while before retry.
}
}
}
}
throw new OperationCanceledException("Failed to connect, retry limit exceeded.");
}
private string GetUniqueFileName(string directory, string fileName, string extension)
{
var uniqueName = fileName;

View File

@ -440,8 +440,8 @@ namespace Microsoft.DotNet.OpenApi.Add.Tests
var url = BrokenUrl;
var run = app.Execute(new[] { "add", "url", url });
Assert.Equal(_error.ToString(), $"The given url returned 'NotFound', " +
"indicating failure. The url might be wrong, or there might be a networking issue."+Environment.NewLine);
Assert.Equal($"The given url returned 'NotFound', " +
"indicating failure. The url might be wrong, or there might be a networking issue."+Environment.NewLine, _error.ToString());
Assert.Equal(1, run);
var expectedJsonName = "dingos.json";