From 16f577b074082b41222a4992634af7762e7bf410 Mon Sep 17 00:00:00 2001
From: "dotnet-maestro[bot]"
<42748379+dotnet-maestro[bot]@users.noreply.github.com>
Date: Thu, 15 Feb 2024 17:44:00 +0000
Subject: [PATCH 01/22] Update dependencies from
https://github.com/dotnet/arcade build 20240214.4 (#33107)
[release/7.0] Update dependencies from dotnet/arcade
---
eng/Version.Details.xml | 12 ++++++------
eng/Versions.props | 2 +-
eng/common/post-build/publish-using-darc.ps1 | 4 ++--
eng/common/templates/job/publish-build-assets.yml | 8 ++++----
eng/common/templates/jobs/jobs.yml | 4 ++--
eng/common/templates/post-build/post-build.yml | 12 ++++++------
global.json | 4 ++--
7 files changed, 23 insertions(+), 23 deletions(-)
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index 23b2af1cbea..56918c57c9f 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -39,17 +39,17 @@
-
+
https://github.com/dotnet/arcade
- 5fd1dbf1679abc625e9e74614d9d7a28d151d675
+ c9bbc4b7606b46f6121a2758d2555dfc6322ed88
-
+
https://github.com/dotnet/arcade
- 5fd1dbf1679abc625e9e74614d9d7a28d151d675
+ c9bbc4b7606b46f6121a2758d2555dfc6322ed88
-
+
https://github.com/dotnet/arcade
- 5fd1dbf1679abc625e9e74614d9d7a28d151d675
+ c9bbc4b7606b46f6121a2758d2555dfc6322ed88
diff --git a/eng/Versions.props b/eng/Versions.props
index 4364bfad678..3ac3bf85df8 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -25,7 +25,7 @@
7.0.0
- 7.0.0-beta.24114.2
+ 7.0.0-beta.24114.4
diff --git a/eng/common/post-build/publish-using-darc.ps1 b/eng/common/post-build/publish-using-darc.ps1
index 5a3a32ea8d7..1e779fec4dd 100644
--- a/eng/common/post-build/publish-using-darc.ps1
+++ b/eng/common/post-build/publish-using-darc.ps1
@@ -12,7 +12,7 @@ param(
try {
. $PSScriptRoot\post-build-utils.ps1
- $darc = Get-Darc
+ $darc = Get-Darc
$optionalParams = [System.Collections.ArrayList]::new()
@@ -46,7 +46,7 @@ try {
}
Write-Host 'done.'
-}
+}
catch {
Write-Host $_
Write-PipelineTelemetryError -Category 'PromoteBuild' -Message "There was an error while trying to publish build '$BuildId' to default channels."
diff --git a/eng/common/templates/job/publish-build-assets.yml b/eng/common/templates/job/publish-build-assets.yml
index 127948252db..4ff83a5362b 100644
--- a/eng/common/templates/job/publish-build-assets.yml
+++ b/eng/common/templates/job/publish-build-assets.yml
@@ -92,7 +92,7 @@ jobs:
/p:OfficialBuildId=$(Build.BuildNumber)
condition: ${{ parameters.condition }}
continueOnError: ${{ parameters.continueOnError }}
-
+
- task: powershell@2
displayName: Create ReleaseConfigs Artifact
inputs:
@@ -101,7 +101,7 @@ jobs:
Add-Content -Path "$(Build.StagingDirectory)/ReleaseConfigs.txt" -Value $(BARBuildId)
Add-Content -Path "$(Build.StagingDirectory)/ReleaseConfigs.txt" -Value "$(DefaultChannels)"
Add-Content -Path "$(Build.StagingDirectory)/ReleaseConfigs.txt" -Value $(IsStableBuild)
-
+
- task: PublishBuildArtifacts@1
displayName: Publish ReleaseConfigs Artifact
inputs:
@@ -127,7 +127,7 @@ jobs:
- task: PublishBuildArtifacts@1
displayName: Publish SymbolPublishingExclusionsFile Artifact
- condition: eq(variables['SymbolExclusionFile'], 'true')
+ condition: eq(variables['SymbolExclusionFile'], 'true')
inputs:
PathtoPublish: '$(Build.SourcesDirectory)/eng/SymbolPublishingExclusionsFile.txt'
PublishLocation: Container
@@ -154,4 +154,4 @@ jobs:
- ${{ if eq(parameters.enablePublishBuildArtifacts, 'true') }}:
- template: /eng/common/templates/steps/publish-logs.yml
parameters:
- JobLabel: 'Publish_Artifacts_Logs'
+ JobLabel: 'Publish_Artifacts_Logs'
diff --git a/eng/common/templates/jobs/jobs.yml b/eng/common/templates/jobs/jobs.yml
index 67a2e2c747c..289bb2396ce 100644
--- a/eng/common/templates/jobs/jobs.yml
+++ b/eng/common/templates/jobs/jobs.yml
@@ -20,7 +20,7 @@ parameters:
enabled: false
# Optional: Include toolset dependencies in the generated graph files
includeToolset: false
-
+
# Required: A collection of jobs to run - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#job
jobs: []
@@ -47,7 +47,7 @@ parameters:
jobs:
- ${{ each job in parameters.jobs }}:
- template: ../job/job.yml
- parameters:
+ parameters:
# pass along parameters
${{ each parameter in parameters }}:
${{ if ne(parameter.key, 'jobs') }}:
diff --git a/eng/common/templates/post-build/post-build.yml b/eng/common/templates/post-build/post-build.yml
index 37bca799a3f..7b989985b0e 100644
--- a/eng/common/templates/post-build/post-build.yml
+++ b/eng/common/templates/post-build/post-build.yml
@@ -39,7 +39,7 @@ parameters:
displayName: Enable NuGet validation
type: boolean
default: true
-
+
- name: publishInstallersAndChecksums
displayName: Publish installers and checksums
type: boolean
@@ -131,8 +131,8 @@ stages:
displayName: Validate
inputs:
filePath: $(Build.SourcesDirectory)/eng/common/post-build/nuget-validation.ps1
- arguments: -PackagesPath $(Build.ArtifactStagingDirectory)/PackageArtifacts/
- -ToolDestinationPath $(Agent.BuildDirectory)/Extract/
+ arguments: -PackagesPath $(Build.ArtifactStagingDirectory)/PackageArtifacts/
+ -ToolDestinationPath $(Agent.BuildDirectory)/Extract/
- job:
displayName: Signing Validation
@@ -227,9 +227,9 @@ stages:
displayName: Validate
inputs:
filePath: $(Build.SourcesDirectory)/eng/common/post-build/sourcelink-validation.ps1
- arguments: -InputPath $(Build.ArtifactStagingDirectory)/BlobArtifacts/
- -ExtractPath $(Agent.BuildDirectory)/Extract/
- -GHRepoName $(Build.Repository.Name)
+ arguments: -InputPath $(Build.ArtifactStagingDirectory)/BlobArtifacts/
+ -ExtractPath $(Agent.BuildDirectory)/Extract/
+ -GHRepoName $(Build.Repository.Name)
-GHCommit $(Build.SourceVersion)
-SourcelinkCliVersion $(SourceLinkCLIVersion)
continueOnError: true
diff --git a/global.json b/global.json
index 505f93f3317..7e9bd06a734 100644
--- a/global.json
+++ b/global.json
@@ -8,7 +8,7 @@
"rollForward": "latestMajor"
},
"msbuild-sdks": {
- "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.24114.2",
- "Microsoft.DotNet.Helix.Sdk": "7.0.0-beta.24114.2"
+ "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.24114.4",
+ "Microsoft.DotNet.Helix.Sdk": "7.0.0-beta.24114.4"
}
}
From 73bafd11454cc2e511c123aa8dcb1c7209edfb2d Mon Sep 17 00:00:00 2001
From: vseanreesermsft <78103370+vseanreesermsft@users.noreply.github.com>
Date: Tue, 5 Mar 2024 12:42:33 -0800
Subject: [PATCH 02/22] Update branding to 6.0.29 (#33246)
---
eng/Versions.props | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/eng/Versions.props b/eng/Versions.props
index 6368edf34c2..63081a20126 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -1,6 +1,6 @@
- 6.0.28
+ 6.0.29
servicing
False
true
From 651835f18f69392e60dec30bdc777cfc11bdda23 Mon Sep 17 00:00:00 2001
From: vseanreesermsft <78103370+vseanreesermsft@users.noreply.github.com>
Date: Tue, 5 Mar 2024 12:42:53 -0800
Subject: [PATCH 03/22] Update branding to 8.0.4 (#33248)
---
eng/Versions.props | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/eng/Versions.props b/eng/Versions.props
index 04c6b26f20a..d170618fa59 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -1,6 +1,6 @@
- 8.0.3
+ 8.0.4
servicing
From c4fda642938b3c6b60038d4116074e0dce6fb0a6 Mon Sep 17 00:00:00 2001
From: Shay Rojansky
Date: Tue, 5 Mar 2024 22:45:01 +0200
Subject: [PATCH 04/22] Fix OPENJSON postprocessing with split query (#32978)
(#33027)
Fixes #32976
(cherry picked from commit 451514e2e8887b3ee56062b241386d66aeabffc7)
---
.../Internal/SqlServerJsonPostprocessor.cs | 12 ++++++-
...dPrimitiveCollectionsQuerySqlServerTest.cs | 36 +++++++++++++++++++
2 files changed, 47 insertions(+), 1 deletion(-)
diff --git a/src/EFCore.SqlServer/Query/Internal/SqlServerJsonPostprocessor.cs b/src/EFCore.SqlServer/Query/Internal/SqlServerJsonPostprocessor.cs
index 4baa71272c9..28c74f76cbc 100644
--- a/src/EFCore.SqlServer/Query/Internal/SqlServerJsonPostprocessor.cs
+++ b/src/EFCore.SqlServer/Query/Internal/SqlServerJsonPostprocessor.cs
@@ -32,6 +32,9 @@ private readonly
private RelationalTypeMapping? _nvarcharMaxTypeMapping;
+ private static readonly bool UseOldBehavior32976 =
+ AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue32976", out var enabled32976) && enabled32976;
+
///
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
@@ -70,7 +73,14 @@ public virtual Expression Process(Expression expression)
switch (expression)
{
case ShapedQueryExpression shapedQueryExpression:
- return shapedQueryExpression.UpdateQueryExpression(Visit(shapedQueryExpression.QueryExpression));
+ shapedQueryExpression = shapedQueryExpression.UpdateQueryExpression(Visit(shapedQueryExpression.QueryExpression));
+
+ if (!UseOldBehavior32976)
+ {
+ shapedQueryExpression = shapedQueryExpression.UpdateShaperExpression(Visit(shapedQueryExpression.ShaperExpression));
+ }
+
+ return shapedQueryExpression;
case SelectExpression selectExpression:
{
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NonSharedPrimitiveCollectionsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NonSharedPrimitiveCollectionsQuerySqlServerTest.cs
index 28703f1f91d..a28150f3ad6 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/NonSharedPrimitiveCollectionsQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/NonSharedPrimitiveCollectionsQuerySqlServerTest.cs
@@ -871,6 +871,42 @@ public virtual async Task Same_collection_with_conflicting_type_mappings_not_sup
#endregion Type mapping inference
+ [ConditionalFact]
+ public virtual async Task Ordered_collection_with_split_query()
+ {
+ var contextFactory = await InitializeAsync(
+ onModelCreating: mb => mb.Entity(),
+ seed: context =>
+ {
+ context.Add(new Context32976.Principal { Ints = [2, 3, 4]});
+ context.SaveChanges();
+ });
+
+ await using var context = contextFactory.CreateContext();
+
+ _ = await context.Set()
+ .Where(p => p.Ints.Skip(1).Contains(3))
+ .Include(p => p.Dependents)
+ .AsSplitQuery()
+ .SingleAsync();
+ }
+
+ public class Context32976(DbContextOptions options) : DbContext(options)
+ {
+ public class Principal
+ {
+ public int Id { get; set; }
+ public List Ints { get; set; }
+ public List Dependents { get; set; }
+ }
+
+ public class Dependent
+ {
+ public int Id { get; set; }
+ public Principal Principal { get; set; }
+ }
+ }
+
[ConditionalFact]
public virtual void Check_all_tests_overridden()
=> TestHelpers.AssertAllMethodsOverridden(GetType());
From 406121fdcef8d1e18f50518f57eeb1fb8e047b98 Mon Sep 17 00:00:00 2001
From: Maurycy Markowski
Date: Tue, 5 Mar 2024 12:46:01 -0800
Subject: [PATCH 05/22] Fix to #32972 - The database default created by
Migrations for primitive collections mapped to JSON is invalid (#33048)
Problem was that when adding new required column to an existing table we always need to provide default value (to fill the values for rows already in the table). For collection of primitives that get map to json we should be setting the value to empty JSON collection, i.e. '[]' but we were not doing that.
---
.../Internal/MigrationsModelDiffer.cs | 12 +-
.../Migrations/MigrationsTestBase.cs | 267 ++++++++++++++++++
.../Migrations/MigrationsSqlServerTest.cs | 98 +++++++
.../Migrations/MigrationsSqliteTest.cs | 97 +++++++
4 files changed, 473 insertions(+), 1 deletion(-)
diff --git a/src/EFCore.Relational/Migrations/Internal/MigrationsModelDiffer.cs b/src/EFCore.Relational/Migrations/Internal/MigrationsModelDiffer.cs
index a14998c9fd4..04cc44f1621 100644
--- a/src/EFCore.Relational/Migrations/Internal/MigrationsModelDiffer.cs
+++ b/src/EFCore.Relational/Migrations/Internal/MigrationsModelDiffer.cs
@@ -16,6 +16,9 @@ namespace Microsoft.EntityFrameworkCore.Migrations.Internal;
///
public class MigrationsModelDiffer : IMigrationsModelDiffer
{
+ private static readonly bool UseOldBehavior32972 =
+ AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue32972", out var enabled32972) && enabled32972;
+
private static readonly Type[] DropOperationTypes =
{
typeof(DropIndexOperation),
@@ -1190,7 +1193,14 @@ private void Initialize(
if (!column.TryGetDefaultValue(out var defaultValue))
{
- defaultValue = null;
+ // for non-nullable collections of primitives that are mapped to JSON we set a default value corresponding to empty JSON collection
+ defaultValue = !UseOldBehavior32972
+ && !inline
+ && column is { IsNullable: false, StoreTypeMapping: { ElementTypeMapping: not null, Converter: ValueConverter columnValueConverter } }
+ && columnValueConverter.GetType() is Type { IsGenericType: true } columnValueConverterType
+ && columnValueConverterType.GetGenericTypeDefinition() == typeof(CollectionToJsonStringConverter<>)
+ ? "[]"
+ : null;
}
columnOperation.ColumnType = column.StoreType;
diff --git a/test/EFCore.Relational.Specification.Tests/Migrations/MigrationsTestBase.cs b/test/EFCore.Relational.Specification.Tests/Migrations/MigrationsTestBase.cs
index 8af3b5cbc97..7ce11ea2355 100644
--- a/test/EFCore.Relational.Specification.Tests/Migrations/MigrationsTestBase.cs
+++ b/test/EFCore.Relational.Specification.Tests/Migrations/MigrationsTestBase.cs
@@ -1874,6 +1874,273 @@ await Test(
""");
}
+ [ConditionalFact]
+ public virtual Task Add_required_primitve_collection_to_existing_table()
+ => Test(
+ builder => builder.Entity(
+ "Customer", e =>
+ {
+ e.Property("Id").ValueGeneratedOnAdd();
+ e.HasKey("Id");
+ e.Property("Name");
+ e.ToTable("Customers");
+ }),
+ builder => builder.Entity(
+ "Customer", e =>
+ {
+ e.Property("Id").ValueGeneratedOnAdd();
+ e.HasKey("Id");
+ e.Property("Name");
+ e.Property>("Numbers").IsRequired();
+ e.ToTable("Customers");
+ }),
+ model =>
+ {
+ var customersTable = Assert.Single(model.Tables.Where(t => t.Name == "Customers"));
+
+ Assert.Collection(
+ customersTable.Columns,
+ c => Assert.Equal("Id", c.Name),
+ c => Assert.Equal("Name", c.Name),
+ c => Assert.Equal("Numbers", c.Name));
+ Assert.Same(
+ customersTable.Columns.Single(c => c.Name == "Id"),
+ Assert.Single(customersTable.PrimaryKey!.Columns));
+ });
+
+ [ConditionalFact]
+ public virtual Task Add_required_primitve_collection_with_custom_default_value_to_existing_table()
+ => Test(
+ builder => builder.Entity(
+ "Customer", e =>
+ {
+ e.Property("Id").ValueGeneratedOnAdd();
+ e.HasKey("Id");
+ e.Property("Name");
+ e.ToTable("Customers");
+ }),
+ builder => builder.Entity(
+ "Customer", e =>
+ {
+ e.Property("Id").ValueGeneratedOnAdd();
+ e.HasKey("Id");
+ e.Property("Name");
+ e.Property>("Numbers").IsRequired().HasDefaultValue(new List { 1, 2, 3 });
+ e.ToTable("Customers");
+ }),
+ model =>
+ {
+ var customersTable = Assert.Single(model.Tables.Where(t => t.Name == "Customers"));
+
+ Assert.Collection(
+ customersTable.Columns,
+ c => Assert.Equal("Id", c.Name),
+ c => Assert.Equal("Name", c.Name),
+ c => Assert.Equal("Numbers", c.Name));
+ Assert.Same(
+ customersTable.Columns.Single(c => c.Name == "Id"),
+ Assert.Single(customersTable.PrimaryKey!.Columns));
+ });
+
+ [ConditionalFact]
+ public abstract Task Add_required_primitve_collection_with_custom_default_value_sql_to_existing_table();
+
+ protected virtual Task Add_required_primitve_collection_with_custom_default_value_sql_to_existing_table_core(string defaultValueSql)
+ => Test(
+ builder => builder.Entity(
+ "Customer", e =>
+ {
+ e.Property("Id").ValueGeneratedOnAdd();
+ e.HasKey("Id");
+ e.Property("Name");
+ e.ToTable("Customers");
+ }),
+ builder => builder.Entity(
+ "Customer", e =>
+ {
+ e.Property("Id").ValueGeneratedOnAdd();
+ e.HasKey("Id");
+ e.Property("Name");
+ e.Property>("Numbers").IsRequired().HasDefaultValueSql(defaultValueSql);
+ e.ToTable("Customers");
+ }),
+ model =>
+ {
+ var customersTable = Assert.Single(model.Tables.Where(t => t.Name == "Customers"));
+
+ Assert.Collection(
+ customersTable.Columns,
+ c => Assert.Equal("Id", c.Name),
+ c => Assert.Equal("Name", c.Name),
+ c => Assert.Equal("Numbers", c.Name));
+ Assert.Same(
+ customersTable.Columns.Single(c => c.Name == "Id"),
+ Assert.Single(customersTable.PrimaryKey!.Columns));
+ });
+
+ [ConditionalFact(Skip = "issue #33038")]
+ public virtual Task Add_required_primitve_collection_with_custom_converter_to_existing_table()
+ => Test(
+ builder => builder.Entity(
+ "Customer", e =>
+ {
+ e.Property("Id").ValueGeneratedOnAdd();
+ e.HasKey("Id");
+ e.Property("Name");
+ e.ToTable("Customers");
+ }),
+ builder => builder.Entity(
+ "Customer", e =>
+ {
+ e.Property("Id").ValueGeneratedOnAdd();
+ e.HasKey("Id");
+ e.Property("Name");
+ e.Property>("Numbers").HasConversion(new ValueConverter, string>(
+ convertToProviderExpression: x => x != null && x.Count > 0 ? "some numbers" : "nothing",
+ convertFromProviderExpression: x => x == "nothing" ? new List { } : new List { 7, 8, 9 }))
+ .IsRequired();
+ e.ToTable("Customers");
+ }),
+ model =>
+ {
+ var customersTable = Assert.Single(model.Tables.Where(t => t.Name == "Customers"));
+
+ Assert.Collection(
+ customersTable.Columns,
+ c => Assert.Equal("Id", c.Name),
+ c => Assert.Equal("Name", c.Name),
+ c => Assert.Equal("Numbers", c.Name));
+ Assert.Same(
+ customersTable.Columns.Single(c => c.Name == "Id"),
+ Assert.Single(customersTable.PrimaryKey!.Columns));
+ });
+
+ [ConditionalFact]
+ public virtual Task Add_required_primitve_collection_with_custom_converter_and_custom_default_value_to_existing_table()
+ => Test(
+ builder => builder.Entity(
+ "Customer", e =>
+ {
+ e.Property("Id").ValueGeneratedOnAdd();
+ e.HasKey("Id");
+ e.Property("Name");
+ e.ToTable("Customers");
+ }),
+ builder => builder.Entity(
+ "Customer", e =>
+ {
+ e.Property("Id").ValueGeneratedOnAdd();
+ e.HasKey("Id");
+ e.Property("Name");
+ e.Property>("Numbers").HasConversion(new ValueConverter, string>(
+ convertToProviderExpression: x => x != null && x.Count > 0 ? "some numbers" : "nothing",
+ convertFromProviderExpression: x => x == "nothing" ? new List { } : new List { 7, 8, 9 }))
+ .HasDefaultValue(new List { 42 })
+ .IsRequired();
+ e.ToTable("Customers");
+ }),
+ model =>
+ {
+ var customersTable = Assert.Single(model.Tables.Where(t => t.Name == "Customers"));
+
+ Assert.Collection(
+ customersTable.Columns,
+ c => Assert.Equal("Id", c.Name),
+ c => Assert.Equal("Name", c.Name),
+ c => Assert.Equal("Numbers", c.Name));
+ Assert.Same(
+ customersTable.Columns.Single(c => c.Name == "Id"),
+ Assert.Single(customersTable.PrimaryKey!.Columns));
+ });
+
+ [ConditionalFact]
+ public virtual Task Add_optional_primitive_collection_to_existing_table()
+ => Test(
+ builder => builder.Entity(
+ "Customer", e =>
+ {
+ e.Property("Id").ValueGeneratedOnAdd();
+ e.HasKey("Id");
+ e.Property("Name");
+ e.ToTable("Customers");
+ }),
+ builder => builder.Entity(
+ "Customer", e =>
+ {
+ e.Property("Id").ValueGeneratedOnAdd();
+ e.HasKey("Id");
+ e.Property("Name");
+ e.Property>("Numbers");
+ e.ToTable("Customers");
+ }),
+ model =>
+ {
+ var customersTable = Assert.Single(model.Tables.Where(t => t.Name == "Customers"));
+
+ Assert.Collection(
+ customersTable.Columns,
+ c => Assert.Equal("Id", c.Name),
+ c => Assert.Equal("Name", c.Name),
+ c => Assert.Equal("Numbers", c.Name));
+ Assert.Same(
+ customersTable.Columns.Single(c => c.Name == "Id"),
+ Assert.Single(customersTable.PrimaryKey!.Columns));
+ });
+
+ [ConditionalFact]
+ public virtual Task Create_table_with_required_primitive_collection()
+ => Test(
+ builder => { },
+ builder => builder.Entity(
+ "Customer", e =>
+ {
+ e.Property("Id").ValueGeneratedOnAdd();
+ e.HasKey("Id");
+ e.Property("Name");
+ e.Property>("Numbers").IsRequired();
+ e.ToTable("Customers");
+ }),
+ model =>
+ {
+ var customersTable = Assert.Single(model.Tables.Where(t => t.Name == "Customers"));
+
+ Assert.Collection(
+ customersTable.Columns,
+ c => Assert.Equal("Id", c.Name),
+ c => Assert.Equal("Name", c.Name),
+ c => Assert.Equal("Numbers", c.Name));
+ Assert.Same(
+ customersTable.Columns.Single(c => c.Name == "Id"),
+ Assert.Single(customersTable.PrimaryKey!.Columns));
+ });
+
+ [ConditionalFact]
+ public virtual Task Create_table_with_optional_primitive_collection()
+ => Test(
+ builder => { },
+ builder => builder.Entity(
+ "Customer", e =>
+ {
+ e.Property("Id").ValueGeneratedOnAdd();
+ e.HasKey("Id");
+ e.Property("Name");
+ e.Property>("Numbers");
+ e.ToTable("Customers");
+ }),
+ model =>
+ {
+ var customersTable = Assert.Single(model.Tables.Where(t => t.Name == "Customers"));
+
+ Assert.Collection(
+ customersTable.Columns,
+ c => Assert.Equal("Id", c.Name),
+ c => Assert.Equal("Name", c.Name),
+ c => Assert.Equal("Numbers", c.Name));
+ Assert.Same(
+ customersTable.Columns.Single(c => c.Name == "Id"),
+ Assert.Single(customersTable.PrimaryKey!.Columns));
+ });
+
protected class Person
{
public int Id { get; set; }
diff --git a/test/EFCore.SqlServer.FunctionalTests/Migrations/MigrationsSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Migrations/MigrationsSqlServerTest.cs
index a2c64defd70..fd327ecba19 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Migrations/MigrationsSqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Migrations/MigrationsSqlServerTest.cs
@@ -9230,6 +9230,104 @@ await Test(
AssertSql();
}
+ [ConditionalFact]
+ public override async Task Add_required_primitve_collection_to_existing_table()
+ {
+ await base.Add_required_primitve_collection_to_existing_table();
+
+ AssertSql(
+"""
+ALTER TABLE [Customers] ADD [Numbers] nvarchar(max) NOT NULL DEFAULT N'[]';
+""");
+ }
+
+ [ConditionalFact]
+ public override async Task Add_required_primitve_collection_with_custom_default_value_to_existing_table()
+ {
+ await base.Add_required_primitve_collection_with_custom_default_value_to_existing_table();
+
+ AssertSql(
+"""
+ALTER TABLE [Customers] ADD [Numbers] nvarchar(max) NOT NULL DEFAULT N'[1,2,3]';
+""");
+ }
+
+ [ConditionalFact]
+ public override async Task Add_required_primitve_collection_with_custom_default_value_sql_to_existing_table()
+ {
+ await base.Add_required_primitve_collection_with_custom_default_value_sql_to_existing_table_core("N'[3, 2, 1]'");
+
+ AssertSql(
+"""
+ALTER TABLE [Customers] ADD [Numbers] nvarchar(max) NOT NULL DEFAULT (N'[3, 2, 1]');
+""");
+ }
+
+ [ConditionalFact(Skip = "issue #33038")]
+ public override async Task Add_required_primitve_collection_with_custom_converter_to_existing_table()
+ {
+ await base.Add_required_primitve_collection_with_custom_converter_to_existing_table();
+
+ AssertSql(
+"""
+ALTER TABLE [Customers] ADD [Numbers] nvarchar(max) NOT NULL DEFAULT N'nothing';
+""");
+ }
+
+ [ConditionalFact]
+ public override async Task Add_required_primitve_collection_with_custom_converter_and_custom_default_value_to_existing_table()
+ {
+ await base.Add_required_primitve_collection_with_custom_converter_and_custom_default_value_to_existing_table();
+
+ AssertSql(
+"""
+ALTER TABLE [Customers] ADD [Numbers] nvarchar(max) NOT NULL DEFAULT N'some numbers';
+""");
+ }
+
+ [ConditionalFact]
+ public override async Task Add_optional_primitive_collection_to_existing_table()
+ {
+ await base.Add_optional_primitive_collection_to_existing_table();
+
+ AssertSql(
+"""
+ALTER TABLE [Customers] ADD [Numbers] nvarchar(max) NULL;
+""");
+ }
+
+ [ConditionalFact]
+ public override async Task Create_table_with_required_primitive_collection()
+ {
+ await base.Create_table_with_required_primitive_collection();
+
+ AssertSql(
+"""
+CREATE TABLE [Customers] (
+ [Id] int NOT NULL IDENTITY,
+ [Name] nvarchar(max) NULL,
+ [Numbers] nvarchar(max) NOT NULL,
+ CONSTRAINT [PK_Customers] PRIMARY KEY ([Id])
+);
+""");
+ }
+
+ [ConditionalFact]
+ public override async Task Create_table_with_optional_primitive_collection()
+ {
+ await base.Create_table_with_optional_primitive_collection();
+
+ AssertSql(
+"""
+CREATE TABLE [Customers] (
+ [Id] int NOT NULL IDENTITY,
+ [Name] nvarchar(max) NULL,
+ [Numbers] nvarchar(max) NULL,
+ CONSTRAINT [PK_Customers] PRIMARY KEY ([Id])
+);
+""");
+ }
+
protected override string NonDefaultCollation
=> _nonDefaultCollation ??= GetDatabaseCollation() == "German_PhoneBook_CI_AS"
? "French_CI_AS"
diff --git a/test/EFCore.Sqlite.FunctionalTests/Migrations/MigrationsSqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Migrations/MigrationsSqliteTest.cs
index c5de28da7a2..f0179b94b70 100644
--- a/test/EFCore.Sqlite.FunctionalTests/Migrations/MigrationsSqliteTest.cs
+++ b/test/EFCore.Sqlite.FunctionalTests/Migrations/MigrationsSqliteTest.cs
@@ -1732,6 +1732,103 @@ public override Task Rename_sequence()
public override Task Move_sequence()
=> AssertNotSupportedAsync(base.Move_sequence, SqliteStrings.SequencesNotSupported);
+
+ [ConditionalFact]
+ public override async Task Add_required_primitve_collection_to_existing_table()
+ {
+ await base.Add_required_primitve_collection_to_existing_table();
+
+ AssertSql(
+"""
+ALTER TABLE "Customers" ADD "Numbers" TEXT NOT NULL DEFAULT '[]';
+""");
+ }
+
+ [ConditionalFact]
+ public override async Task Add_required_primitve_collection_with_custom_default_value_to_existing_table()
+ {
+ await base.Add_required_primitve_collection_with_custom_default_value_to_existing_table();
+
+ AssertSql(
+"""
+ALTER TABLE "Customers" ADD "Numbers" TEXT NOT NULL DEFAULT '[1,2,3]';
+""");
+ }
+
+ [ConditionalFact]
+ public override async Task Add_required_primitve_collection_with_custom_default_value_sql_to_existing_table()
+ {
+ await base.Add_required_primitve_collection_with_custom_default_value_sql_to_existing_table_core("'[3, 2, 1]'");
+
+ AssertSql(
+"""
+ALTER TABLE "Customers" ADD "Numbers" TEXT NOT NULL DEFAULT ('[3, 2, 1]');
+""");
+ }
+
+ [ConditionalFact(Skip = "issue #33038")]
+ public override async Task Add_required_primitve_collection_with_custom_converter_to_existing_table()
+ {
+ await base.Add_required_primitve_collection_with_custom_converter_to_existing_table();
+
+ AssertSql(
+"""
+ALTER TABLE [Customers] ADD [Numbers] nvarchar(max) NOT NULL DEFAULT N'nothing';
+""");
+ }
+
+ [ConditionalFact]
+ public override async Task Add_required_primitve_collection_with_custom_converter_and_custom_default_value_to_existing_table()
+ {
+ await base.Add_required_primitve_collection_with_custom_converter_and_custom_default_value_to_existing_table();
+
+ AssertSql(
+"""
+ALTER TABLE "Customers" ADD "Numbers" TEXT NOT NULL DEFAULT 'some numbers';
+""");
+ }
+
+ [ConditionalFact]
+ public override async Task Add_optional_primitive_collection_to_existing_table()
+ {
+ await base.Add_optional_primitive_collection_to_existing_table();
+
+ AssertSql(
+"""
+ALTER TABLE "Customers" ADD "Numbers" TEXT NULL;
+""");
+ }
+
+ [ConditionalFact]
+ public override async Task Create_table_with_required_primitive_collection()
+ {
+ await base.Create_table_with_required_primitive_collection();
+
+ AssertSql(
+"""
+CREATE TABLE "Customers" (
+ "Id" INTEGER NOT NULL CONSTRAINT "PK_Customers" PRIMARY KEY AUTOINCREMENT,
+ "Name" TEXT NULL,
+ "Numbers" TEXT NOT NULL
+);
+""");
+ }
+
+ [ConditionalFact]
+ public override async Task Create_table_with_optional_primitive_collection()
+ {
+ await base.Create_table_with_optional_primitive_collection();
+
+ AssertSql(
+"""
+CREATE TABLE "Customers" (
+ "Id" INTEGER NOT NULL CONSTRAINT "PK_Customers" PRIMARY KEY AUTOINCREMENT,
+ "Name" TEXT NULL,
+ "Numbers" TEXT NULL
+);
+""");
+ }
+
// SQLite does not support schemas
protected override bool AssertSchemaNames
=> false;
From b0faa525f3373005d0799bf749bb9e9b1656cf60 Mon Sep 17 00:00:00 2001
From: Andriy Svyryd
Date: Tue, 5 Mar 2024 12:46:37 -0800
Subject: [PATCH 06/22] Reduce memory usage during relationship cycle detection
by keeping track of visited properties whenever there are FK forks (#33211)
Fixes #33176
---
src/EFCore/Metadata/Internal/Property.cs | 22 ++++++-
.../SqlServerModelValidatorTest.cs | 14 +++++
.../Infrastructure/ModelValidatorTestBase.cs | 58 +++++++++++++++----
3 files changed, 80 insertions(+), 14 deletions(-)
diff --git a/src/EFCore/Metadata/Internal/Property.cs b/src/EFCore/Metadata/Internal/Property.cs
index a8fcb4eee96..e88f9f4bef5 100644
--- a/src/EFCore/Metadata/Internal/Property.cs
+++ b/src/EFCore/Metadata/Internal/Property.cs
@@ -40,6 +40,9 @@ public class Property : PropertyBase, IMutableProperty, IConventionProperty, IPr
public static readonly bool UseOldBehavior32422 =
AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue32422", out var enabled32422) && enabled32422;
+ private static readonly bool UseOldBehavior33176 =
+ AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue33176", out var enabled33176) && enabled33176;
+
///
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
@@ -911,9 +914,10 @@ public virtual (ValueConverter? ValueConverter, Type? ValueConverterType, Type?
bool throwOnValueConverterConflict = true,
bool throwOnProviderClrTypeConflict = true)
{
- Queue<(Property CurrentProperty, Property CycleBreakingPropert, int CyclePosition, int MaxCycleLength)>? queue = null;
- (Property CurrentProperty, Property CycleBreakingPropert, int CyclePosition, int MaxCycleLength)? currentNode =
+ Queue<(Property CurrentProperty, Property CycleBreakingProperty, int CyclePosition, int MaxCycleLength)>? queue = null;
+ (Property CurrentProperty, Property CycleBreakingProperty, int CyclePosition, int MaxCycleLength)? currentNode =
(this, this, 0, 2);
+ HashSet? visitedProperties = null;
ValueConverter? valueConverter = null;
Type? valueConverterType = null;
@@ -922,12 +926,17 @@ public virtual (ValueConverter? ValueConverter, Type? ValueConverterType, Type?
{
var (property, cycleBreakingProperty, cyclePosition, maxCycleLength) = currentNode ?? queue!.Dequeue();
currentNode = null;
- if (cyclePosition >= ForeignKey.LongestFkChainAllowedLength)
+ if (cyclePosition >= ForeignKey.LongestFkChainAllowedLength
+ || (!UseOldBehavior33176
+ && queue is not null
+ && queue.Count >= ForeignKey.LongestFkChainAllowedLength))
{
throw new InvalidOperationException(
CoreStrings.RelationshipCycle(DeclaringType.DisplayName(), Name, "ValueConverter"));
}
+ visitedProperties?.Add(property);
+
foreach (var foreignKey in property.GetContainingForeignKeys())
{
for (var propertyIndex = 0; propertyIndex < foreignKey.Properties.Count; propertyIndex++)
@@ -956,6 +965,13 @@ public virtual (ValueConverter? ValueConverter, Type? ValueConverterType, Type?
{
queue = new();
queue.Enqueue(currentNode.Value);
+ visitedProperties = new() { property };
+ }
+
+ if (!UseOldBehavior33176
+ && visitedProperties?.Contains(principalProperty) == true)
+ {
+ break;
}
if (cyclePosition == maxCycleLength - 1)
diff --git a/test/EFCore.SqlServer.Tests/Infrastructure/SqlServerModelValidatorTest.cs b/test/EFCore.SqlServer.Tests/Infrastructure/SqlServerModelValidatorTest.cs
index 7019f8ada98..a311cb5d41b 100644
--- a/test/EFCore.SqlServer.Tests/Infrastructure/SqlServerModelValidatorTest.cs
+++ b/test/EFCore.SqlServer.Tests/Infrastructure/SqlServerModelValidatorTest.cs
@@ -11,6 +11,20 @@ namespace Microsoft.EntityFrameworkCore.Infrastructure;
public class SqlServerModelValidatorTest : RelationalModelValidatorTest
{
+ [ConditionalFact]
+ public virtual void Passes_on_TPT_with_nested_owned_types()
+ {
+ var modelBuilder = base.CreateConventionModelBuilder();
+
+ modelBuilder.Entity().UseTptMappingStrategy();
+ modelBuilder.Entity();
+ modelBuilder.Entity();
+ modelBuilder.Entity();
+ modelBuilder.Entity();
+
+ Validate(modelBuilder);
+ }
+
public override void Detects_duplicate_columns_in_derived_types_with_different_types()
{
var modelBuilder = CreateConventionModelBuilder();
diff --git a/test/EFCore.Tests/Infrastructure/ModelValidatorTestBase.cs b/test/EFCore.Tests/Infrastructure/ModelValidatorTestBase.cs
index e6d2953e258..ddee4e89e0b 100644
--- a/test/EFCore.Tests/Infrastructure/ModelValidatorTestBase.cs
+++ b/test/EFCore.Tests/Infrastructure/ModelValidatorTestBase.cs
@@ -118,7 +118,43 @@ protected class Generic : Abstract
{
}
- public class SampleEntity
+#nullable enable
+ protected class BaseEntity
+ {
+ public int Id { get; set; }
+ }
+
+ protected class ChildA : BaseEntity
+ {
+ public OwnedType OwnedType { get; set; } = null!;
+ }
+
+ protected class ChildB : BaseEntity
+ {
+ }
+
+ protected class ChildC : BaseEntity
+ {
+ }
+
+ protected class ChildD : BaseEntity
+ {
+ }
+
+ [Owned]
+ protected class OwnedType
+ {
+ public NestedOwnedType NestedOwnedType { get; set; } = null!;
+ }
+
+ [Owned]
+ protected class NestedOwnedType
+ {
+ }
+
+#nullable restore
+
+ protected class SampleEntity
{
public int Id { get; set; }
public int Number { get; set; }
@@ -131,29 +167,29 @@ public class SampleEntity
public ICollection OtherSamples { get; set; }
}
- public class AnotherSampleEntity
+ protected class AnotherSampleEntity
{
public int Id { get; set; }
public ReferencedEntity ReferencedEntity { get; set; }
}
- public class ReferencedEntity
+ protected class ReferencedEntity
{
public int Id { get; set; }
public int SampleEntityId { get; set; }
}
- public class SampleEntityMinimal
+ protected class SampleEntityMinimal
{
public int Id { get; set; }
public ReferencedEntityMinimal ReferencedEntity { get; set; }
}
- public class ReferencedEntityMinimal
+ protected class ReferencedEntityMinimal
{
}
- public class AnotherSampleEntityMinimal
+ protected class AnotherSampleEntityMinimal
{
public int Id { get; set; }
public ReferencedEntityMinimal ReferencedEntity { get; set; }
@@ -373,7 +409,7 @@ protected class DependentFour
public PrincipalFour PrincipalFour { get; set; }
}
- public class Blog
+ protected class Blog
{
public int BlogId { get; set; }
public bool IsDeleted { get; set; }
@@ -381,14 +417,14 @@ public class Blog
public List BlogOwnedEntities { get; set; }
}
- public class BlogOwnedEntity
+ protected class BlogOwnedEntity
{
public int BlogOwnedEntityId { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
}
- public class Post
+ protected class Post
{
public int PostId { get; set; }
public int BlogId { get; set; }
@@ -397,13 +433,13 @@ public class Post
public Blog Blog { get; set; }
}
- public class PicturePost : Post
+ protected class PicturePost : Post
{
public string PictureUrl { get; set; }
public List Pictures { get; set; }
}
- public class Picture
+ protected class Picture
{
public int PictureId { get; set; }
public bool IsDeleted { get; set; }
From 492381343a9529f17f99e6711be82e205bc8c5a3 Mon Sep 17 00:00:00 2001
From: Maurycy Markowski
Date: Tue, 5 Mar 2024 15:01:25 -0800
Subject: [PATCH 07/22] Fix to #33004 - Unfulfillable nullable contraints are
set for complex types with TPH entities (#33054)
When figuring out nullability of columns representing a given property, if property is declared on derived entity in TPH, we make that column nullable. For complex type properties we should be doing the same (and we did), but declaring type of that property is the complex type itself. Instead we should look at the ContainingEntityType rather than just DeclaringType.
---
.../RelationalPropertyExtensions.cs | 9 ++-
.../Migrations/MigrationsTestBase.cs | 67 +++++++++++++++++++
.../Migrations/MigrationsSqlServerTest.cs | 19 ++++++
.../Migrations/MigrationsSqliteTest.cs | 18 +++++
4 files changed, 112 insertions(+), 1 deletion(-)
diff --git a/src/EFCore.Relational/Extensions/RelationalPropertyExtensions.cs b/src/EFCore.Relational/Extensions/RelationalPropertyExtensions.cs
index 0b0d0b7f410..929fb4f470e 100644
--- a/src/EFCore.Relational/Extensions/RelationalPropertyExtensions.cs
+++ b/src/EFCore.Relational/Extensions/RelationalPropertyExtensions.cs
@@ -20,6 +20,9 @@ public static class RelationalPropertyExtensions
private static readonly bool UseOldBehavior32763 =
AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue32763", out var enabled32763) && enabled32763;
+ private static readonly bool UseOldBehavior33004 =
+ AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue33004", out var enabled33004) && enabled33004;
+
private static readonly MethodInfo GetFieldValueMethod =
typeof(DbDataReader).GetRuntimeMethod(nameof(DbDataReader.GetFieldValue), new[] { typeof(int) })!;
@@ -1191,8 +1194,12 @@ public static bool IsColumnNullable(this IReadOnlyProperty property, in StoreObj
return sharedTableRootProperty.IsColumnNullable(storeObject);
}
+ var declaringEntityType = UseOldBehavior33004
+ ? property.DeclaringType
+ : property.DeclaringType.ContainingEntityType;
+
return property.IsNullable
- || (property.DeclaringType is IReadOnlyEntityType entityType
+ || (declaringEntityType is IReadOnlyEntityType entityType
&& ((entityType.BaseType != null
&& entityType.GetMappingStrategy() == RelationalAnnotationNames.TphMappingStrategy)
|| IsOptionalSharingDependent(entityType, storeObject, 0)));
diff --git a/test/EFCore.Relational.Specification.Tests/Migrations/MigrationsTestBase.cs b/test/EFCore.Relational.Specification.Tests/Migrations/MigrationsTestBase.cs
index 7ce11ea2355..eef96d80c95 100644
--- a/test/EFCore.Relational.Specification.Tests/Migrations/MigrationsTestBase.cs
+++ b/test/EFCore.Relational.Specification.Tests/Migrations/MigrationsTestBase.cs
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System.ComponentModel.DataAnnotations;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using Microsoft.EntityFrameworkCore.Migrations.Internal;
using Microsoft.EntityFrameworkCore.Scaffolding.Metadata;
@@ -2141,6 +2142,72 @@ public virtual Task Create_table_with_optional_primitive_collection()
Assert.Single(customersTable.PrimaryKey!.Columns));
});
+ [ConditionalFact]
+ public virtual Task Create_table_with_complex_type_with_required_properties_on_derived_entity_in_TPH()
+ => Test(
+ builder => { },
+ builder =>
+ {
+ builder.Entity(
+ "Contact", e =>
+ {
+ e.Property("Id").ValueGeneratedOnAdd();
+ e.HasKey("Id");
+ e.Property("Name");
+ e.ToTable("Contacts");
+ });
+ builder.Entity(
+ "Supplier", e =>
+ {
+ e.HasBaseType("Contact");
+ e.Property("Number");
+ e.ComplexProperty("MyComplex", ct =>
+ {
+ ct.ComplexProperty("MyNestedComplex").IsRequired();
+ });
+ });
+ },
+ model =>
+ {
+ var contactsTable = Assert.Single(model.Tables.Where(t => t.Name == "Contacts"));
+ Assert.Collection(
+ contactsTable.Columns,
+ c => Assert.Equal("Id", c.Name),
+ c => Assert.Equal("Discriminator", c.Name),
+ c => Assert.Equal("Name", c.Name),
+ c => Assert.Equal("Number", c.Name),
+ c =>
+ {
+ Assert.Equal("MyComplex_Prop", c.Name);
+ Assert.Equal(true, c.IsNullable);
+ },
+ c =>
+ {
+ Assert.Equal("MyComplex_MyNestedComplex_Bar", c.Name);
+ Assert.Equal(true, c.IsNullable);
+ },
+ c =>
+ {
+ Assert.Equal("MyComplex_MyNestedComplex_Foo", c.Name);
+ Assert.Equal(true, c.IsNullable);
+ });
+ });
+
+ protected class MyComplex
+ {
+ [Required]
+ public string Prop { get; set; }
+
+ [Required]
+ public MyNestedComplex Nested { get; set; }
+ }
+
+ public class MyNestedComplex
+ {
+ public int Foo { get; set; }
+ public DateTime Bar { get; set; }
+ }
+
protected class Person
{
public int Id { get; set; }
diff --git a/test/EFCore.SqlServer.FunctionalTests/Migrations/MigrationsSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Migrations/MigrationsSqlServerTest.cs
index fd327ecba19..f8c618f88ca 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Migrations/MigrationsSqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Migrations/MigrationsSqlServerTest.cs
@@ -9328,6 +9328,25 @@ CONSTRAINT [PK_Customers] PRIMARY KEY ([Id])
""");
}
+ public override async Task Create_table_with_complex_type_with_required_properties_on_derived_entity_in_TPH()
+ {
+ await base.Create_table_with_complex_type_with_required_properties_on_derived_entity_in_TPH();
+
+ AssertSql(
+"""
+CREATE TABLE [Contacts] (
+ [Id] int NOT NULL IDENTITY,
+ [Discriminator] nvarchar(8) NOT NULL,
+ [Name] nvarchar(max) NULL,
+ [Number] int NULL,
+ [MyComplex_Prop] nvarchar(max) NULL,
+ [MyComplex_MyNestedComplex_Bar] datetime2 NULL,
+ [MyComplex_MyNestedComplex_Foo] int NULL,
+ CONSTRAINT [PK_Contacts] PRIMARY KEY ([Id])
+);
+""");
+ }
+
protected override string NonDefaultCollation
=> _nonDefaultCollation ??= GetDatabaseCollation() == "German_PhoneBook_CI_AS"
? "French_CI_AS"
diff --git a/test/EFCore.Sqlite.FunctionalTests/Migrations/MigrationsSqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Migrations/MigrationsSqliteTest.cs
index f0179b94b70..1dfe9c2d5a1 100644
--- a/test/EFCore.Sqlite.FunctionalTests/Migrations/MigrationsSqliteTest.cs
+++ b/test/EFCore.Sqlite.FunctionalTests/Migrations/MigrationsSqliteTest.cs
@@ -1702,6 +1702,24 @@ await Test(
""");
}
+ public override async Task Create_table_with_complex_type_with_required_properties_on_derived_entity_in_TPH()
+ {
+ await base.Create_table_with_complex_type_with_required_properties_on_derived_entity_in_TPH();
+
+ AssertSql(
+"""
+CREATE TABLE "Contacts" (
+ "Id" INTEGER NOT NULL CONSTRAINT "PK_Contacts" PRIMARY KEY AUTOINCREMENT,
+ "Discriminator" TEXT NOT NULL,
+ "Name" TEXT NULL,
+ "Number" INTEGER NULL,
+ "MyComplex_Prop" TEXT NULL,
+ "MyComplex_MyNestedComplex_Bar" TEXT NULL,
+ "MyComplex_MyNestedComplex_Foo" INTEGER NULL
+);
+""");
+ }
+
public override Task Create_sequence()
=> AssertNotSupportedAsync(base.Create_sequence, SqliteStrings.SequencesNotSupported);
From d41b49f5bab9a3f41336f4d478866acf5ce54947 Mon Sep 17 00:00:00 2001
From: Andriy Svyryd
Date: Tue, 5 Mar 2024 16:24:08 -0800
Subject: [PATCH 08/22] [release/8.0] Split public pipeline definition (#33251)
---
azure-pipelines-public.yml | 316 +++++++++++++++++++++++++++++++++++++
1 file changed, 316 insertions(+)
create mode 100644 azure-pipelines-public.yml
diff --git a/azure-pipelines-public.yml b/azure-pipelines-public.yml
new file mode 100644
index 00000000000..aa704ddcde6
--- /dev/null
+++ b/azure-pipelines-public.yml
@@ -0,0 +1,316 @@
+schedules:
+- cron: 0 9 * * 1
+ displayName: "Run CodeQL3000 weekly, Monday at 2:00 AM PDT"
+ branches:
+ include:
+ - release/2.1
+ - release/6.0
+ - release/7.0
+ - main
+ always: true
+
+parameters:
+ # Parameter below is ignored in public builds.
+ #
+ # Choose whether to run the CodeQL3000 tasks.
+ # Manual builds align w/ official builds unless this parameter is true.
+ - name: runCodeQL3000
+ default: false
+ displayName: Run CodeQL3000 tasks
+ type: boolean
+
+variables:
+ - name: _BuildConfig
+ value: Release
+ - name: _TeamName
+ value: AspNetCore
+ - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE
+ value: true
+ - name: _PublishUsingPipelines
+ value: true
+ - name: _CosmosConnectionUrl
+ value: https://localhost:8081
+ - name: _CosmosToken
+ value: C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==
+ - ${{ if or(startswith(variables['Build.SourceBranch'], 'refs/heads/release/'), startswith(variables['Build.SourceBranch'], 'refs/heads/internal/release/'), eq(variables['Build.Reason'], 'Manual')) }}:
+ - name: PostBuildSign
+ value: false
+ - ${{ else }}:
+ - name: PostBuildSign
+ value: true
+ - ${{ if ne(variables['System.TeamProject'], 'public') }}:
+ - group: DotNet-HelixApi-Access
+ - group: DotNetBuilds storage account read tokens
+ - group: AzureDevOps-Artifact-Feeds-Pats
+ - name: _InternalRuntimeDownloadArgs
+ value: /p:DotNetRuntimeSourceFeed=https://dotnetbuilds.blob.core.windows.net/internal
+ /p:DotNetRuntimeSourceFeedKey=$(dotnetbuilds-internal-container-read-token-base64)
+ - ${{ if eq(variables['System.TeamProject'], 'public') }}:
+ - name: _InternalRuntimeDownloadArgs
+ value: ''
+ - name: LC_ALL
+ value: 'en_US.UTF-8'
+ - name: LANG
+ value: 'en_US.UTF-8'
+ - name: LANGUAGE
+ value: 'en_US.UTF-8'
+ - name: runCodeQL3000
+ value: ${{ and(ne(variables['System.TeamProject'], 'public'), or(eq(variables['Build.Reason'], 'Schedule'), and(eq(variables['Build.Reason'], 'Manual'), eq(parameters.runCodeQL3000, 'true')))) }}
+ - template: /eng/common/templates/variables/pool-providers.yml
+
+trigger:
+ batch: true
+ branches:
+ include:
+ - main
+ - release/*
+ - feature/*
+ - internal/release/*
+
+pr: ['*']
+
+stages:
+- stage: build
+ displayName: Build
+ jobs:
+ - template: eng/common/templates/jobs/jobs.yml
+ parameters:
+ enableMicrobuild: ${{ ne(variables.runCodeQL3000, 'true') }}
+ enablePublishBuildArtifacts: true
+ enablePublishBuildAssets: ${{ ne(variables.runCodeQL3000, 'true') }}
+ enablePublishUsingPipelines: ${{ variables._PublishUsingPipelines }}
+ publishAssetsImmediately: true
+ enableSourceIndex: ${{ and(ne(variables['System.TeamProject'], 'public'), eq(variables['Build.SourceBranch'], 'refs/heads/main')) }}
+ enableTelemetry: true
+ helixRepo: dotnet/efcore
+ jobs:
+ - job: Windows
+ enablePublishTestResults: ${{ ne(variables.runCodeQL3000, 'true') }}
+ pool:
+ ${{ if eq(variables['System.TeamProject'], 'public') }}:
+ name: $(DncEngPublicBuildPool)
+ demands: ImageOverride -equals 1es-windows-2019-open
+ ${{ if ne(variables['System.TeamProject'], 'public') }}:
+ name: $(DncEngInternalBuildPool)
+ demands: ImageOverride -equals 1es-windows-2019
+ ${{ if eq(variables.runCodeQL3000, 'true') }}:
+ # Component governance and SBOM creation are not needed here. Disable what Arcade would inject.
+ disableComponentGovernance: true
+ enableSbom: false
+ # CodeQL3000 extends build duration.
+ timeoutInMinutes: 180
+ ${{ else }}:
+ timeoutInMinutes: 90
+ variables:
+ - _InternalBuildArgs: ''
+ # Rely on task Arcade injects, not auto-injected build step.
+ - skipComponentGovernanceDetection: true
+ - ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
+ - _SignType: real
+ - _InternalBuildArgs: /p:DotNetSignType=$(_SignType) /p:TeamName=$(_TeamName) /p:DotNetPublishUsingPipelines=$(_PublishUsingPipelines) /p:OfficialBuildId=$(BUILD.BUILDNUMBER)
+ - ${{ if eq(variables.runCodeQL3000, 'true') }}:
+ - _AdditionalBuildArgs: /p:Test=false /p:Sign=false /p:Pack=false /p:Publish=false /p:UseSharedCompilation=false
+ # Security analysis is included in normal runs. Disable its auto-injection.
+ - skipNugetSecurityAnalysis: true
+ # Do not let CodeQL3000 Extension gate scan frequency.
+ - Codeql.Cadence: 0
+ # Enable CodeQL3000 unconditionally so it may be run on any branch.
+ - Codeql.Enabled: true
+ # Ignore test and infrastructure code.
+ - Codeql.SourceRoot: src
+ # CodeQL3000 needs this plumbed along as a variable to enable TSA.
+ - Codeql.TSAEnabled: ${{ eq(variables['Build.Reason'], 'Schedule') }}
+ # Default expects tsaoptions.json under SourceRoot.
+ - Codeql.TSAOptionsPath: '$(Build.SourcesDirectory)/.config/tsaoptions.json'
+ - ${{ else }}:
+ - _AdditionalBuildArgs: ''
+ steps:
+ - task: NuGetCommand@2
+ displayName: 'Clear NuGet caches'
+ condition: succeeded()
+ inputs:
+ command: custom
+ arguments: 'locals all -clear'
+ - script: "echo ##vso[build.addbuildtag]daily-build"
+ condition: and(notin(variables['Build.Reason'], 'PullRequest'), ne(variables['IsFinalBuild'], 'true'))
+ displayName: 'Set CI tags'
+ - script: "echo ##vso[build.addbuildtag]release-candidate"
+ condition: and(notin(variables['Build.Reason'], 'PullRequest'), eq(variables['IsFinalBuild'], 'true'))
+ displayName: 'Set CI tags'
+ - powershell: SqlLocalDB start
+ displayName: Start LocalDB
+ - ${{ if ne(variables['System.TeamProject'], 'public') }}:
+ - task: PowerShell@2
+ displayName: Setup Private Feeds Credentials
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/common/SetupNugetSources.ps1
+ arguments: -ConfigFile $(Build.SourcesDirectory)/NuGet.config -Password $Env:Token
+ env:
+ Token: $(dn-bot-dnceng-artifact-feeds-rw)
+ - ${{ if eq(variables.runCodeQL3000, 'true') }}:
+ - task: CodeQL3000Init@0
+ displayName: CodeQL Initialize
+ - script: "echo ##vso[build.addbuildtag]CodeQL3000"
+ displayName: 'Set CI CodeQL3000 tag'
+ condition: ne(variables.CODEQL_DIST,'')
+ - script: eng\common\cibuild.cmd -configuration $(_BuildConfig) -prepareMachine $(_InternalBuildArgs)
+ $(_InternalRuntimeDownloadArgs) $(_AdditionalBuildArgs)
+ env:
+ Test__Cosmos__DefaultConnection: $(_CosmosConnectionUrl)
+ name: Build
+ - ${{ if eq(variables.runCodeQL3000, 'true') }}:
+ - task: CodeQL3000Finalize@0
+ displayName: CodeQL Finalize
+ - ${{ else }}:
+ - task: PublishBuildArtifacts@1
+ displayName: Upload TestResults
+ condition: always()
+ continueOnError: true
+ inputs:
+ pathtoPublish: artifacts/TestResults/$(_BuildConfig)/
+ artifactName: $(Agent.Os)_$(Agent.JobName) TestResults
+ artifactType: Container
+ parallel: true
+
+ - ${{ if ne(variables.runCodeQL3000, 'true') }}:
+ - job: macOS
+ enablePublishTestResults: true
+ pool:
+ vmImage: macOS-11
+ variables:
+ # Rely on task Arcade injects, not auto-injected build step.
+ - skipComponentGovernanceDetection: true
+ steps:
+ - ${{ if ne(variables['System.TeamProject'], 'public') }}:
+ - task: Bash@3
+ displayName: Setup Private Feeds Credentials
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/common/SetupNugetSources.sh
+ arguments: $(Build.SourcesDirectory)/NuGet.config $Token
+ env:
+ Token: $(dn-bot-dnceng-artifact-feeds-rw)
+ - script: eng/common/cibuild.sh --configuration $(_BuildConfig) --prepareMachine $(_InternalRuntimeDownloadArgs)
+ env:
+ Test__Cosmos__DefaultConnection: $(_CosmosConnectionUrl)
+ COMPlus_EnableWriteXorExecute: 0 # Work-around for https://github.com/dotnet/runtime/issues/70758
+ name: Build
+ - task: PublishBuildArtifacts@1
+ displayName: Upload TestResults
+ condition: always()
+ continueOnError: true
+ inputs:
+ pathtoPublish: artifacts/TestResults/$(_BuildConfig)/
+ artifactName: $(Agent.Os)_$(Agent.JobName) TestResults
+ artifactType: Container
+ parallel: true
+
+ - job: Linux
+ timeoutInMinutes: 120
+ enablePublishTestResults: true
+ pool:
+ ${{ if or(ne(variables['System.TeamProject'], 'internal'), in(variables['Build.Reason'], 'Manual', 'PullRequest', 'Schedule')) }}:
+ vmImage: ubuntu-22.04
+ ${{ if and(eq(variables['System.TeamProject'], 'internal'), notin(variables['Build.Reason'], 'Manual', 'PullRequest', 'Schedule')) }}:
+ name: $(DncEngInternalBuildPool)
+ demands: ImageOverride -equals Build.Ubuntu.2204.Amd64
+ variables:
+ - _runCounter: $[counter(variables['Build.Reason'], 0)]
+ # Rely on task Arcade injects, not auto-injected build step.
+ - skipComponentGovernanceDetection: true
+ - ${{ if and(eq(variables['System.TeamProject'], 'internal'), notin(variables['Build.Reason'], 'PullRequest', 'Schedule')) }}:
+ - _CosmosConnectionUrl: 'true'
+ steps:
+ - bash: |
+ echo "##vso[task.setvariable variable=_CosmosConnectionUrl]https://ef-nightly-test.documents.azure.com:443/"
+ echo "##vso[task.setvariable variable=_CosmosToken]$(ef-nightly-cosmos-key)"
+ displayName: Prepare to run Cosmos tests on ef-nightly-test
+ condition: and(eq(variables['_CosmosConnectionUrl'], 'true'), or(endsWith(variables['_runCounter'], '0'), endsWith(variables['_runCounter'], '2'), endsWith(variables['_runCounter'], '4'), endsWith(variables['_runCounter'], '6'), endsWith(variables['_runCounter'], '8')))
+ - bash: |
+ echo "##vso[task.setvariable variable=_CosmosConnectionUrl]https://ef-pr-test.documents.azure.com:443/"
+ echo "##vso[task.setvariable variable=_CosmosToken]$(ef-pr-cosmos-test)"
+ displayName: Prepare to run Cosmos tests on ef-pr-test
+ condition: and(eq(variables['_CosmosConnectionUrl'], 'true'), or(endsWith(variables['_runCounter'], '1'), endsWith(variables['_runCounter'], '3'), endsWith(variables['_runCounter'], '5'), endsWith(variables['_runCounter'], '7'), endsWith(variables['_runCounter'], '9')))
+ - ${{ if ne(variables['System.TeamProject'], 'public') }}:
+ - task: Bash@3
+ displayName: Setup Private Feeds Credentials
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/common/SetupNugetSources.sh
+ arguments: $(Build.SourcesDirectory)/NuGet.config $Token
+ env:
+ Token: $(dn-bot-dnceng-artifact-feeds-rw)
+ - script: eng/common/cibuild.sh --configuration $(_BuildConfig) --prepareMachine $(_InternalRuntimeDownloadArgs)
+ env:
+ Test__Cosmos__DefaultConnection: $(_CosmosConnectionUrl)
+ Test__Cosmos__AuthToken: $(_CosmosToken)
+ name: Build
+ - task: PublishBuildArtifacts@1
+ displayName: Upload TestResults
+ condition: always()
+ continueOnError: true
+ inputs:
+ pathtoPublish: artifacts/TestResults/$(_BuildConfig)/
+ artifactName: $(Agent.Os)_$(Agent.JobName) TestResults
+ artifactType: Container
+ parallel: true
+
+ - job: Helix
+ timeoutInMinutes: 180
+ pool:
+ ${{ if eq(variables['System.TeamProject'], 'public') }}:
+ name: $(DncEngPublicBuildPool)
+ demands: ImageOverride -equals 1es-windows-2019-open
+ ${{ if ne(variables['System.TeamProject'], 'public') }}:
+ name: $(DncEngInternalBuildPool)
+ demands: ImageOverride -equals 1es-windows-2019
+ variables:
+ # Rely on task Arcade injects, not auto-injected build step.
+ - skipComponentGovernanceDetection: true
+ - name: _HelixBuildConfig
+ value: $(_BuildConfig)
+ - ${{ if eq(variables['System.TeamProject'], 'public') }}:
+ - name: HelixTargetQueues
+ value: OSX.1100.Amd64.Open;(Ubuntu.2004.Amd64.SqlServer)Ubuntu.2004.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-20.04-helix-sqlserver-amd64
+ - name: _HelixAccessToken
+ value: '' # Needed for public queues
+ - ${{ if ne(variables['System.TeamProject'], 'public') }}:
+ - name: HelixTargetQueues
+ value: OSX.1100.Amd64;(Ubuntu.2004.Amd64.SqlServer)Ubuntu.2004.Amd64@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-20.04-helix-sqlserver-amd64
+ - name: _HelixAccessToken
+ value: $(HelixApiAccessToken) # Needed for internal queues
+ steps:
+ - task: NuGetCommand@2
+ displayName: 'Clear NuGet caches'
+ condition: succeeded()
+ inputs:
+ command: custom
+ arguments: 'locals all -clear'
+ - ${{ if ne(variables['System.TeamProject'], 'public') }}:
+ - task: PowerShell@2
+ displayName: Setup Private Feeds Credentials
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/common/SetupNugetSources.ps1
+ arguments: -ConfigFile $(Build.SourcesDirectory)/NuGet.config -Password $Env:Token
+ env:
+ Token: $(dn-bot-dnceng-artifact-feeds-rw)
+ - script: restore.cmd -ci /p:configuration=$(_BuildConfig) $(_InternalRuntimeDownloadArgs)
+ displayName: Restore packages
+ - script: .dotnet\dotnet build eng\helix.proj /restore /t:Test /p:configuration=$(_BuildConfig) /bl:$(Build.SourcesDirectory)/artifacts/log/$(_BuildConfig)/SendToHelix.binlog $(_InternalRuntimeDownloadArgs)
+ displayName: Send job to helix
+ env:
+ HelixAccessToken: $(_HelixAccessToken)
+ SYSTEM_ACCESSTOKEN: $(System.AccessToken) # We need to set this env var to publish helix results to Azure Dev Ops
+ MSSQL_SA_PASSWORD: "Password12!"
+ COMPlus_EnableWriteXorExecute: 0 # Work-around for https://github.com/dotnet/runtime/issues/70758
+ DotNetBuildsInternalReadSasToken: $(dotnetbuilds-internal-container-read-token)
+
+- ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest'), ne(variables.runCodeQL3000, 'true')) }}:
+ - template: eng\common\templates\post-build\post-build.yml
+ parameters:
+ publishingInfraVersion: 3
+ # Symbol validation isn't being very reliable lately. This should be enabled back
+ # once this issue is resolved: https://github.com/dotnet/arcade/issues/2871
+ enableSymbolValidation: false
+ enableSigningValidation: false
+ enableNugetValidation: false
+ enableSourceLinkValidation: false
+ publishAssetsImmediately: true
From 94783a1056a3377b18887346f5948d05497c16f7 Mon Sep 17 00:00:00 2001
From: Andriy Svyryd
Date: Tue, 5 Mar 2024 16:24:27 -0800
Subject: [PATCH 09/22] [release/7.0] Split public pipeline definition (#33252)
---
azure-pipelines-public.yml | 313 +++++++++++++++++++++++++++++++++++++
1 file changed, 313 insertions(+)
create mode 100644 azure-pipelines-public.yml
diff --git a/azure-pipelines-public.yml b/azure-pipelines-public.yml
new file mode 100644
index 00000000000..c9f593a3d86
--- /dev/null
+++ b/azure-pipelines-public.yml
@@ -0,0 +1,313 @@
+schedules:
+- cron: 0 9 * * 1
+ displayName: "Run CodeQL3000 weekly, Monday at 2:00 AM PDT"
+ branches:
+ include:
+ - release/2.1
+ - release/6.0
+ - release/7.0
+ - main
+ always: true
+
+parameters:
+ # Parameter below is ignored in public builds.
+ #
+ # Choose whether to run the CodeQL3000 tasks.
+ # Manual builds align w/ official builds unless this parameter is true.
+ - name: runCodeQL3000
+ default: false
+ displayName: Run CodeQL3000 tasks
+ type: boolean
+
+variables:
+ - name: _BuildConfig
+ value: Release
+ - name: _TeamName
+ value: AspNetCore
+ - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE
+ value: true
+ - name: _PublishUsingPipelines
+ value: true
+ - name: _CosmosConnectionUrl
+ value: https://localhost:8081
+ - name: _CosmosToken
+ value: C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==
+ - ${{ if or(startswith(variables['Build.SourceBranch'], 'refs/heads/release/'), startswith(variables['Build.SourceBranch'], 'refs/heads/internal/release/'), eq(variables['Build.Reason'], 'Manual')) }}:
+ - name: PostBuildSign
+ value: false
+ - ${{ else }}:
+ - name: PostBuildSign
+ value: true
+ - ${{ if ne(variables['System.TeamProject'], 'public') }}:
+ - group: DotNet-HelixApi-Access
+ - group: DotNetBuilds storage account read tokens
+ - group: AzureDevOps-Artifact-Feeds-Pats
+ - name: _InternalRuntimeDownloadArgs
+ value: /p:DotNetRuntimeSourceFeed=https://dotnetbuilds.blob.core.windows.net/internal
+ /p:DotNetRuntimeSourceFeedKey=$(dotnetbuilds-internal-container-read-token-base64)
+ - ${{ if eq(variables['System.TeamProject'], 'public') }}:
+ - name: _InternalRuntimeDownloadArgs
+ value: ''
+ - name: LC_ALL
+ value: 'en_US.UTF-8'
+ - name: LANG
+ value: 'en_US.UTF-8'
+ - name: LANGUAGE
+ value: 'en_US.UTF-8'
+ - name: runCodeQL3000
+ value: ${{ and(ne(variables['System.TeamProject'], 'public'), or(eq(variables['Build.Reason'], 'Schedule'), and(eq(variables['Build.Reason'], 'Manual'), eq(parameters.runCodeQL3000, 'true')))) }}
+
+trigger:
+ batch: true
+ branches:
+ include:
+ - main
+ - release/*
+ - feature/*
+ - internal/release/*
+
+pr: ['*']
+
+stages:
+- stage: build
+ displayName: Build
+ jobs:
+ - template: eng/common/templates/jobs/jobs.yml
+ parameters:
+ enableMicrobuild: ${{ ne(variables.runCodeQL3000, 'true') }}
+ enablePublishBuildArtifacts: true
+ enablePublishBuildAssets: ${{ ne(variables.runCodeQL3000, 'true') }}
+ enablePublishUsingPipelines: ${{ variables._PublishUsingPipelines }}
+ enableTelemetry: true
+ helixRepo: dotnet/efcore
+ jobs:
+ - job: Windows
+ enablePublishTestResults: ${{ ne(variables.runCodeQL3000, 'true') }}
+ pool:
+ ${{ if eq(variables['System.TeamProject'], 'public') }}:
+ name: NetCore-Svc-Public
+ demands: ImageOverride -equals 1es-windows-2019-open
+ ${{ if ne(variables['System.TeamProject'], 'public') }}:
+ name: NetCore1ESPool-Svc-Internal
+ demands: ImageOverride -equals 1es-windows-2019
+ ${{ if eq(variables.runCodeQL3000, 'true') }}:
+ # Component governance and SBOM creation are not needed here. Disable what Arcade would inject.
+ disableComponentGovernance: true
+ enableSbom: false
+ # CodeQL3000 extends build duration.
+ timeoutInMinutes: 180
+ ${{ else }}:
+ timeoutInMinutes: 90
+ variables:
+ - _InternalBuildArgs: ''
+ # Rely on task Arcade injects, not auto-injected build step.
+ - skipComponentGovernanceDetection: true
+ - ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
+ - _SignType: real
+ - _InternalBuildArgs: /p:DotNetSignType=$(_SignType) /p:TeamName=$(_TeamName) /p:DotNetPublishUsingPipelines=$(_PublishUsingPipelines) /p:OfficialBuildId=$(BUILD.BUILDNUMBER)
+ - ${{ if eq(variables.runCodeQL3000, 'true') }}:
+ - _AdditionalBuildArgs: /p:Test=false /p:Sign=false /p:Pack=false /p:Publish=false /p:UseSharedCompilation=false
+ # Security analysis is included in normal runs. Disable its auto-injection.
+ - skipNugetSecurityAnalysis: true
+ # Do not let CodeQL3000 Extension gate scan frequency.
+ - Codeql.Cadence: 0
+ # Enable CodeQL3000 unconditionally so it may be run on any branch.
+ - Codeql.Enabled: true
+ # Ignore test and infrastructure code.
+ - Codeql.SourceRoot: src
+ # CodeQL3000 needs this plumbed along as a variable to enable TSA.
+ - Codeql.TSAEnabled: ${{ eq(variables['Build.Reason'], 'Schedule') }}
+ # Default expects tsaoptions.json under SourceRoot.
+ - Codeql.TSAOptionsPath: '$(Build.SourcesDirectory)/.config/tsaoptions.json'
+ steps:
+ - task: NuGetCommand@2
+ displayName: 'Clear NuGet caches'
+ condition: succeeded()
+ inputs:
+ command: custom
+ arguments: 'locals all -clear'
+ - script: "echo ##vso[build.addbuildtag]daily-build"
+ condition: and(notin(variables['Build.Reason'], 'PullRequest'), ne(variables['IsFinalBuild'], 'true'))
+ displayName: 'Set CI tags'
+ - script: "echo ##vso[build.addbuildtag]release-candidate"
+ condition: and(notin(variables['Build.Reason'], 'PullRequest'), eq(variables['IsFinalBuild'], 'true'))
+ displayName: 'Set CI tags'
+ - powershell: SqlLocalDB start
+ displayName: Start LocalDB
+ - ${{ if ne(variables['System.TeamProject'], 'public') }}:
+ - task: PowerShell@2
+ displayName: Setup Private Feeds Credentials
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/common/SetupNugetSources.ps1
+ arguments: -ConfigFile $(Build.SourcesDirectory)/NuGet.config -Password $Env:Token
+ env:
+ Token: $(dn-bot-dnceng-artifact-feeds-rw)
+ - ${{ if eq(variables.runCodeQL3000, 'true') }}:
+ - task: CodeQL3000Init@0
+ displayName: CodeQL Initialize
+ - script: "echo ##vso[build.addbuildtag]CodeQL3000"
+ displayName: 'Set CI CodeQL3000 tag'
+ condition: ne(variables.CODEQL_DIST,'')
+ - script: eng\common\cibuild.cmd -configuration $(_BuildConfig) -prepareMachine $(_InternalBuildArgs)
+ $(_InternalRuntimeDownloadArgs) $(_AdditionalBuildArgs)
+ env:
+ Test__Cosmos__DefaultConnection: $(_CosmosConnectionUrl)
+ name: Build
+ - ${{ if eq(variables.runCodeQL3000, 'true') }}:
+ - task: CodeQL3000Finalize@0
+ displayName: CodeQL Finalize
+ - ${{ else }}:
+ - script: |
+ .dotnet\dotnet publish --configuration $(_BuildConfig) --runtime win-x64 --self-contained test\EFCore.Trimming.Tests
+ artifacts\bin\EFCore.Trimming.Tests\$(_BuildConfig)\net7.0\win-x64\publish\EFCore.Trimming.Tests.exe
+ displayName: Test trimming
+ - task: PublishBuildArtifacts@1
+ displayName: Upload TestResults
+ condition: always()
+ continueOnError: true
+ inputs:
+ pathtoPublish: artifacts/TestResults/$(_BuildConfig)/
+ artifactName: $(Agent.Os)_$(Agent.JobName) TestResults
+ artifactType: Container
+ parallel: true
+
+ - ${{ if ne(variables.runCodeQL3000, 'true') }}:
+ - job: macOS
+ enablePublishTestResults: true
+ pool:
+ vmImage: macOS-11
+ variables:
+ # Rely on task Arcade injects, not auto-injected build step.
+ - skipComponentGovernanceDetection: true
+ steps:
+ - ${{ if ne(variables['System.TeamProject'], 'public') }}:
+ - task: Bash@3
+ displayName: Setup Private Feeds Credentials
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/common/SetupNugetSources.sh
+ arguments: $(Build.SourcesDirectory)/NuGet.config $Token
+ env:
+ Token: $(dn-bot-dnceng-artifact-feeds-rw)
+ - script: eng/common/cibuild.sh --configuration $(_BuildConfig) --prepareMachine $(_InternalRuntimeDownloadArgs)
+ env:
+ Test__Cosmos__DefaultConnection: $(_CosmosConnectionUrl)
+ COMPlus_EnableWriteXorExecute: 0 # Work-around for https://github.com/dotnet/runtime/issues/70758
+ name: Build
+ - task: PublishBuildArtifacts@1
+ displayName: Upload TestResults
+ condition: always()
+ continueOnError: true
+ inputs:
+ pathtoPublish: artifacts/TestResults/$(_BuildConfig)/
+ artifactName: $(Agent.Os)_$(Agent.JobName) TestResults
+ artifactType: Container
+ parallel: true
+
+ - job: Linux
+ timeoutInMinutes: 120
+ enablePublishTestResults: true
+ pool:
+ ${{ if or(ne(variables['System.TeamProject'], 'internal'), in(variables['Build.Reason'], 'Manual', 'PullRequest', 'Schedule')) }}:
+ vmImage: ubuntu-22.04
+ ${{ if and(eq(variables['System.TeamProject'], 'internal'), notin(variables['Build.Reason'], 'Manual', 'PullRequest', 'Schedule')) }}:
+ name: NetCore1ESPool-Svc-Internal
+ demands: ImageOverride -equals Build.Ubuntu.2004.Amd64
+ variables:
+ - _runCounter: $[counter(variables['Build.Reason'], 0)]
+ # Rely on task Arcade injects, not auto-injected build step.
+ - skipComponentGovernanceDetection: true
+ - ${{ if and(eq(variables['System.TeamProject'], 'internal'), notin(variables['Build.Reason'], 'PullRequest', 'Schedule')) }}:
+ - _CosmosConnectionUrl: 'true'
+ steps:
+ - bash: |
+ echo "##vso[task.setvariable variable=_CosmosConnectionUrl]https://ef-nightly-test.documents.azure.com:443/"
+ echo "##vso[task.setvariable variable=_CosmosToken]$(ef-nightly-cosmos-key)"
+ displayName: Prepare to run Cosmos tests on ef-nightly-test
+ condition: and(eq(variables['_CosmosConnectionUrl'], 'true'), or(endsWith(variables['_runCounter'], '0'), endsWith(variables['_runCounter'], '2'), endsWith(variables['_runCounter'], '4'), endsWith(variables['_runCounter'], '6'), endsWith(variables['_runCounter'], '8')))
+ - bash: |
+ echo "##vso[task.setvariable variable=_CosmosConnectionUrl]https://ef-pr-test.documents.azure.com:443/"
+ echo "##vso[task.setvariable variable=_CosmosToken]$(ef-pr-cosmos-test)"
+ displayName: Prepare to run Cosmos tests on ef-pr-test
+ condition: and(eq(variables['_CosmosConnectionUrl'], 'true'), or(endsWith(variables['_runCounter'], '1'), endsWith(variables['_runCounter'], '3'), endsWith(variables['_runCounter'], '5'), endsWith(variables['_runCounter'], '7'), endsWith(variables['_runCounter'], '9')))
+ - ${{ if ne(variables['System.TeamProject'], 'public') }}:
+ - task: Bash@3
+ displayName: Setup Private Feeds Credentials
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/common/SetupNugetSources.sh
+ arguments: $(Build.SourcesDirectory)/NuGet.config $Token
+ env:
+ Token: $(dn-bot-dnceng-artifact-feeds-rw)
+ - script: eng/common/cibuild.sh --configuration $(_BuildConfig) --prepareMachine $(_InternalRuntimeDownloadArgs)
+ env:
+ Test__Cosmos__DefaultConnection: $(_CosmosConnectionUrl)
+ Test__Cosmos__AuthToken: $(_CosmosToken)
+ name: Build
+ - task: PublishBuildArtifacts@1
+ displayName: Upload TestResults
+ condition: always()
+ continueOnError: true
+ inputs:
+ pathtoPublish: artifacts/TestResults/$(_BuildConfig)/
+ artifactName: $(Agent.Os)_$(Agent.JobName) TestResults
+ artifactType: Container
+ parallel: true
+
+ - job: Helix
+ timeoutInMinutes: 180
+ pool:
+ ${{ if eq(variables['System.TeamProject'], 'public') }}:
+ name: NetCore-Svc-Public
+ demands: ImageOverride -equals 1es-windows-2019-open
+ ${{ if ne(variables['System.TeamProject'], 'public') }}:
+ name: NetCore1ESPool-Svc-Internal
+ demands: ImageOverride -equals 1es-windows-2019
+ variables:
+ # Rely on task Arcade injects, not auto-injected build step.
+ - skipComponentGovernanceDetection: true
+ - name: _HelixBuildConfig
+ value: $(_BuildConfig)
+ - ${{ if eq(variables['System.TeamProject'], 'public') }}:
+ - name: HelixTargetQueues
+ value: OSX.1100.Amd64.Open;(Ubuntu.2004.Amd64.SqlServer)Ubuntu.2004.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-helix-sqlserver-amd64
+ - name: _HelixAccessToken
+ value: '' # Needed for public queues
+ - ${{ if ne(variables['System.TeamProject'], 'public') }}:
+ - name: HelixTargetQueues
+ value: OSX.1100.Amd64;(Ubuntu.2004.Amd64.SqlServer)Ubuntu.2004.Amd64@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-helix-sqlserver-amd64
+ - name: _HelixAccessToken
+ value: $(HelixApiAccessToken) # Needed for internal queues
+ steps:
+ - task: NuGetCommand@2
+ displayName: 'Clear NuGet caches'
+ condition: succeeded()
+ inputs:
+ command: custom
+ arguments: 'locals all -clear'
+ - ${{ if ne(variables['System.TeamProject'], 'public') }}:
+ - task: PowerShell@2
+ displayName: Setup Private Feeds Credentials
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/common/SetupNugetSources.ps1
+ arguments: -ConfigFile $(Build.SourcesDirectory)/NuGet.config -Password $Env:Token
+ env:
+ Token: $(dn-bot-dnceng-artifact-feeds-rw)
+ - script: restore.cmd -ci /p:configuration=$(_BuildConfig)
+ displayName: Restore packages
+ - script: .dotnet\dotnet build eng\helix.proj /restore /t:Test /p:configuration=$(_BuildConfig) /bl:$(Build.SourcesDirectory)/artifacts/log/$(_BuildConfig)/SendToHelix.binlog
+ displayName: Send job to helix
+ env:
+ HelixAccessToken: $(_HelixAccessToken)
+ SYSTEM_ACCESSTOKEN: $(System.AccessToken) # We need to set this env var to publish helix results to Azure Dev Ops
+ MSSQL_SA_PASSWORD: "Password12!"
+ COMPlus_EnableWriteXorExecute: 0 # Work-around for https://github.com/dotnet/runtime/issues/70758
+
+- ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest'), ne(variables.runCodeQL3000, 'true')) }}:
+ - template: eng\common\templates\post-build\post-build.yml
+ parameters:
+ publishingInfraVersion: 3
+ # Symbol validation isn't being very reliable lately. This should be enabled back
+ # once this issue is resolved: https://github.com/dotnet/arcade/issues/2871
+ enableSymbolValidation: false
+ enableSigningValidation: false
+ enableNugetValidation: false
+ enableSourceLinkValidation: false
From dc10fef1913e7acee2c769b8013b2a8a4fa60145 Mon Sep 17 00:00:00 2001
From: Andriy Svyryd
Date: Tue, 5 Mar 2024 16:24:30 -0800
Subject: [PATCH 10/22] [release/6.0] Split public pipeline definition (#33253)
---
azure-pipelines-public.yml | 307 +++++++++++++++++++++++++++++++++++++
1 file changed, 307 insertions(+)
create mode 100644 azure-pipelines-public.yml
diff --git a/azure-pipelines-public.yml b/azure-pipelines-public.yml
new file mode 100644
index 00000000000..220954a623d
--- /dev/null
+++ b/azure-pipelines-public.yml
@@ -0,0 +1,307 @@
+schedules:
+- cron: 0 9 * * 1
+ displayName: "Run CodeQL3000 weekly, Monday at 2:00 AM PDT"
+ branches:
+ include:
+ - release/2.1
+ - release/6.0
+ - release/7.0
+ - main
+ always: true
+
+parameters:
+ # Parameter below is ignored in public builds.
+ #
+ # Choose whether to run the CodeQL3000 tasks.
+ # Manual builds align w/ official builds unless this parameter is true.
+ - name: runCodeQL3000
+ default: false
+ displayName: Run CodeQL3000 tasks
+ type: boolean
+
+variables:
+ - name: _BuildConfig
+ value: Release
+ - name: _TeamName
+ value: AspNetCore
+ - name: DOTNET_SKIP_FIRST_TIME_EXPERIENCE
+ value: true
+ - name: _PublishUsingPipelines
+ value: true
+ - name: _DotNetArtifactsCategory
+ value: ENTITYFRAMEWORKCORE
+ - name: _CosmosConnectionUrl
+ value: https://localhost:8081
+ - name: _CosmosToken
+ value: C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==
+ - name: PostBuildSign
+ value: true
+ - ${{ if ne(variables['System.TeamProject'], 'public') }}:
+ - group: DotNet-HelixApi-Access
+ - group: DotNet-MSRC-Storage
+ - name: _InternalRuntimeDownloadArgs
+ value: /p:DotNetRuntimeSourceFeed=https://dotnetclimsrc.blob.core.windows.net/dotnet
+ /p:DotNetRuntimeSourceFeedKey=$(dotnetclimsrc-read-sas-token-base64)
+ - ${{ if eq(variables['System.TeamProject'], 'public') }}:
+ - name: _InternalRuntimeDownloadArgs
+ value: ''
+ - name: LC_ALL
+ value: 'en_US.UTF-8'
+ - name: LANG
+ value: 'en_US.UTF-8'
+ - name: LANGUAGE
+ value: 'en_US.UTF-8'
+ - name: runCodeQL3000
+ value: ${{ and(ne(variables['System.TeamProject'], 'public'), or(eq(variables['Build.Reason'], 'Schedule'), and(eq(variables['Build.Reason'], 'Manual'), eq(parameters.runCodeQL3000, 'true')))) }}
+
+trigger:
+ batch: true
+ branches:
+ include:
+ - main
+ - release/*
+ - feature/*
+ - internal/release/*
+
+pr: ['*']
+
+stages:
+- stage: build
+ displayName: Build
+ jobs:
+ - template: eng/common/templates/jobs/jobs.yml
+ parameters:
+ enableMicrobuild: ${{ ne(variables.runCodeQL3000, 'true') }}
+ enablePublishBuildArtifacts: true
+ enablePublishBuildAssets: ${{ ne(variables.runCodeQL3000, 'true') }}
+ enablePublishUsingPipelines: ${{ variables._PublishUsingPipelines }}
+ enableTelemetry: true
+ helixRepo: dotnet/efcore
+ jobs:
+ - job: Windows
+ enablePublishTestResults: ${{ ne(variables.runCodeQL3000, 'true') }}
+ pool:
+ ${{ if eq(variables['System.TeamProject'], 'public') }}:
+ name: NetCore-Svc-Public
+ demands: ImageOverride -equals windows.vs2019.amd64.open
+ ${{ if ne(variables['System.TeamProject'], 'public') }}:
+ name: NetCore1ESPool-Svc-Internal
+ demands: ImageOverride -equals windows.vs2019.amd64
+ ${{ if eq(variables.runCodeQL3000, 'true') }}:
+ # Component governance and SBOM creation are not needed here. Disable what Arcade would inject.
+ disableComponentGovernance: true
+ enableSbom: false
+ # CodeQL3000 extends build duration.
+ timeoutInMinutes: 180
+ ${{ else }}:
+ timeoutInMinutes: 90
+ variables:
+ - _InternalBuildArgs: ''
+ # Rely on task Arcade injects, not auto-injected build step.
+ - skipComponentGovernanceDetection: true
+ - ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
+ - group: DotNet-Blob-Feed
+ - _SignType: real
+ - _PublishBlobFeedUrl: https://dotnetfeed.blob.core.windows.net/aspnet-entityframeworkcore/index.json
+ - _DotNetPublishToBlobFeed: true
+ - _InternalBuildArgs: /p:DotNetSignType=$(_SignType) /p:TeamName=$(_TeamName) /p:DotNetPublishBlobFeedKey=$(dotnetfeed-storage-access-key-1) /p:DotNetPublishBlobFeedUrl=$(_PublishBlobFeedUrl) /p:DotNetPublishToBlobFeed=$(_DotNetPublishToBlobFeed) /p:DotNetPublishUsingPipelines=$(_PublishUsingPipelines) /p:DotNetArtifactsCategory=$(_DotNetArtifactsCategory) /p:OfficialBuildId=$(BUILD.BUILDNUMBER)
+ - ${{ if eq(variables.runCodeQL3000, 'true') }}:
+ - _AdditionalBuildArgs: /p:Test=false /p:Sign=false /p:Pack=false /p:Publish=false /p:UseSharedCompilation=false
+ # Security analysis is included in normal runs. Disable its auto-injection.
+ - skipNugetSecurityAnalysis: true
+ # Do not let CodeQL3000 Extension gate scan frequency.
+ - Codeql.Cadence: 0
+ # Enable CodeQL3000 unconditionally so it may be run on any branch.
+ - Codeql.Enabled: true
+ # Ignore test and infrastructure code.
+ - Codeql.SourceRoot: src
+ # CodeQL3000 needs this plumbed along as a variable to enable TSA.
+ - Codeql.TSAEnabled: ${{ eq(variables['Build.Reason'], 'Schedule') }}
+ # Default expects tsaoptions.json under SourceRoot.
+ - Codeql.TSAOptionsPath: '$(Build.SourcesDirectory)/.config/tsaoptions.json'
+ steps:
+ - task: NuGetCommand@2
+ displayName: 'Clear NuGet caches'
+ condition: succeeded()
+ inputs:
+ command: custom
+ arguments: 'locals all -clear'
+ - script: "echo ##vso[build.addbuildtag]daily-build"
+ condition: and(notin(variables['Build.Reason'], 'PullRequest'), ne(variables['IsFinalBuild'], 'true'))
+ displayName: 'Set CI tags'
+ - script: "echo ##vso[build.addbuildtag]release-candidate"
+ condition: and(notin(variables['Build.Reason'], 'PullRequest'), eq(variables['IsFinalBuild'], 'true'))
+ displayName: 'Set CI tags'
+ - powershell: SqlLocalDB start
+ displayName: Start LocalDB
+ - ${{ if ne(variables['System.TeamProject'], 'public') }}:
+ - task: PowerShell@2
+ displayName: Setup Private Feeds Credentials
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/common/SetupNugetSources.ps1
+ arguments: -ConfigFile $(Build.SourcesDirectory)/NuGet.config -Password $Env:Token
+ env:
+ Token: $(dn-bot-dnceng-artifact-feeds-rw)
+ - ${{ if eq(variables.runCodeQL3000, 'true') }}:
+ - task: CodeQL3000Init@0
+ displayName: CodeQL Initialize
+ - script: "echo ##vso[build.addbuildtag]CodeQL3000"
+ displayName: 'Set CI CodeQL3000 tag'
+ condition: ne(variables.CODEQL_DIST,'')
+ - script: eng\common\cibuild.cmd -configuration $(_BuildConfig) -prepareMachine $(_InternalBuildArgs)
+ $(_InternalRuntimeDownloadArgs) $(_AdditionalBuildArgs)
+ env:
+ Test__Cosmos__DefaultConnection: $(_CosmosConnectionUrl)
+ name: Build
+ - ${{ if eq(variables.runCodeQL3000, 'true') }}:
+ - task: CodeQL3000Finalize@0
+ displayName: CodeQL Finalize
+ - ${{ else }}:
+ - task: PublishBuildArtifacts@1
+ displayName: Upload TestResults
+ condition: always()
+ continueOnError: true
+ inputs:
+ pathtoPublish: artifacts/TestResults/$(_BuildConfig)/
+ artifactName: $(Agent.Os)_$(Agent.JobName) TestResults
+ artifactType: Container
+ parallel: true
+
+ - ${{ if ne(variables.runCodeQL3000, 'true') }}:
+ - job: macOS
+ enablePublishTestResults: true
+ pool:
+ vmImage: macOS-11
+ variables:
+ # Rely on task Arcade injects, not auto-injected build step.
+ - skipComponentGovernanceDetection: true
+ steps:
+ - ${{ if ne(variables['System.TeamProject'], 'public') }}:
+ - task: Bash@3
+ displayName: Setup Private Feeds Credentials
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/common/SetupNugetSources.sh
+ arguments: $(Build.SourcesDirectory)/NuGet.config $Token
+ env:
+ Token: $(dn-bot-dnceng-artifact-feeds-rw)
+ - script: eng/common/cibuild.sh --configuration $(_BuildConfig) --prepareMachine $(_InternalRuntimeDownloadArgs)
+ env:
+ Test__Cosmos__DefaultConnection: $(_CosmosConnectionUrl)
+ name: Build
+ - task: PublishBuildArtifacts@1
+ displayName: Upload TestResults
+ condition: always()
+ continueOnError: true
+ inputs:
+ pathtoPublish: artifacts/TestResults/$(_BuildConfig)/
+ artifactName: $(Agent.Os)_$(Agent.JobName) TestResults
+ artifactType: Container
+ parallel: true
+
+ - job: Linux
+ timeoutInMinutes: 120
+ enablePublishTestResults: true
+ pool:
+ ${{ if or(ne(variables['System.TeamProject'], 'internal'), in(variables['Build.Reason'], 'Manual', 'PullRequest', 'Schedule')) }}:
+ vmImage: ubuntu-22.04
+ ${{ if and(eq(variables['System.TeamProject'], 'internal'), notin(variables['Build.Reason'], 'Manual', 'PullRequest', 'Schedule')) }}:
+ name: NetCore1ESPool-Svc-Internal
+ demands: ImageOverride -equals Build.Ubuntu.2004.Amd64
+ variables:
+ - _runCounter: $[counter(variables['Build.Reason'], 0)]
+ # Rely on task Arcade injects, not auto-injected build step.
+ - skipComponentGovernanceDetection: true
+ - ${{ if and(eq(variables['System.TeamProject'], 'internal'), notin(variables['Build.Reason'], 'PullRequest', 'Schedule')) }}:
+ - _CosmosConnectionUrl: 'true'
+ steps:
+ - bash: |
+ echo "##vso[task.setvariable variable=_CosmosConnectionUrl]https://ef-nightly-test.documents.azure.com:443/"
+ echo "##vso[task.setvariable variable=_CosmosToken]$(ef-nightly-cosmos-key)"
+ displayName: Prepare to run Cosmos tests on ef-nightly-test
+ condition: and(eq(variables['_CosmosConnectionUrl'], 'true'), or(endsWith(variables['_runCounter'], '0'), endsWith(variables['_runCounter'], '2'), endsWith(variables['_runCounter'], '4'), endsWith(variables['_runCounter'], '6'), endsWith(variables['_runCounter'], '8')))
+ - bash: |
+ echo "##vso[task.setvariable variable=_CosmosConnectionUrl]https://ef-pr-test.documents.azure.com:443/"
+ echo "##vso[task.setvariable variable=_CosmosToken]$(ef-pr-cosmos-test)"
+ displayName: Prepare to run Cosmos tests on ef-pr-test
+ condition: and(eq(variables['_CosmosConnectionUrl'], 'true'), or(endsWith(variables['_runCounter'], '1'), endsWith(variables['_runCounter'], '3'), endsWith(variables['_runCounter'], '5'), endsWith(variables['_runCounter'], '7'), endsWith(variables['_runCounter'], '9')))
+ - ${{ if ne(variables['System.TeamProject'], 'public') }}:
+ - task: Bash@3
+ displayName: Setup Private Feeds Credentials
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/common/SetupNugetSources.sh
+ arguments: $(Build.SourcesDirectory)/NuGet.config $Token
+ env:
+ Token: $(dn-bot-dnceng-artifact-feeds-rw)
+ - script: eng/common/cibuild.sh --configuration $(_BuildConfig) --prepareMachine $(_InternalRuntimeDownloadArgs)
+ env:
+ Test__Cosmos__DefaultConnection: $(_CosmosConnectionUrl)
+ Test__Cosmos__AuthToken: $(_CosmosToken)
+ name: Build
+ - task: PublishBuildArtifacts@1
+ displayName: Upload TestResults
+ condition: always()
+ continueOnError: true
+ inputs:
+ pathtoPublish: artifacts/TestResults/$(_BuildConfig)/
+ artifactName: $(Agent.Os)_$(Agent.JobName) TestResults
+ artifactType: Container
+ parallel: true
+
+ - job: Helix
+ timeoutInMinutes: 180
+ pool:
+ ${{ if eq(variables['System.TeamProject'], 'public') }}:
+ name: NetCore-Svc-Public
+ demands: ImageOverride -equals windows.vs2019.amd64.open
+ ${{ if ne(variables['System.TeamProject'], 'public') }}:
+ name: NetCore1ESPool-Svc-Internal
+ demands: ImageOverride -equals windows.vs2019.amd64
+ variables:
+ # Rely on task Arcade injects, not auto-injected build step.
+ - skipComponentGovernanceDetection: true
+ - name: _HelixBuildConfig
+ value: $(_BuildConfig)
+ - ${{ if eq(variables['System.TeamProject'], 'public') }}:
+ - name: HelixTargetQueues
+ value: Windows.10.Amd64.Open;Ubuntu.2004.Amd64.Open;OSX.1100.Amd64.Open;Ubuntu.2004.Amd64.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-helix-sqlserver-amd64
+ - name: _HelixAccessToken
+ value: '' # Needed for public queues
+ - ${{ if ne(variables['System.TeamProject'], 'public') }}:
+ - name: HelixTargetQueues
+ value: Windows.10.Amd64;Ubuntu.2004.Amd64;OSX.1100.Amd64;Ubuntu.2004.Amd64@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-helix-sqlserver-amd64
+ - name: _HelixAccessToken
+ value: $(HelixApiAccessToken) # Needed for internal queues
+ steps:
+ - task: NuGetCommand@2
+ displayName: 'Clear NuGet caches'
+ condition: succeeded()
+ inputs:
+ command: custom
+ arguments: 'locals all -clear'
+ - ${{ if ne(variables['System.TeamProject'], 'public') }}:
+ - task: PowerShell@2
+ displayName: Setup Private Feeds Credentials
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/common/SetupNugetSources.ps1
+ arguments: -ConfigFile $(Build.SourcesDirectory)/NuGet.config -Password $Env:Token
+ env:
+ Token: $(dn-bot-dnceng-artifact-feeds-rw)
+ - script: restore.cmd -ci /p:configuration=$(_BuildConfig)
+ displayName: Restore packages
+ - script: .dotnet\dotnet build eng\helix.proj /restore /t:Test /p:configuration=$(_BuildConfig) /bl:$(Build.SourcesDirectory)/artifacts/log/$(_BuildConfig)/SendToHelix.binlog
+ displayName: Send job to helix
+ env:
+ HelixAccessToken: $(_HelixAccessToken)
+ SYSTEM_ACCESSTOKEN: $(System.AccessToken) # We need to set this env var to publish helix results to Azure Dev Ops
+ MSSQL_SA_PASSWORD: "Password12!"
+
+- ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest'), ne(variables.runCodeQL3000, 'true')) }}:
+ - template: eng\common\templates\post-build\post-build.yml
+ parameters:
+ publishingInfraVersion: 3
+ # Symbol validation isn't being very reliable lately. This should be enabled back
+ # once this issue is resolved: https://github.com/dotnet/arcade/issues/2871
+ enableSymbolValidation: false
+ enableSigningValidation: false
+ enableNugetValidation: false
+ enableSourceLinkValidation: false
From f644de20a5310e0dd17147cb1fc729a66c19f70c Mon Sep 17 00:00:00 2001
From: vseanreesermsft <78103370+vseanreesermsft@users.noreply.github.com>
Date: Tue, 5 Mar 2024 18:01:13 -0800
Subject: [PATCH 11/22] Update branding to 7.0.18 (#33247)
---
eng/Versions.props | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/eng/Versions.props b/eng/Versions.props
index 3ac3bf85df8..412e5b0fcb4 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -1,6 +1,6 @@
- 7.0.17
+ 7.0.18
servicing
False
true
From d12993825ef0459b847c8787c54845014e9bf963 Mon Sep 17 00:00:00 2001
From: Milena Hristova
Date: Wed, 6 Mar 2024 05:56:16 +0100
Subject: [PATCH 12/22] [release/6.0] Set ProducesDotNetReleaseShippingAssets
property in Publishing.props (#33175)
---
eng/Publishing.props | 1 +
1 file changed, 1 insertion(+)
diff --git a/eng/Publishing.props b/eng/Publishing.props
index 1da7cb4e448..6f77090ffcd 100644
--- a/eng/Publishing.props
+++ b/eng/Publishing.props
@@ -5,5 +5,6 @@
false
+ true
From 2519ba44a8906dc4c185acea7fd60374ee5124c7 Mon Sep 17 00:00:00 2001
From: Milena Hristova
Date: Wed, 6 Mar 2024 05:56:22 +0100
Subject: [PATCH 13/22] [release/7.0] Set ProducesDotNetReleaseShippingAssets
property in Publishing.props (#33174)
---
eng/Publishing.props | 1 +
1 file changed, 1 insertion(+)
diff --git a/eng/Publishing.props b/eng/Publishing.props
index 1da7cb4e448..6f77090ffcd 100644
--- a/eng/Publishing.props
+++ b/eng/Publishing.props
@@ -5,5 +5,6 @@
false
+ true
From 082283652a349714914f44fe5ec2c1775df9531f Mon Sep 17 00:00:00 2001
From: Milena Hristova
Date: Wed, 6 Mar 2024 05:56:34 +0100
Subject: [PATCH 14/22] [release/8.0] Set ProducesDotNetReleaseShippingAssets
property in Publishing.props (#33173)
---
eng/Publishing.props | 1 +
1 file changed, 1 insertion(+)
diff --git a/eng/Publishing.props b/eng/Publishing.props
index 1da7cb4e448..6f77090ffcd 100644
--- a/eng/Publishing.props
+++ b/eng/Publishing.props
@@ -5,5 +5,6 @@
false
+ true
From ecbad2ecea192ef7f132565cac6c4a021e63e0a3 Mon Sep 17 00:00:00 2001
From: Maurycy Markowski
Date: Thu, 7 Mar 2024 10:36:50 -0800
Subject: [PATCH 15/22] Fix to #32911 - Incorrect apply projection for complex
properties (#33212)
Problem was that when we lift structural type projection during pushdown, if that projection contains complex types with the same column names (e.g. cross join of same entities - it's perfectly fine to do in a vacuum, we just alias the columns whose names are repeated) we would lift the projection incorrectly.
What we do is go through all the properties, apply the corresponding columns to the selectExpression if needed and generate StructuralTypeProjection object if the projection needs to be applied one level up. For complex types we would generate a shaper expression and then run it through the same process, BUT the nested complex properties would be added to a flat structure along with the primitive properties, rather than in separate cache dedicated for complex property shapers.
This was wrong and not what we expected to see, when processing this structure one level up (i.e. when applying projection to the outer select)
SELECT [applying_this_projection_was_wrong]
FROM
(
SELECT c.Id, c.Name, c.ComplexProp, o.ComplexProp as ComplexProp0
FROM Customers as c
JOIN Orders as o ON ...
) as s
i.e. applying projection once worked fine, but doing it second time did not. The reason why is that we expected to see information about the complex type shape in the complex property shaper cache, rather than flat structure for primitives, but it wasn't there. So we assumed this is the first time we the projection is being applied, so we conjure up the complex type shaper based on table alias and IColumn metadata. This results in a situation, where complex property that was aliased is never picked. So we end up with:
SELECT s.Id, s.Name, s.ComplexProp -- we would also try to add s.ComplexProp again, instead of s.ComplexProp0 but of course we don't add same thing twice
FROM
(
SELECT c.Id, c.Name, c.ComplexProp, o.ComplexProp as ComplexProp0
FROM Customers as c
JOIN Orders as o ON ...
) as s
This leads to bad data - two different objects with distinct data in them are mapped to the same column in the database.
Fix is to property build a complex type shaper structure when applying projection instead, so the structure we generate matches expectations. Also modified VisitChildren and MakeNullable methods on StructuralTypeProjectionExpression to process/preserve complex type cache information, which was previously gobbled up/ignored.
Fixes #32911
---
.../Query/SqlExpressions/SelectExpression.cs | 355 +++++++++++++-----
.../StructuralTypeProjectionExpression.cs | 81 +++-
.../AdHocAdvancedMappingsQueryInMemoryTest.cs | 10 +
...AdvancedMappingsQueryRelationalTestBase.cs | 230 ++++++++++++
.../AdHocAdvancedMappingsQueryTestBase.cs | 10 +
.../Query/ComplexTypeQueryTestBase.cs | 286 ++++++++++++++
...AdHocAdvancedMappingsQuerySqlServerTest.cs | 82 ++++
.../Query/ComplexTypeQuerySqlServerTest.cs | 270 +++++++++++++
.../AdHocAdvancedMappingsQuerySqliteTest.cs | 10 +
.../Query/ComplexTypeQuerySqliteTest.cs | 270 +++++++++++++
10 files changed, 1508 insertions(+), 96 deletions(-)
create mode 100644 test/EFCore.InMemory.FunctionalTests/Query/AdHocAdvancedMappingsQueryInMemoryTest.cs
create mode 100644 test/EFCore.Relational.Specification.Tests/Query/AdHocAdvancedMappingsQueryRelationalTestBase.cs
create mode 100644 test/EFCore.Specification.Tests/Query/AdHocAdvancedMappingsQueryTestBase.cs
create mode 100644 test/EFCore.SqlServer.FunctionalTests/Query/AdHocAdvancedMappingsQuerySqlServerTest.cs
create mode 100644 test/EFCore.Sqlite.FunctionalTests/Query/AdHocAdvancedMappingsQuerySqliteTest.cs
diff --git a/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs b/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs
index 4ddcc348373..7ac113066b1 100644
--- a/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs
+++ b/src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs
@@ -30,6 +30,8 @@ public sealed partial class SelectExpression : TableExpressionBase
AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue31107", out var enabled31107) && enabled31107;
private static readonly bool UseOldBehavior32234 =
AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue32234", out var enabled32234) && enabled32234;
+ private static readonly bool UseOldBehavior32911 =
+ AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue32911", out var enabled32911) && enabled32911;
private static readonly IdentifierComparer IdentifierComparerInstance = new();
@@ -2706,116 +2708,243 @@ void HandleStructuralTypeProjection(
projection1.StructuralType.DisplayName(), projection2.StructuralType.DisplayName()));
}
- var propertyExpressions = new Dictionary();
-
- ProcessStructuralType(projection1, projection2);
-
- void ProcessStructuralType(
- StructuralTypeProjectionExpression nestedProjection1,
- StructuralTypeProjectionExpression nestedProjection2)
+ if (UseOldBehavior32911)
{
- var type = nestedProjection1.StructuralType;
+ var propertyExpressions = new Dictionary();
+
+ ProcessStructuralType(projection1, projection2);
- foreach (var property in GetAllPropertiesInHierarchy(type))
+ void ProcessStructuralType(
+ StructuralTypeProjectionExpression nestedProjection1,
+ StructuralTypeProjectionExpression nestedProjection2)
{
- var column1 = nestedProjection1.BindProperty(property);
- var column2 = nestedProjection2.BindProperty(property);
- var alias = GenerateUniqueColumnAlias(column1.Name);
- var innerProjection = new ProjectionExpression(column1, alias);
- select1._projection.Add(innerProjection);
- select2._projection.Add(new ProjectionExpression(column2, alias));
- var outerColumn = new ConcreteColumnExpression(innerProjection, tableReferenceExpression);
- if (column1.IsNullable
- || column2.IsNullable)
+ var type = nestedProjection1.StructuralType;
+
+ foreach (var property in GetAllPropertiesInHierarchy(type))
{
- outerColumn = outerColumn.MakeNullable();
- }
+ var column1 = nestedProjection1.BindProperty(property);
+ var column2 = nestedProjection2.BindProperty(property);
+ var alias = GenerateUniqueColumnAlias(column1.Name);
+ var innerProjection = new ProjectionExpression(column1, alias);
+ select1._projection.Add(innerProjection);
+ select2._projection.Add(new ProjectionExpression(column2, alias));
+ var outerColumn = new ConcreteColumnExpression(innerProjection, tableReferenceExpression);
+ if (column1.IsNullable
+ || column2.IsNullable)
+ {
+ outerColumn = outerColumn.MakeNullable();
+ }
- propertyExpressions[property] = outerColumn;
+ propertyExpressions[property] = outerColumn;
- // Lift up any identifier columns to the set operation result (the outer).
- // This is typically the entity primary key columns, but can also be all of a complex type's properties if Distinct
- // was previously called.
- if (outerIdentifiers.Length > 0)
- {
- var index = select1._identifier.FindIndex(e => e.Column.Equals(column1));
- if (index != -1)
+ // Lift up any identifier columns to the set operation result (the outer).
+ // This is typically the entity primary key columns, but can also be all of a complex type's properties if Distinct
+ // was previously called.
+ if (outerIdentifiers.Length > 0)
{
- if (select2._identifier[index].Column.Equals(column2))
+ var index = select1._identifier.FindIndex(e => e.Column.Equals(column1));
+ if (index != -1)
{
- outerIdentifiers[index] = outerColumn;
+ if (select2._identifier[index].Column.Equals(column2))
+ {
+ outerIdentifiers[index] = outerColumn;
+ }
+ else
+ {
+ // If select1 matched but select2 did not then we erase all identifiers
+ // TODO: We could make this little more robust by allow the indexes to be different. See issue#24475
+ // i.e. Identifier ordering being different.
+ outerIdentifiers = Array.Empty();
+ }
}
- else
+ // If the top-level projection - not the current nested one - is a complex type and not an entity type, then add
+ // all its columns to the "otherExpressions" list (i.e. columns not part of a an entity primary key). This is
+ // the same as with a non-structural type projection.
+ else if (projection1.StructuralType is IComplexType)
{
- // If select1 matched but select2 did not then we erase all identifiers
- // TODO: We could make this little more robust by allow the indexes to be different. See issue#24475
- // i.e. Identifier ordering being different.
- outerIdentifiers = Array.Empty();
+ var outerTypeMapping = column1.TypeMapping ?? column1.TypeMapping;
+ if (outerTypeMapping == null)
+ {
+ throw new InvalidOperationException(
+ RelationalStrings.SetOperationsRequireAtLeastOneSideWithValidTypeMapping(setOperationType));
+ }
+
+ otherExpressions.Add((outerColumn, outerTypeMapping.KeyComparer));
}
}
- // If the top-level projection - not the current nested one - is a complex type and not an entity type, then add
- // all its columns to the "otherExpressions" list (i.e. columns not part of a an entity primary key). This is
- // the same as with a non-structural type projection.
- else if (projection1.StructuralType is IComplexType)
- {
- var outerTypeMapping = column1.TypeMapping ?? column1.TypeMapping;
- if (outerTypeMapping == null)
- {
- throw new InvalidOperationException(
- RelationalStrings.SetOperationsRequireAtLeastOneSideWithValidTypeMapping(setOperationType));
- }
+ }
- otherExpressions.Add((outerColumn, outerTypeMapping.KeyComparer));
- }
+ foreach (var complexProperty in GetAllComplexPropertiesInHierarchy(nestedProjection1.StructuralType))
+ {
+ ProcessStructuralType(
+ (StructuralTypeProjectionExpression)nestedProjection1.BindComplexProperty(complexProperty).ValueBufferExpression,
+ (StructuralTypeProjectionExpression)nestedProjection2.BindComplexProperty(complexProperty).ValueBufferExpression);
}
}
- foreach (var complexProperty in GetAllComplexPropertiesInHierarchy(nestedProjection1.StructuralType))
+ Check.DebugAssert(
+ projection1.TableMap.Count == projection2.TableMap.Count,
+ "Set operation over entity projections with different table map counts");
+ Check.DebugAssert(
+ projection1.TableMap.Keys.All(t => projection2.TableMap.ContainsKey(t)),
+ "Set operation over entity projections with table map discrepancy");
+
+ var tableMap = projection1.TableMap.ToDictionary(kvp => kvp.Key, kvp => tableReferenceExpression);
+
+ var discriminatorExpression = projection1.DiscriminatorExpression;
+ if (projection1.DiscriminatorExpression != null
+ && projection2.DiscriminatorExpression != null)
{
- ProcessStructuralType(
- (StructuralTypeProjectionExpression)nestedProjection1.BindComplexProperty(complexProperty).ValueBufferExpression,
- (StructuralTypeProjectionExpression)nestedProjection2.BindComplexProperty(complexProperty).ValueBufferExpression);
+ var alias = GenerateUniqueColumnAlias(DiscriminatorColumnAlias);
+ var innerProjection = new ProjectionExpression(projection1.DiscriminatorExpression, alias);
+ select1._projection.Add(innerProjection);
+ select2._projection.Add(new ProjectionExpression(projection2.DiscriminatorExpression, alias));
+ discriminatorExpression = new ConcreteColumnExpression(innerProjection, tableReferenceExpression);
}
- }
-
- Check.DebugAssert(
- projection1.TableMap.Count == projection2.TableMap.Count,
- "Set operation over entity projections with different table map counts");
- Check.DebugAssert(
- projection1.TableMap.Keys.All(t => projection2.TableMap.ContainsKey(t)),
- "Set operation over entity projections with table map discrepancy");
- var tableMap = projection1.TableMap.ToDictionary(kvp => kvp.Key, kvp => tableReferenceExpression);
+ var outerProjection = new StructuralTypeProjectionExpression(
+ projection1.StructuralType, propertyExpressions, tableMap, nullable: false, discriminatorExpression);
- var discriminatorExpression = projection1.DiscriminatorExpression;
- if (projection1.DiscriminatorExpression != null
- && projection2.DiscriminatorExpression != null)
- {
- var alias = GenerateUniqueColumnAlias(DiscriminatorColumnAlias);
- var innerProjection = new ProjectionExpression(projection1.DiscriminatorExpression, alias);
- select1._projection.Add(innerProjection);
- select2._projection.Add(new ProjectionExpression(projection2.DiscriminatorExpression, alias));
- discriminatorExpression = new ConcreteColumnExpression(innerProjection, tableReferenceExpression);
- }
+ if (outerIdentifiers.Length > 0 && outerProjection is { StructuralType: IEntityType entityType })
+ {
+ var primaryKey = entityType.FindPrimaryKey();
- var outerProjection = new StructuralTypeProjectionExpression(
- projection1.StructuralType, propertyExpressions, tableMap, nullable: false, discriminatorExpression);
+ // We know that there are existing identifiers (see condition above); we know we must have a key since a keyless
+ // entity type would have wiped the identifiers when generating the join.
+ Check.DebugAssert(primaryKey != null, "primary key is null.");
+ foreach (var property in primaryKey.Properties)
+ {
+ entityProjectionIdentifiers.Add(outerProjection.BindProperty(property));
+ entityProjectionValueComparers.Add(property.GetKeyValueComparer());
+ }
+ }
- if (outerIdentifiers.Length > 0 && outerProjection is { StructuralType: IEntityType entityType })
+ _projectionMapping[projectionMember] = outerProjection;
+ }
+ else
{
- var primaryKey = entityType.FindPrimaryKey();
+ var resultProjection = ProcessStructuralType(projection1, projection2);
+ _projectionMapping[projectionMember] = resultProjection;
- // We know that there are existing identifiers (see condition above); we know we must have a key since a keyless
- // entity type would have wiped the identifiers when generating the join.
- Check.DebugAssert(primaryKey != null, "primary key is null.");
- foreach (var property in primaryKey.Properties)
+ StructuralTypeProjectionExpression ProcessStructuralType(
+ StructuralTypeProjectionExpression structuralProjection1,
+ StructuralTypeProjectionExpression structuralProjection2)
{
- entityProjectionIdentifiers.Add(outerProjection.BindProperty(property));
- entityProjectionValueComparers.Add(property.GetKeyValueComparer());
+ var propertyExpressions = new Dictionary();
+ var complexPropertyCache = new Dictionary();
+ var type = structuralProjection1.StructuralType;
+
+ foreach (var property in GetAllPropertiesInHierarchy(type))
+ {
+ var column1 = structuralProjection1.BindProperty(property);
+ var column2 = structuralProjection2.BindProperty(property);
+ var alias = GenerateUniqueColumnAlias(column1.Name);
+ var innerProjection = new ProjectionExpression(column1, alias);
+ select1._projection.Add(innerProjection);
+ select2._projection.Add(new ProjectionExpression(column2, alias));
+ var outerColumn = new ConcreteColumnExpression(innerProjection, tableReferenceExpression);
+ if (column1.IsNullable
+ || column2.IsNullable)
+ {
+ outerColumn = outerColumn.MakeNullable();
+ }
+
+ propertyExpressions[property] = outerColumn;
+
+ // Lift up any identifier columns to the set operation result (the outer).
+ // This is typically the entity primary key columns, but can also be all of a complex type's properties if Distinct
+ // was previously called.
+ if (outerIdentifiers.Length > 0)
+ {
+ var index = select1._identifier.FindIndex(e => e.Column.Equals(column1));
+ if (index != -1)
+ {
+ if (select2._identifier[index].Column.Equals(column2))
+ {
+ outerIdentifiers[index] = outerColumn;
+ }
+ else
+ {
+ // If select1 matched but select2 did not then we erase all identifiers
+ // TODO: We could make this little more robust by allow the indexes to be different. See issue#24475
+ // i.e. Identifier ordering being different.
+ outerIdentifiers = Array.Empty();
+ }
+ }
+ // If the top-level projection - not the current nested one - is a complex type and not an entity type, then add
+ // all its columns to the "otherExpressions" list (i.e. columns not part of a an entity primary key). This is
+ // the same as with a non-structural type projection.
+ else if (projection1.StructuralType is IComplexType)
+ {
+ var outerTypeMapping = column1.TypeMapping ?? column1.TypeMapping;
+ if (outerTypeMapping == null)
+ {
+ throw new InvalidOperationException(
+ RelationalStrings.SetOperationsRequireAtLeastOneSideWithValidTypeMapping(setOperationType));
+ }
+
+ otherExpressions.Add((outerColumn, outerTypeMapping.KeyComparer));
+ }
+ }
+ }
+
+ foreach (var complexProperty in GetAllComplexPropertiesInHierarchy(type))
+ {
+ var complexPropertyShaper1 = structuralProjection1.BindComplexProperty(complexProperty);
+ var complexPropertyShaper2 = structuralProjection2.BindComplexProperty(complexProperty);
+
+ var resultComplexProjection = ProcessStructuralType(
+ (StructuralTypeProjectionExpression)complexPropertyShaper1.ValueBufferExpression,
+ (StructuralTypeProjectionExpression)complexPropertyShaper2.ValueBufferExpression);
+
+ var resultComplexShaper = new RelationalStructuralTypeShaperExpression(
+ complexProperty.ComplexType,
+ resultComplexProjection,
+ resultComplexProjection.IsNullable);
+
+ complexPropertyCache[complexProperty] = resultComplexShaper;
+ }
+
+ Check.DebugAssert(
+ structuralProjection1.TableMap.Count == structuralProjection2.TableMap.Count,
+ "Set operation over entity projections with different table map counts");
+ Check.DebugAssert(
+ structuralProjection1.TableMap.Keys.All(t => structuralProjection2.TableMap.ContainsKey(t)),
+ "Set operation over entity projections with table map discrepancy");
+
+ var tableMap = structuralProjection1.TableMap.ToDictionary(kvp => kvp.Key, _ => tableReferenceExpression);
+
+ var discriminatorExpression = structuralProjection1.DiscriminatorExpression;
+ if (structuralProjection1.DiscriminatorExpression != null
+ && structuralProjection2.DiscriminatorExpression != null)
+ {
+ var alias = GenerateUniqueColumnAlias(DiscriminatorColumnAlias);
+ var innerProjection = new ProjectionExpression(structuralProjection1.DiscriminatorExpression, alias);
+ select1._projection.Add(innerProjection);
+ select2._projection.Add(new ProjectionExpression(structuralProjection2.DiscriminatorExpression, alias));
+ discriminatorExpression = new ConcreteColumnExpression(innerProjection, tableReferenceExpression);
+ }
+
+ var outerProjection = new StructuralTypeProjectionExpression(
+ type, propertyExpressions, complexPropertyCache, tableMap, nullable: false, discriminatorExpression);
+
+ if (outerIdentifiers.Length > 0 && outerProjection is { StructuralType: IEntityType entityType })
+ {
+ var primaryKey = entityType.FindPrimaryKey();
+
+ // We know that there are existing identifiers (see condition above); we know we must have a key since a keyless
+ // entity type would have wiped the identifiers when generating the join.
+ Check.DebugAssert(primaryKey != null, "primary key is null.");
+ foreach (var property in primaryKey.Properties)
+ {
+ entityProjectionIdentifiers.Add(outerProjection.BindProperty(property));
+ entityProjectionValueComparers.Add(property.GetKeyValueComparer());
+ }
+ }
+
+ return outerProjection;
}
}
-
- _projectionMapping[projectionMember] = outerProjection;
}
string GenerateUniqueColumnAlias(string baseAlias)
@@ -4184,32 +4313,67 @@ StructuralTypeProjectionExpression LiftEntityProjectionFromSubquery(
TableReferenceExpression subqueryTableReference)
{
var propertyExpressions = new Dictionary();
+ var complexPropertyCache = new Dictionary();
+
+ if (UseOldBehavior32911)
+ {
+ HandleTypeProjection(projection);
- HandleTypeProjection(projection);
+ void HandleTypeProjection(StructuralTypeProjectionExpression typeProjection)
+ {
+ foreach (var property in GetAllPropertiesInHierarchy(typeProjection.StructuralType))
+ {
+ // json entity projection (i.e. JSON entity that was transformed into query root) may have synthesized keys
+ // but they don't correspond to any columns - we need to skip those
+ if (typeProjection is { StructuralType: IEntityType entityType }
+ && entityType.IsMappedToJson()
+ && property.IsOrdinalKeyProperty())
+ {
+ continue;
+ }
+
+ var innerColumn = typeProjection.BindProperty(property);
+ var outerColumn = subquery.GenerateOuterColumn(subqueryTableReferenceExpression, innerColumn);
+ projectionMap[innerColumn] = outerColumn;
+ propertyExpressions[property] = outerColumn;
+ }
- void HandleTypeProjection(StructuralTypeProjectionExpression typeProjection)
+ foreach (var complexProperty in GetAllComplexPropertiesInHierarchy(typeProjection.StructuralType))
+ {
+ HandleTypeProjection(
+ (StructuralTypeProjectionExpression)typeProjection.BindComplexProperty(complexProperty).ValueBufferExpression);
+ }
+ }
+ }
+ else
{
- foreach (var property in GetAllPropertiesInHierarchy(typeProjection.StructuralType))
+ foreach (var property in GetAllPropertiesInHierarchy(projection.StructuralType))
{
// json entity projection (i.e. JSON entity that was transformed into query root) may have synthesized keys
// but they don't correspond to any columns - we need to skip those
- if (typeProjection is { StructuralType: IEntityType entityType }
+ if (projection is { StructuralType: IEntityType entityType }
&& entityType.IsMappedToJson()
&& property.IsOrdinalKeyProperty())
{
continue;
}
- var innerColumn = typeProjection.BindProperty(property);
- var outerColumn = subquery.GenerateOuterColumn(subqueryTableReferenceExpression, innerColumn);
+ var innerColumn = projection.BindProperty(property);
+ var outerColumn = subquery.GenerateOuterColumn(subqueryTableReference, innerColumn);
+
projectionMap[innerColumn] = outerColumn;
propertyExpressions[property] = outerColumn;
}
- foreach (var complexProperty in GetAllComplexPropertiesInHierarchy(typeProjection.StructuralType))
+ foreach (var complexProperty in GetAllComplexPropertiesInHierarchy(projection.StructuralType))
{
- HandleTypeProjection(
- (StructuralTypeProjectionExpression)typeProjection.BindComplexProperty(complexProperty).ValueBufferExpression);
+ var complexPropertyShaper = projection.BindComplexProperty(complexProperty);
+
+ var complexTypeProjectionExpression = LiftEntityProjectionFromSubquery(
+ (StructuralTypeProjectionExpression)complexPropertyShaper.ValueBufferExpression,
+ subqueryTableReference);
+
+ complexPropertyCache[complexProperty] = complexPropertyShaper.Update(complexTypeProjectionExpression);
}
}
@@ -4223,8 +4387,11 @@ void HandleTypeProjection(StructuralTypeProjectionExpression typeProjection)
var tableMap = projection.TableMap.ToDictionary(kvp => kvp.Key, _ => subqueryTableReference);
- var newEntityProjection = new StructuralTypeProjectionExpression(
- projection.StructuralType, propertyExpressions, tableMap, nullable: false, discriminatorExpression);
+ var newEntityProjection = UseOldBehavior32911
+ ? new StructuralTypeProjectionExpression(
+ projection.StructuralType, propertyExpressions, tableMap, nullable: false, discriminatorExpression)
+ : new StructuralTypeProjectionExpression(
+ projection.StructuralType, propertyExpressions, complexPropertyCache, tableMap, nullable: false, discriminatorExpression);
if (projection.StructuralType is IEntityType entityType2)
{
diff --git a/src/EFCore.Relational/Query/StructuralTypeProjectionExpression.cs b/src/EFCore.Relational/Query/StructuralTypeProjectionExpression.cs
index 828a7c95b2b..5b9c7dd152d 100644
--- a/src/EFCore.Relational/Query/StructuralTypeProjectionExpression.cs
+++ b/src/EFCore.Relational/Query/StructuralTypeProjectionExpression.cs
@@ -17,6 +17,9 @@ namespace Microsoft.EntityFrameworkCore.Query;
///
public class StructuralTypeProjectionExpression : Expression
{
+ private static readonly bool UseOldBehavior32911 =
+ AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue32911", out var enabled32911) && enabled32911;
+
private readonly IReadOnlyDictionary _propertyExpressionMap;
private readonly Dictionary _ownedNavigationMap;
private Dictionary? _complexPropertyCache;
@@ -38,6 +41,32 @@ public StructuralTypeProjectionExpression(
type,
propertyExpressionMap,
new Dictionary(),
+ null,
+ tableMap,
+ nullable,
+ discriminatorExpression)
+ {
+ }
+
+ ///
+ /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
+ /// the same compatibility standards as public APIs. It may be changed or removed without notice in
+ /// any release. You should only use it directly in your code with extreme caution and knowing that
+ /// doing so can result in application failures when updating to a new Entity Framework Core release.
+ ///
+ [EntityFrameworkInternal]
+ public StructuralTypeProjectionExpression(
+ ITypeBase type,
+ IReadOnlyDictionary propertyExpressionMap,
+ Dictionary complexPropertyCache,
+ IReadOnlyDictionary tableMap,
+ bool nullable = false,
+ SqlExpression? discriminatorExpression = null)
+ : this(
+ type,
+ propertyExpressionMap,
+ new Dictionary(),
+ complexPropertyCache,
tableMap,
nullable,
discriminatorExpression)
@@ -48,6 +77,7 @@ private StructuralTypeProjectionExpression(
ITypeBase type,
IReadOnlyDictionary propertyExpressionMap,
Dictionary ownedNavigationMap,
+ Dictionary? complexPropertyCache,
IReadOnlyDictionary tableMap,
bool nullable,
SqlExpression? discriminatorExpression = null)
@@ -55,6 +85,7 @@ private StructuralTypeProjectionExpression(
StructuralType = type;
_propertyExpressionMap = propertyExpressionMap;
_ownedNavigationMap = ownedNavigationMap;
+ _complexPropertyCache = complexPropertyCache;
TableMap = tableMap;
IsNullable = nullable;
DiscriminatorExpression = discriminatorExpression;
@@ -115,6 +146,21 @@ protected override Expression VisitChildren(ExpressionVisitor visitor)
propertyExpressionMap[property] = newExpression;
}
+ var complexPropertyCache = default(Dictionary);
+ if (!UseOldBehavior32911)
+ {
+ if (_complexPropertyCache != null)
+ {
+ complexPropertyCache = new();
+ foreach (var (complexProperty, complexShaper) in _complexPropertyCache)
+ {
+ var newComplexShaper = (StructuralTypeShaperExpression)visitor.Visit(complexShaper);
+ changed |= complexShaper != newComplexShaper;
+ complexPropertyCache[complexProperty] = newComplexShaper;
+ }
+ }
+ }
+
// We only need to visit the table map since TableReferenceUpdatingExpressionVisitor may need to modify it; it mutates
// TableReferenceExpression (a new TableReferenceExpression is never returned), so we never need a new table map.
foreach (var (_, tableExpression) in TableMap)
@@ -136,7 +182,7 @@ protected override Expression VisitChildren(ExpressionVisitor visitor)
return changed
? new StructuralTypeProjectionExpression(
- StructuralType, propertyExpressionMap, ownedNavigationMap, TableMap, IsNullable, discriminatorExpression)
+ StructuralType, propertyExpressionMap, ownedNavigationMap, complexPropertyCache, TableMap, IsNullable, discriminatorExpression)
: this;
}
@@ -159,6 +205,19 @@ public virtual StructuralTypeProjectionExpression MakeNullable()
discriminatorExpression = ce.MakeNullable();
}
+ var complexPropertyCache = default(Dictionary);
+ if (!UseOldBehavior32911)
+ {
+ if (_complexPropertyCache != null)
+ {
+ complexPropertyCache = new();
+ foreach (var (complexProperty, complexShaper) in _complexPropertyCache)
+ {
+ complexPropertyCache[complexProperty] = complexShaper.MakeNullable();
+ }
+ }
+ }
+
var ownedNavigationMap = new Dictionary();
foreach (var (navigation, shaper) in _ownedNavigationMap)
{
@@ -178,6 +237,7 @@ public virtual StructuralTypeProjectionExpression MakeNullable()
StructuralType,
propertyExpressionMap,
ownedNavigationMap,
+ complexPropertyCache,
TableMap,
nullable: true,
discriminatorExpression);
@@ -212,6 +272,23 @@ public virtual StructuralTypeProjectionExpression UpdateEntityType(IEntityType d
}
}
+ var complexPropertyCache = default(Dictionary);
+ if (!UseOldBehavior32911)
+ {
+ if (_complexPropertyCache != null)
+ {
+ complexPropertyCache = new();
+ foreach (var (complexProperty, complexShaper) in _complexPropertyCache)
+ {
+ if (derivedType.IsAssignableFrom(complexProperty.DeclaringType)
+ || complexProperty.DeclaringType.IsAssignableFrom(derivedType))
+ {
+ complexPropertyCache[complexProperty] = complexShaper;
+ }
+ }
+ }
+ }
+
var ownedNavigationMap = new Dictionary();
foreach (var (navigation, entityShaperExpression) in _ownedNavigationMap)
{
@@ -263,7 +340,7 @@ public virtual StructuralTypeProjectionExpression UpdateEntityType(IEntityType d
}
return new StructuralTypeProjectionExpression(
- derivedType, propertyExpressionMap, ownedNavigationMap, newTableMap ?? TableMap, IsNullable, discriminatorExpression);
+ derivedType, propertyExpressionMap, ownedNavigationMap, complexPropertyCache, newTableMap ?? TableMap, IsNullable, discriminatorExpression);
}
///
diff --git a/test/EFCore.InMemory.FunctionalTests/Query/AdHocAdvancedMappingsQueryInMemoryTest.cs b/test/EFCore.InMemory.FunctionalTests/Query/AdHocAdvancedMappingsQueryInMemoryTest.cs
new file mode 100644
index 00000000000..bcd988e7562
--- /dev/null
+++ b/test/EFCore.InMemory.FunctionalTests/Query/AdHocAdvancedMappingsQueryInMemoryTest.cs
@@ -0,0 +1,10 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace Microsoft.EntityFrameworkCore.Query;
+
+public class AdHocAdvancedMappingsQueryInMemoryTest : AdHocAdvancedMappingsQueryTestBase
+{
+ protected override ITestStoreFactory TestStoreFactory
+ => InMemoryTestStoreFactory.Instance;
+}
diff --git a/test/EFCore.Relational.Specification.Tests/Query/AdHocAdvancedMappingsQueryRelationalTestBase.cs b/test/EFCore.Relational.Specification.Tests/Query/AdHocAdvancedMappingsQueryRelationalTestBase.cs
new file mode 100644
index 00000000000..d001b5488f2
--- /dev/null
+++ b/test/EFCore.Relational.Specification.Tests/Query/AdHocAdvancedMappingsQueryRelationalTestBase.cs
@@ -0,0 +1,230 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace Microsoft.EntityFrameworkCore.Query;
+
+public abstract class AdHocAdvancedMappingsQueryRelationalTestBase : AdHocAdvancedMappingsQueryTestBase
+{
+ protected TestSqlLoggerFactory TestSqlLoggerFactory
+ => (TestSqlLoggerFactory)ListLoggerFactory;
+
+ protected void ClearLog()
+ => TestSqlLoggerFactory.Clear();
+
+ protected void AssertSql(params string[] expected)
+ => TestSqlLoggerFactory.AssertBaseline(expected);
+
+ #region 32911
+
+ [ConditionalFact]
+ public virtual async Task Two_similar_complex_properties_projected_with_split_query1()
+ {
+ var contextFactory = await InitializeAsync(seed: c => c.Seed());
+
+ using var context = contextFactory.CreateContext();
+ var query = context.Offers
+ .Include(e => e.Variations)
+ .ThenInclude(v => v.Nested)
+ .AsSplitQuery()
+ .ToList();
+
+ var resultElement = query.Single();
+ foreach (var variation in resultElement.Variations)
+ {
+ Assert.NotEqual(variation.Payment.Brutto, variation.Nested.Payment.Brutto);
+ Assert.NotEqual(variation.Payment.Netto, variation.Nested.Payment.Netto);
+ }
+ }
+
+ [ConditionalFact]
+ public virtual async Task Two_similar_complex_properties_projected_with_split_query2()
+ {
+ var contextFactory = await InitializeAsync(seed: c => c.Seed());
+
+ using var context = contextFactory.CreateContext();
+ var query = context.Offers
+ .Include(e => e.Variations)
+ .ThenInclude(v => v.Nested)
+ .AsSplitQuery()
+ .Single(x => x.Id == 1);
+
+ foreach (var variation in query.Variations)
+ {
+ Assert.NotEqual(variation.Payment.Brutto, variation.Nested.Payment.Brutto);
+ Assert.NotEqual(variation.Payment.Netto, variation.Nested.Payment.Netto);
+ }
+ }
+
+ [ConditionalFact]
+ public virtual async Task Projecting_one_of_two_similar_complex_types_picks_the_correct_one()
+ {
+ var contextFactory = await InitializeAsync(seed: c => c.Seed());
+
+ using var context = contextFactory.CreateContext();
+
+ var query = context.Cs
+ .Where(x => x.B.AId.Value == 1)
+ .OrderBy(x => x.Id)
+ .Take(10)
+ .Select(x => new
+ {
+ x.B.A.Id,
+ x.B.Info.Created,
+ }).ToList();
+
+ Assert.Equal(new DateTime(2000, 1, 1), query[0].Created);
+ }
+
+ protected class Context32911(DbContextOptions options) : DbContext(options)
+ {
+ public DbSet Offers { get; set; }
+
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
+ {
+ modelBuilder.Entity().Property(x => x.Id).ValueGeneratedNever();
+ modelBuilder.Entity().Property(x => x.Id).ValueGeneratedNever();
+ modelBuilder.Entity().ComplexProperty(x => x.Payment, cpb =>
+ {
+ cpb.IsRequired();
+ cpb.Property(p => p.Netto).HasColumnName("payment_netto");
+ cpb.Property(p => p.Brutto).HasColumnName("payment_brutto");
+ });
+ modelBuilder.Entity().Property(x => x.Id).ValueGeneratedNever();
+ modelBuilder.Entity().ComplexProperty(x => x.Payment, cpb =>
+ {
+ cpb.IsRequired();
+ cpb.Property(p => p.Netto).HasColumnName("payment_netto");
+ cpb.Property(p => p.Brutto).HasColumnName("payment_brutto");
+ });
+ }
+
+ public void Seed()
+ {
+ var v1 = new Variation
+ {
+ Id = 1,
+ Payment = new Payment(1, 10),
+ Nested = new NestedEntity
+ {
+ Id = 1,
+ Payment = new Payment(10, 100)
+ }
+ };
+
+ var v2 = new Variation
+ {
+ Id = 2,
+ Payment = new Payment(2, 20),
+ Nested = new NestedEntity
+ {
+ Id = 2,
+ Payment = new Payment(20, 200)
+ }
+ };
+
+ var v3 = new Variation
+ {
+ Id = 3,
+ Payment = new Payment(3, 30),
+ Nested = new NestedEntity
+ {
+ Id = 3,
+ Payment = new Payment(30, 300)
+ }
+ };
+
+ Offers.Add(new Offer { Id = 1, Variations = new List { v1, v2, v3 } });
+
+ SaveChanges();
+ }
+
+ public abstract class EntityBase
+ {
+ public int Id { get; set; }
+ }
+
+ public class Offer : EntityBase
+ {
+ public ICollection Variations { get; set; }
+ }
+
+ public class Variation : EntityBase
+ {
+ public Payment Payment { get; set; } = new Payment(0, 0);
+
+ public NestedEntity Nested { get; set; }
+ }
+
+ public class NestedEntity : EntityBase
+ {
+ public Payment Payment { get; set; } = new Payment(0, 0);
+ }
+
+ public record Payment(decimal Netto, decimal Brutto);
+ }
+
+ protected class Context32911_2(DbContextOptions options) : DbContext(options)
+ {
+ public DbSet As { get; set; }
+ public DbSet Bs { get; set; }
+ public DbSet Cs { get; set; }
+
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
+ {
+ modelBuilder.Entity().Property(x => x.Id).ValueGeneratedNever();
+ modelBuilder.Entity().Property(x => x.Id).ValueGeneratedNever();
+ modelBuilder.Entity().Property(x => x.Id).ValueGeneratedNever();
+
+ modelBuilder.Entity(x => x.ComplexProperty(b => b.Info).IsRequired());
+ modelBuilder.Entity(x => x.ComplexProperty(c => c.Info).IsRequired());
+ }
+
+ public void Seed()
+ {
+ var c = new C
+ {
+ Id = 100,
+ Info = new Metadata { Created = new DateTime(2020, 10, 10) },
+ B = new B
+ {
+ Id = 10,
+ Info = new Metadata { Created = new DateTime(2000, 1, 1) },
+ A = new A { Id = 1 }
+ }
+ };
+
+ Cs.Add(c);
+ SaveChanges();
+ }
+
+ public class Metadata
+ {
+ public DateTime Created { get; set; }
+ }
+
+ public class A
+ {
+ public int Id { get; set; }
+ }
+
+ public class B
+ {
+ public int Id { get; set; }
+ public Metadata Info { get; set; }
+ public int? AId { get; set; }
+
+ public A A { get; set; }
+ }
+
+ public class C
+ {
+ public int Id { get; set; }
+ public Metadata Info { get; set; }
+ public int BId { get; set; }
+
+ public B B { get; set; }
+ }
+ }
+
+ #endregion
+}
diff --git a/test/EFCore.Specification.Tests/Query/AdHocAdvancedMappingsQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/AdHocAdvancedMappingsQueryTestBase.cs
new file mode 100644
index 00000000000..7782e297b48
--- /dev/null
+++ b/test/EFCore.Specification.Tests/Query/AdHocAdvancedMappingsQueryTestBase.cs
@@ -0,0 +1,10 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace Microsoft.EntityFrameworkCore.Query;
+
+public abstract class AdHocAdvancedMappingsQueryTestBase : NonSharedModelTestBase
+{
+ protected override string StoreName
+ => "AdHocAdvancedMappingsQueryTests";
+}
diff --git a/test/EFCore.Specification.Tests/Query/ComplexTypeQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/ComplexTypeQueryTestBase.cs
index ceb4a5d65af..1f45144803e 100644
--- a/test/EFCore.Specification.Tests/Query/ComplexTypeQueryTestBase.cs
+++ b/test/EFCore.Specification.Tests/Query/ComplexTypeQueryTestBase.cs
@@ -506,6 +506,292 @@ public virtual Task Union_two_different_struct_complex_type(bool async)
async,
ss => ss.Set().Select(c => c.ShippingAddress).Union(ss.Set().Select(c => c.BillingAddress)));
+ [ConditionalTheory]
+ [MemberData(nameof(IsAsyncData))]
+ public virtual Task Project_same_nested_complex_type_twice_with_pushdown(bool async)
+ => AssertQuery(
+ async,
+ ss => (from c1 in ss.Set()
+ from c2 in ss.Set()
+ select new { BA1 = c1.BillingAddress, BA2 = c2.BillingAddress })
+ .Distinct()
+ .Select(x => new { x.BA1, x.BA2 }),
+ elementSorter: e => (e.BA1.ZipCode, e.BA2.ZipCode),
+ elementAsserter: (e, a) =>
+ {
+ AssertEqual(e.BA1, a.BA1);
+ AssertEqual(e.BA2, a.BA2);
+ });
+
+ [ConditionalTheory]
+ [MemberData(nameof(IsAsyncData))]
+ public virtual Task Project_same_entity_with_nested_complex_type_twice_with_pushdown(bool async)
+ => AssertQuery(
+ async,
+ ss => (from c1 in ss.Set()
+ from c2 in ss.Set()
+ select new { c1, c2 })
+ .Distinct()
+ .Select(x => new { x.c1, x.c2 }),
+ elementSorter: e => (e.c1.Id, e.c2.Id),
+ elementAsserter: (e, a) =>
+ {
+ AssertEqual(e.c1, a.c1);
+ AssertEqual(e.c2, a.c2);
+ });
+
+ [ConditionalTheory]
+ [MemberData(nameof(IsAsyncData))]
+ public virtual Task Project_same_nested_complex_type_twice_with_double_pushdown(bool async)
+ => AssertQuery(
+ async,
+ ss => (from c1 in ss.Set()
+ from c2 in ss.Set()
+ orderby c1.Id, c2.Id
+ select new { BA1 = c1.BillingAddress, BA2 = c2.BillingAddress })
+ .Take(50)
+ .Distinct()
+ .Select(x => new { x.BA1, x.BA2 }),
+ elementSorter: e => (e.BA1.ZipCode, e.BA2.ZipCode),
+ elementAsserter: (e, a) =>
+ {
+ AssertEqual(e.BA1, a.BA1);
+ AssertEqual(e.BA2, a.BA2);
+ });
+
+ [ConditionalTheory]
+ [MemberData(nameof(IsAsyncData))]
+ public virtual Task Project_same_entity_with_nested_complex_type_twice_with_double_pushdown(bool async)
+ => AssertQuery(
+ async,
+ ss => (from c1 in ss.Set()
+ from c2 in ss.Set()
+ orderby c1.Id, c2.Id
+ select new { c1, c2 })
+ .Take(50)
+ .Distinct()
+ .Select(x => new { x.c1, x.c2 }),
+ elementSorter: e => (e.c1.Id, e.c2.Id),
+ elementAsserter: (e, a) =>
+ {
+ AssertEqual(e.c1, a.c1);
+ AssertEqual(e.c2, a.c2);
+ });
+
+ [ConditionalTheory]
+ [MemberData(nameof(IsAsyncData))]
+ public virtual Task Project_same_struct_nested_complex_type_twice_with_pushdown(bool async)
+ => AssertQuery(
+ async,
+ ss => (from c1 in ss.Set()
+ from c2 in ss.Set()
+ select new { BA1 = c1.BillingAddress, BA2 = c2.BillingAddress })
+ .Distinct()
+ .Select(x => new { x.BA1, x.BA2 }),
+ elementSorter: e => (e.BA1.ZipCode, e.BA2.ZipCode),
+ elementAsserter: (e, a) =>
+ {
+ AssertEqual(e.BA1, a.BA1);
+ AssertEqual(e.BA2, a.BA2);
+ });
+
+ [ConditionalTheory]
+ [MemberData(nameof(IsAsyncData))]
+ public virtual Task Project_same_entity_with_struct_nested_complex_type_twice_with_pushdown(bool async)
+ => AssertQuery(
+ async,
+ ss => (from c1 in ss.Set()
+ from c2 in ss.Set()
+ select new { c1, c2 })
+ .Distinct()
+ .Select(x => new { x.c1, x.c2 }),
+ elementSorter: e => (e.c1.Id, e.c2.Id),
+ elementAsserter: (e, a) =>
+ {
+ AssertEqual(e.c1, a.c1);
+ AssertEqual(e.c2, a.c2);
+ });
+
+ [ConditionalTheory]
+ [MemberData(nameof(IsAsyncData))]
+ public virtual Task Project_same_struct_nested_complex_type_twice_with_double_pushdown(bool async)
+ => AssertQuery(
+ async,
+ ss => (from c1 in ss.Set()
+ from c2 in ss.Set()
+ orderby c1.Id, c2.Id
+ select new { BA1 = c1.BillingAddress, BA2 = c2.BillingAddress })
+ .Take(50)
+ .Distinct()
+ .Select(x => new { x.BA1, x.BA2 }),
+ elementSorter: e => (e.BA1.ZipCode, e.BA2.ZipCode),
+ elementAsserter: (e, a) =>
+ {
+ AssertEqual(e.BA1, a.BA1);
+ AssertEqual(e.BA2, a.BA2);
+ });
+
+ [ConditionalTheory]
+ [MemberData(nameof(IsAsyncData))]
+ public virtual Task Project_same_entity_with_struct_nested_complex_type_twice_with_double_pushdown(bool async)
+ => AssertQuery(
+ async,
+ ss => (from c1 in ss.Set()
+ from c2 in ss.Set()
+ orderby c1.Id, c2.Id
+ select new { c1, c2 })
+ .Take(50)
+ .Distinct()
+ .Select(x => new { x.c1, x.c2 }),
+ elementSorter: e => (e.c1.Id, e.c2.Id),
+ elementAsserter: (e, a) =>
+ {
+ AssertEqual(e.c1, a.c1);
+ AssertEqual(e.c2, a.c2);
+ });
+
+ [ConditionalTheory]
+ [MemberData(nameof(IsAsyncData))]
+ public virtual Task Union_of_same_entity_with_nested_complex_type_projected_twice_with_pushdown(bool async)
+ => AssertQuery(
+ async,
+ ss => (from c1 in ss.Set()
+ from c2 in ss.Set()
+ orderby c1.Id, c2.Id
+ select new { c1, c2 })
+ .Union(from c1 in ss.Set()
+ from c2 in ss.Set()
+ orderby c1.Id, c2.Id
+ select new { c1, c2 })
+ .OrderBy(x => x.c1.Id).ThenBy(x => x.c2.Id)
+ .Take(50)
+ .Select(x => new { x.c1, x.c2 }),
+ assertOrder: true,
+ elementAsserter: (e, a) =>
+ {
+ AssertEqual(e.c1, a.c1);
+ AssertEqual(e.c2, a.c2);
+ });
+
+ [ConditionalTheory]
+ [MemberData(nameof(IsAsyncData))]
+ public virtual Task Union_of_same_entity_with_nested_complex_type_projected_twice_with_double_pushdown(bool async)
+ => AssertQuery(
+ async,
+ ss => (from c1 in ss.Set()
+ from c2 in ss.Set()
+ orderby c1.Id, c2.Id
+ select new { c1, c2 })
+ .Union(from c1 in ss.Set()
+ from c2 in ss.Set()
+ orderby c1.Id, c2.Id
+ select new { c1, c2 })
+ .OrderBy(x => x.c1.Id).ThenBy(x => x.c2.Id)
+ .Take(50)
+ .Select(x => new { x.c1, x.c2 })
+ .Distinct()
+ .OrderBy(x => x.c1.Id).ThenBy(x => x.c2.Id)
+ .Take(50)
+ .Select(x => new { x.c1, x.c2 }),
+ assertOrder: true,
+ elementAsserter: (e, a) =>
+ {
+ AssertEqual(e.c1, a.c1);
+ AssertEqual(e.c2, a.c2);
+ });
+
+ [ConditionalTheory]
+ [MemberData(nameof(IsAsyncData))]
+ public virtual Task Union_of_same_nested_complex_type_projected_twice_with_pushdown(bool async)
+ => AssertQuery(
+ async,
+ ss => (from c1 in ss.Set()
+ from c2 in ss.Set()
+ orderby c1.Id, c2.Id
+ select new { BA1 = c1.BillingAddress, BA2 = c2.BillingAddress })
+ .Union(from c1 in ss.Set()
+ from c2 in ss.Set()
+ orderby c1.Id, c2.Id
+ select new { BA1 = c1.BillingAddress, BA2 = c2.BillingAddress })
+ .OrderBy(x => x.BA1.ZipCode).ThenBy(x => x.BA2.ZipCode)
+ .Take(50)
+ .Select(x => new { x.BA1, x.BA2 }),
+ assertOrder: true,
+ elementAsserter: (e, a) =>
+ {
+ AssertEqual(e.BA1, a.BA1);
+ AssertEqual(e.BA2, a.BA2);
+ });
+
+ [ConditionalTheory]
+ [MemberData(nameof(IsAsyncData))]
+ public virtual Task Union_of_same_nested_complex_type_projected_twice_with_double_pushdown(bool async)
+ => AssertQuery(
+ async,
+ ss => (from c1 in ss.Set()
+ from c2 in ss.Set()
+ orderby c1.Id, c2.Id
+ select new { BA1 = c1.BillingAddress, BA2 = c2.BillingAddress })
+ .Union(from c1 in ss.Set()
+ from c2 in ss.Set()
+ orderby c1.Id, c2.Id
+ select new { BA1 = c1.BillingAddress, BA2 = c2.BillingAddress })
+ .OrderBy(x => x.BA1.ZipCode).ThenBy(x => x.BA2.ZipCode)
+ .Take(50)
+ .Select(x => new { x.BA1, x.BA2 })
+ .Distinct()
+ .OrderBy(x => x.BA1.ZipCode).ThenBy(x => x.BA2.ZipCode)
+ .Take(50)
+ .Select(x => new { x.BA1, x.BA2 }),
+ assertOrder: true,
+ elementAsserter: (e, a) =>
+ {
+ AssertEqual(e.BA1, a.BA1);
+ AssertEqual(e.BA2, a.BA2);
+ });
+
+ [ConditionalTheory]
+ [MemberData(nameof(IsAsyncData))]
+ public virtual Task Same_entity_with_complex_type_projected_twice_with_pushdown_as_part_of_another_projection(bool async)
+ => AssertQuery(
+ async,
+ ss => ss.Set().Select(x => new
+ {
+ x.Id,
+ Complex = (from c1 in ss.Set()
+ from c2 in ss.Set()
+ orderby c1.Id, c2.Id descending
+ select new { One = c1, Two = c2 }).FirstOrDefault()
+ }),
+ elementSorter: e => e.Id,
+ elementAsserter: (e, a) =>
+ {
+ AssertEqual(e.Id, a.Id);
+ AssertEqual(e.Complex?.One, a.Complex?.One);
+ AssertEqual(e.Complex?.Two, a.Complex?.Two);
+ });
+
+ [ConditionalTheory(Skip = "issue #31376")]
+ [MemberData(nameof(IsAsyncData))]
+ public virtual Task Same_complex_type_projected_twice_with_pushdown_as_part_of_another_projection(bool async)
+ => AssertQuery(
+ async,
+ ss => ss.Set().Select(x => new
+ {
+ x.Id,
+ Complex = (from c1 in ss.Set()
+ from c2 in ss.Set()
+ orderby c1.Id, c2.Id descending
+ select new { One = c1.BillingAddress, Two = c2.BillingAddress }).FirstOrDefault()
+ }),
+ elementSorter: e => e.Id,
+ elementAsserter: (e, a) =>
+ {
+ AssertEqual(e.Id, a.Id);
+ AssertEqual(e.Complex?.One, a.Complex?.One);
+ AssertEqual(e.Complex?.Two, a.Complex?.Two);
+ });
+
protected DbContext CreateContext()
=> Fixture.CreateContext();
}
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/AdHocAdvancedMappingsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/AdHocAdvancedMappingsQuerySqlServerTest.cs
new file mode 100644
index 00000000000..122d76763bf
--- /dev/null
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/AdHocAdvancedMappingsQuerySqlServerTest.cs
@@ -0,0 +1,82 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace Microsoft.EntityFrameworkCore.Query;
+
+public class AdHocAdvancedMappingsQuerySqlServerTest : AdHocAdvancedMappingsQueryRelationalTestBase
+{
+ protected override ITestStoreFactory TestStoreFactory
+ => SqlServerTestStoreFactory.Instance;
+
+ public override async Task Two_similar_complex_properties_projected_with_split_query1()
+ {
+ await base.Two_similar_complex_properties_projected_with_split_query1();
+
+ AssertSql(
+"""
+SELECT [o].[Id]
+FROM [Offers] AS [o]
+ORDER BY [o].[Id]
+""",
+ //
+ """
+SELECT [t].[Id], [t].[NestedId], [t].[OfferId], [t].[payment_brutto], [t].[payment_netto], [t].[Id0], [t].[payment_brutto0], [t].[payment_netto0], [o].[Id]
+FROM [Offers] AS [o]
+INNER JOIN (
+ SELECT [v].[Id], [v].[NestedId], [v].[OfferId], [v].[payment_brutto], [v].[payment_netto], [n].[Id] AS [Id0], [n].[payment_brutto] AS [payment_brutto0], [n].[payment_netto] AS [payment_netto0]
+ FROM [Variation] AS [v]
+ LEFT JOIN [NestedEntity] AS [n] ON [v].[NestedId] = [n].[Id]
+) AS [t] ON [o].[Id] = [t].[OfferId]
+ORDER BY [o].[Id]
+""");
+ }
+
+ public override async Task Two_similar_complex_properties_projected_with_split_query2()
+ {
+ await base.Two_similar_complex_properties_projected_with_split_query2();
+
+ AssertSql(
+"""
+SELECT TOP(2) [o].[Id]
+FROM [Offers] AS [o]
+WHERE [o].[Id] = 1
+ORDER BY [o].[Id]
+""",
+ //
+ """
+SELECT [t0].[Id], [t0].[NestedId], [t0].[OfferId], [t0].[payment_brutto], [t0].[payment_netto], [t0].[Id0], [t0].[payment_brutto0], [t0].[payment_netto0], [t].[Id]
+FROM (
+ SELECT TOP(1) [o].[Id]
+ FROM [Offers] AS [o]
+ WHERE [o].[Id] = 1
+) AS [t]
+INNER JOIN (
+ SELECT [v].[Id], [v].[NestedId], [v].[OfferId], [v].[payment_brutto], [v].[payment_netto], [n].[Id] AS [Id0], [n].[payment_brutto] AS [payment_brutto0], [n].[payment_netto] AS [payment_netto0]
+ FROM [Variation] AS [v]
+ LEFT JOIN [NestedEntity] AS [n] ON [v].[NestedId] = [n].[Id]
+) AS [t0] ON [t].[Id] = [t0].[OfferId]
+ORDER BY [t].[Id]
+""");
+ }
+
+ public override async Task Projecting_one_of_two_similar_complex_types_picks_the_correct_one()
+ {
+ await base.Projecting_one_of_two_similar_complex_types_picks_the_correct_one();
+
+ AssertSql(
+"""
+@__p_0='10'
+
+SELECT [a].[Id], [t].[Info_Created0] AS [Created]
+FROM (
+ SELECT TOP(@__p_0) [c].[Id], [b].[AId], [b].[Info_Created] AS [Info_Created0]
+ FROM [Cs] AS [c]
+ INNER JOIN [Bs] AS [b] ON [c].[BId] = [b].[Id]
+ WHERE [b].[AId] = 1
+ ORDER BY [c].[Id]
+) AS [t]
+LEFT JOIN [As] AS [a] ON [t].[AId] = [a].[Id]
+ORDER BY [t].[Id]
+""");
+ }
+}
diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexTypeQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexTypeQuerySqlServerTest.cs
index 9c72bf3aebe..cbaf021a01c 100644
--- a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexTypeQuerySqlServerTest.cs
+++ b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexTypeQuerySqlServerTest.cs
@@ -858,6 +858,276 @@ FROM [Customer] AS [c]
""").Select(c => c.ShippingAddress).Distinct(),
ss => ss.Set().Select(c => c.ShippingAddress).Distinct());
+ public override async Task Project_same_entity_with_nested_complex_type_twice_with_pushdown(bool async)
+ {
+ await base.Project_same_entity_with_nested_complex_type_twice_with_pushdown(async);
+
+ AssertSql(
+"""
+SELECT [t].[Id], [t].[Name], [t].[BillingAddress_AddressLine1], [t].[BillingAddress_AddressLine2], [t].[BillingAddress_ZipCode], [t].[BillingAddress_Country_Code], [t].[BillingAddress_Country_FullName], [t].[ShippingAddress_AddressLine1], [t].[ShippingAddress_AddressLine2], [t].[ShippingAddress_ZipCode], [t].[ShippingAddress_Country_Code], [t].[ShippingAddress_Country_FullName], [t].[Id0], [t].[Name0], [t].[BillingAddress_AddressLine10], [t].[BillingAddress_AddressLine20], [t].[BillingAddress_ZipCode0], [t].[BillingAddress_Country_Code0], [t].[BillingAddress_Country_FullName0], [t].[ShippingAddress_AddressLine10], [t].[ShippingAddress_AddressLine20], [t].[ShippingAddress_ZipCode0], [t].[ShippingAddress_Country_Code0], [t].[ShippingAddress_Country_FullName0]
+FROM (
+ SELECT DISTINCT [c].[Id], [c].[Name], [c].[BillingAddress_AddressLine1], [c].[BillingAddress_AddressLine2], [c].[BillingAddress_ZipCode], [c].[BillingAddress_Country_Code], [c].[BillingAddress_Country_FullName], [c].[ShippingAddress_AddressLine1], [c].[ShippingAddress_AddressLine2], [c].[ShippingAddress_ZipCode], [c].[ShippingAddress_Country_Code], [c].[ShippingAddress_Country_FullName], [c0].[Id] AS [Id0], [c0].[Name] AS [Name0], [c0].[BillingAddress_AddressLine1] AS [BillingAddress_AddressLine10], [c0].[BillingAddress_AddressLine2] AS [BillingAddress_AddressLine20], [c0].[BillingAddress_ZipCode] AS [BillingAddress_ZipCode0], [c0].[BillingAddress_Country_Code] AS [BillingAddress_Country_Code0], [c0].[BillingAddress_Country_FullName] AS [BillingAddress_Country_FullName0], [c0].[ShippingAddress_AddressLine1] AS [ShippingAddress_AddressLine10], [c0].[ShippingAddress_AddressLine2] AS [ShippingAddress_AddressLine20], [c0].[ShippingAddress_ZipCode] AS [ShippingAddress_ZipCode0], [c0].[ShippingAddress_Country_Code] AS [ShippingAddress_Country_Code0], [c0].[ShippingAddress_Country_FullName] AS [ShippingAddress_Country_FullName0]
+ FROM [Customer] AS [c]
+ CROSS JOIN [Customer] AS [c0]
+) AS [t]
+""");
+ }
+
+ public override async Task Project_same_nested_complex_type_twice_with_pushdown(bool async)
+ {
+ await base.Project_same_nested_complex_type_twice_with_pushdown(async);
+
+ AssertSql(
+"""
+SELECT [t].[BillingAddress_AddressLine1], [t].[BillingAddress_AddressLine2], [t].[BillingAddress_ZipCode], [t].[BillingAddress_Country_Code], [t].[BillingAddress_Country_FullName], [t].[BillingAddress_AddressLine10], [t].[BillingAddress_AddressLine20], [t].[BillingAddress_ZipCode0], [t].[BillingAddress_Country_Code0], [t].[BillingAddress_Country_FullName0]
+FROM (
+ SELECT DISTINCT [c].[BillingAddress_AddressLine1], [c].[BillingAddress_AddressLine2], [c].[BillingAddress_ZipCode], [c].[BillingAddress_Country_Code], [c].[BillingAddress_Country_FullName], [c0].[BillingAddress_AddressLine1] AS [BillingAddress_AddressLine10], [c0].[BillingAddress_AddressLine2] AS [BillingAddress_AddressLine20], [c0].[BillingAddress_ZipCode] AS [BillingAddress_ZipCode0], [c0].[BillingAddress_Country_Code] AS [BillingAddress_Country_Code0], [c0].[BillingAddress_Country_FullName] AS [BillingAddress_Country_FullName0]
+ FROM [Customer] AS [c]
+ CROSS JOIN [Customer] AS [c0]
+) AS [t]
+""");
+ }
+
+ public override async Task Project_same_entity_with_nested_complex_type_twice_with_double_pushdown(bool async)
+ {
+ await base.Project_same_entity_with_nested_complex_type_twice_with_double_pushdown(async);
+
+ AssertSql(
+"""
+@__p_0='50'
+
+SELECT [t0].[Id], [t0].[Name], [t0].[BillingAddress_AddressLine1], [t0].[BillingAddress_AddressLine2], [t0].[BillingAddress_ZipCode], [t0].[BillingAddress_Country_Code], [t0].[BillingAddress_Country_FullName], [t0].[ShippingAddress_AddressLine1], [t0].[ShippingAddress_AddressLine2], [t0].[ShippingAddress_ZipCode], [t0].[ShippingAddress_Country_Code], [t0].[ShippingAddress_Country_FullName], [t0].[Id0], [t0].[Name0], [t0].[BillingAddress_AddressLine10], [t0].[BillingAddress_AddressLine20], [t0].[BillingAddress_ZipCode0], [t0].[BillingAddress_Country_Code0], [t0].[BillingAddress_Country_FullName0], [t0].[ShippingAddress_AddressLine10], [t0].[ShippingAddress_AddressLine20], [t0].[ShippingAddress_ZipCode0], [t0].[ShippingAddress_Country_Code0], [t0].[ShippingAddress_Country_FullName0]
+FROM (
+ SELECT DISTINCT [t].[Id], [t].[Name], [t].[BillingAddress_AddressLine1], [t].[BillingAddress_AddressLine2], [t].[BillingAddress_ZipCode], [t].[BillingAddress_Country_Code], [t].[BillingAddress_Country_FullName], [t].[ShippingAddress_AddressLine1], [t].[ShippingAddress_AddressLine2], [t].[ShippingAddress_ZipCode], [t].[ShippingAddress_Country_Code], [t].[ShippingAddress_Country_FullName], [t].[Id0], [t].[Name0], [t].[BillingAddress_AddressLine10], [t].[BillingAddress_AddressLine20], [t].[BillingAddress_ZipCode0], [t].[BillingAddress_Country_Code0], [t].[BillingAddress_Country_FullName0], [t].[ShippingAddress_AddressLine10], [t].[ShippingAddress_AddressLine20], [t].[ShippingAddress_ZipCode0], [t].[ShippingAddress_Country_Code0], [t].[ShippingAddress_Country_FullName0]
+ FROM (
+ SELECT TOP(@__p_0) [c].[Id], [c].[Name], [c].[BillingAddress_AddressLine1], [c].[BillingAddress_AddressLine2], [c].[BillingAddress_ZipCode], [c].[BillingAddress_Country_Code], [c].[BillingAddress_Country_FullName], [c].[ShippingAddress_AddressLine1], [c].[ShippingAddress_AddressLine2], [c].[ShippingAddress_ZipCode], [c].[ShippingAddress_Country_Code], [c].[ShippingAddress_Country_FullName], [c0].[Id] AS [Id0], [c0].[Name] AS [Name0], [c0].[BillingAddress_AddressLine1] AS [BillingAddress_AddressLine10], [c0].[BillingAddress_AddressLine2] AS [BillingAddress_AddressLine20], [c0].[BillingAddress_ZipCode] AS [BillingAddress_ZipCode0], [c0].[BillingAddress_Country_Code] AS [BillingAddress_Country_Code0], [c0].[BillingAddress_Country_FullName] AS [BillingAddress_Country_FullName0], [c0].[ShippingAddress_AddressLine1] AS [ShippingAddress_AddressLine10], [c0].[ShippingAddress_AddressLine2] AS [ShippingAddress_AddressLine20], [c0].[ShippingAddress_ZipCode] AS [ShippingAddress_ZipCode0], [c0].[ShippingAddress_Country_Code] AS [ShippingAddress_Country_Code0], [c0].[ShippingAddress_Country_FullName] AS [ShippingAddress_Country_FullName0]
+ FROM [Customer] AS [c]
+ CROSS JOIN [Customer] AS [c0]
+ ORDER BY [c].[Id], [c0].[Id]
+ ) AS [t]
+) AS [t0]
+""");
+ }
+
+ public override async Task Project_same_nested_complex_type_twice_with_double_pushdown(bool async)
+ {
+ await base.Project_same_nested_complex_type_twice_with_double_pushdown(async);
+
+ AssertSql(
+"""
+@__p_0='50'
+
+SELECT [t0].[BillingAddress_AddressLine1], [t0].[BillingAddress_AddressLine2], [t0].[BillingAddress_ZipCode], [t0].[BillingAddress_Country_Code], [t0].[BillingAddress_Country_FullName], [t0].[BillingAddress_AddressLine10], [t0].[BillingAddress_AddressLine20], [t0].[BillingAddress_ZipCode0], [t0].[BillingAddress_Country_Code0], [t0].[BillingAddress_Country_FullName0]
+FROM (
+ SELECT DISTINCT [t].[BillingAddress_AddressLine1], [t].[BillingAddress_AddressLine2], [t].[BillingAddress_ZipCode], [t].[BillingAddress_Country_Code], [t].[BillingAddress_Country_FullName], [t].[BillingAddress_AddressLine10], [t].[BillingAddress_AddressLine20], [t].[BillingAddress_ZipCode0], [t].[BillingAddress_Country_Code0], [t].[BillingAddress_Country_FullName0]
+ FROM (
+ SELECT TOP(@__p_0) [c].[BillingAddress_AddressLine1], [c].[BillingAddress_AddressLine2], [c].[BillingAddress_ZipCode], [c].[BillingAddress_Country_Code], [c].[BillingAddress_Country_FullName], [c0].[BillingAddress_AddressLine1] AS [BillingAddress_AddressLine10], [c0].[BillingAddress_AddressLine2] AS [BillingAddress_AddressLine20], [c0].[BillingAddress_ZipCode] AS [BillingAddress_ZipCode0], [c0].[BillingAddress_Country_Code] AS [BillingAddress_Country_Code0], [c0].[BillingAddress_Country_FullName] AS [BillingAddress_Country_FullName0]
+ FROM [Customer] AS [c]
+ CROSS JOIN [Customer] AS [c0]
+ ORDER BY [c].[Id], [c0].[Id]
+ ) AS [t]
+) AS [t0]
+""");
+ }
+
+ public override async Task Project_same_entity_with_struct_nested_complex_type_twice_with_pushdown(bool async)
+ {
+ await base.Project_same_entity_with_struct_nested_complex_type_twice_with_pushdown(async);
+
+ AssertSql(
+"""
+SELECT [t].[Id], [t].[Name], [t].[BillingAddress_AddressLine1], [t].[BillingAddress_AddressLine2], [t].[BillingAddress_ZipCode], [t].[BillingAddress_Country_Code], [t].[BillingAddress_Country_FullName], [t].[ShippingAddress_AddressLine1], [t].[ShippingAddress_AddressLine2], [t].[ShippingAddress_ZipCode], [t].[ShippingAddress_Country_Code], [t].[ShippingAddress_Country_FullName], [t].[Id0], [t].[Name0], [t].[BillingAddress_AddressLine10], [t].[BillingAddress_AddressLine20], [t].[BillingAddress_ZipCode0], [t].[BillingAddress_Country_Code0], [t].[BillingAddress_Country_FullName0], [t].[ShippingAddress_AddressLine10], [t].[ShippingAddress_AddressLine20], [t].[ShippingAddress_ZipCode0], [t].[ShippingAddress_Country_Code0], [t].[ShippingAddress_Country_FullName0]
+FROM (
+ SELECT DISTINCT [v].[Id], [v].[Name], [v].[BillingAddress_AddressLine1], [v].[BillingAddress_AddressLine2], [v].[BillingAddress_ZipCode], [v].[BillingAddress_Country_Code], [v].[BillingAddress_Country_FullName], [v].[ShippingAddress_AddressLine1], [v].[ShippingAddress_AddressLine2], [v].[ShippingAddress_ZipCode], [v].[ShippingAddress_Country_Code], [v].[ShippingAddress_Country_FullName], [v0].[Id] AS [Id0], [v0].[Name] AS [Name0], [v0].[BillingAddress_AddressLine1] AS [BillingAddress_AddressLine10], [v0].[BillingAddress_AddressLine2] AS [BillingAddress_AddressLine20], [v0].[BillingAddress_ZipCode] AS [BillingAddress_ZipCode0], [v0].[BillingAddress_Country_Code] AS [BillingAddress_Country_Code0], [v0].[BillingAddress_Country_FullName] AS [BillingAddress_Country_FullName0], [v0].[ShippingAddress_AddressLine1] AS [ShippingAddress_AddressLine10], [v0].[ShippingAddress_AddressLine2] AS [ShippingAddress_AddressLine20], [v0].[ShippingAddress_ZipCode] AS [ShippingAddress_ZipCode0], [v0].[ShippingAddress_Country_Code] AS [ShippingAddress_Country_Code0], [v0].[ShippingAddress_Country_FullName] AS [ShippingAddress_Country_FullName0]
+ FROM [ValuedCustomer] AS [v]
+ CROSS JOIN [ValuedCustomer] AS [v0]
+) AS [t]
+""");
+ }
+
+ public override async Task Project_same_struct_nested_complex_type_twice_with_pushdown(bool async)
+ {
+ await base.Project_same_struct_nested_complex_type_twice_with_pushdown(async);
+
+ AssertSql(
+"""
+SELECT [t].[BillingAddress_AddressLine1], [t].[BillingAddress_AddressLine2], [t].[BillingAddress_ZipCode], [t].[BillingAddress_Country_Code], [t].[BillingAddress_Country_FullName], [t].[BillingAddress_AddressLine10], [t].[BillingAddress_AddressLine20], [t].[BillingAddress_ZipCode0], [t].[BillingAddress_Country_Code0], [t].[BillingAddress_Country_FullName0]
+FROM (
+ SELECT DISTINCT [v].[BillingAddress_AddressLine1], [v].[BillingAddress_AddressLine2], [v].[BillingAddress_ZipCode], [v].[BillingAddress_Country_Code], [v].[BillingAddress_Country_FullName], [v0].[BillingAddress_AddressLine1] AS [BillingAddress_AddressLine10], [v0].[BillingAddress_AddressLine2] AS [BillingAddress_AddressLine20], [v0].[BillingAddress_ZipCode] AS [BillingAddress_ZipCode0], [v0].[BillingAddress_Country_Code] AS [BillingAddress_Country_Code0], [v0].[BillingAddress_Country_FullName] AS [BillingAddress_Country_FullName0]
+ FROM [ValuedCustomer] AS [v]
+ CROSS JOIN [ValuedCustomer] AS [v0]
+) AS [t]
+""");
+ }
+
+ public override async Task Project_same_entity_with_struct_nested_complex_type_twice_with_double_pushdown(bool async)
+ {
+ await base.Project_same_entity_with_struct_nested_complex_type_twice_with_double_pushdown(async);
+
+ AssertSql(
+"""
+@__p_0='50'
+
+SELECT [t0].[Id], [t0].[Name], [t0].[BillingAddress_AddressLine1], [t0].[BillingAddress_AddressLine2], [t0].[BillingAddress_ZipCode], [t0].[BillingAddress_Country_Code], [t0].[BillingAddress_Country_FullName], [t0].[ShippingAddress_AddressLine1], [t0].[ShippingAddress_AddressLine2], [t0].[ShippingAddress_ZipCode], [t0].[ShippingAddress_Country_Code], [t0].[ShippingAddress_Country_FullName], [t0].[Id0], [t0].[Name0], [t0].[BillingAddress_AddressLine10], [t0].[BillingAddress_AddressLine20], [t0].[BillingAddress_ZipCode0], [t0].[BillingAddress_Country_Code0], [t0].[BillingAddress_Country_FullName0], [t0].[ShippingAddress_AddressLine10], [t0].[ShippingAddress_AddressLine20], [t0].[ShippingAddress_ZipCode0], [t0].[ShippingAddress_Country_Code0], [t0].[ShippingAddress_Country_FullName0]
+FROM (
+ SELECT DISTINCT [t].[Id], [t].[Name], [t].[BillingAddress_AddressLine1], [t].[BillingAddress_AddressLine2], [t].[BillingAddress_ZipCode], [t].[BillingAddress_Country_Code], [t].[BillingAddress_Country_FullName], [t].[ShippingAddress_AddressLine1], [t].[ShippingAddress_AddressLine2], [t].[ShippingAddress_ZipCode], [t].[ShippingAddress_Country_Code], [t].[ShippingAddress_Country_FullName], [t].[Id0], [t].[Name0], [t].[BillingAddress_AddressLine10], [t].[BillingAddress_AddressLine20], [t].[BillingAddress_ZipCode0], [t].[BillingAddress_Country_Code0], [t].[BillingAddress_Country_FullName0], [t].[ShippingAddress_AddressLine10], [t].[ShippingAddress_AddressLine20], [t].[ShippingAddress_ZipCode0], [t].[ShippingAddress_Country_Code0], [t].[ShippingAddress_Country_FullName0]
+ FROM (
+ SELECT TOP(@__p_0) [v].[Id], [v].[Name], [v].[BillingAddress_AddressLine1], [v].[BillingAddress_AddressLine2], [v].[BillingAddress_ZipCode], [v].[BillingAddress_Country_Code], [v].[BillingAddress_Country_FullName], [v].[ShippingAddress_AddressLine1], [v].[ShippingAddress_AddressLine2], [v].[ShippingAddress_ZipCode], [v].[ShippingAddress_Country_Code], [v].[ShippingAddress_Country_FullName], [v0].[Id] AS [Id0], [v0].[Name] AS [Name0], [v0].[BillingAddress_AddressLine1] AS [BillingAddress_AddressLine10], [v0].[BillingAddress_AddressLine2] AS [BillingAddress_AddressLine20], [v0].[BillingAddress_ZipCode] AS [BillingAddress_ZipCode0], [v0].[BillingAddress_Country_Code] AS [BillingAddress_Country_Code0], [v0].[BillingAddress_Country_FullName] AS [BillingAddress_Country_FullName0], [v0].[ShippingAddress_AddressLine1] AS [ShippingAddress_AddressLine10], [v0].[ShippingAddress_AddressLine2] AS [ShippingAddress_AddressLine20], [v0].[ShippingAddress_ZipCode] AS [ShippingAddress_ZipCode0], [v0].[ShippingAddress_Country_Code] AS [ShippingAddress_Country_Code0], [v0].[ShippingAddress_Country_FullName] AS [ShippingAddress_Country_FullName0]
+ FROM [ValuedCustomer] AS [v]
+ CROSS JOIN [ValuedCustomer] AS [v0]
+ ORDER BY [v].[Id], [v0].[Id]
+ ) AS [t]
+) AS [t0]
+""");
+ }
+
+ public override async Task Project_same_struct_nested_complex_type_twice_with_double_pushdown(bool async)
+ {
+ await base.Project_same_struct_nested_complex_type_twice_with_double_pushdown(async);
+
+ AssertSql(
+"""
+@__p_0='50'
+
+SELECT [t0].[BillingAddress_AddressLine1], [t0].[BillingAddress_AddressLine2], [t0].[BillingAddress_ZipCode], [t0].[BillingAddress_Country_Code], [t0].[BillingAddress_Country_FullName], [t0].[BillingAddress_AddressLine10], [t0].[BillingAddress_AddressLine20], [t0].[BillingAddress_ZipCode0], [t0].[BillingAddress_Country_Code0], [t0].[BillingAddress_Country_FullName0]
+FROM (
+ SELECT DISTINCT [t].[BillingAddress_AddressLine1], [t].[BillingAddress_AddressLine2], [t].[BillingAddress_ZipCode], [t].[BillingAddress_Country_Code], [t].[BillingAddress_Country_FullName], [t].[BillingAddress_AddressLine10], [t].[BillingAddress_AddressLine20], [t].[BillingAddress_ZipCode0], [t].[BillingAddress_Country_Code0], [t].[BillingAddress_Country_FullName0]
+ FROM (
+ SELECT TOP(@__p_0) [v].[BillingAddress_AddressLine1], [v].[BillingAddress_AddressLine2], [v].[BillingAddress_ZipCode], [v].[BillingAddress_Country_Code], [v].[BillingAddress_Country_FullName], [v0].[BillingAddress_AddressLine1] AS [BillingAddress_AddressLine10], [v0].[BillingAddress_AddressLine2] AS [BillingAddress_AddressLine20], [v0].[BillingAddress_ZipCode] AS [BillingAddress_ZipCode0], [v0].[BillingAddress_Country_Code] AS [BillingAddress_Country_Code0], [v0].[BillingAddress_Country_FullName] AS [BillingAddress_Country_FullName0]
+ FROM [ValuedCustomer] AS [v]
+ CROSS JOIN [ValuedCustomer] AS [v0]
+ ORDER BY [v].[Id], [v0].[Id]
+ ) AS [t]
+) AS [t0]
+""");
+ }
+
+ public override async Task Union_of_same_entity_with_nested_complex_type_projected_twice_with_pushdown(bool async)
+ {
+ await base.Union_of_same_entity_with_nested_complex_type_projected_twice_with_pushdown(async);
+
+ AssertSql(
+"""
+@__p_0='50'
+
+SELECT TOP(@__p_0) [t].[Id], [t].[Name], [t].[BillingAddress_AddressLine1], [t].[BillingAddress_AddressLine2], [t].[BillingAddress_ZipCode], [t].[BillingAddress_Country_Code], [t].[BillingAddress_Country_FullName], [t].[ShippingAddress_AddressLine1], [t].[ShippingAddress_AddressLine2], [t].[ShippingAddress_ZipCode], [t].[ShippingAddress_Country_Code], [t].[ShippingAddress_Country_FullName], [t].[Id0], [t].[Name0], [t].[BillingAddress_AddressLine10], [t].[BillingAddress_AddressLine20], [t].[BillingAddress_ZipCode0], [t].[BillingAddress_Country_Code0], [t].[BillingAddress_Country_FullName0], [t].[ShippingAddress_AddressLine10], [t].[ShippingAddress_AddressLine20], [t].[ShippingAddress_ZipCode0], [t].[ShippingAddress_Country_Code0], [t].[ShippingAddress_Country_FullName0]
+FROM (
+ SELECT [c].[Id], [c].[Name], [c].[BillingAddress_AddressLine1], [c].[BillingAddress_AddressLine2], [c].[BillingAddress_ZipCode], [c].[BillingAddress_Country_Code], [c].[BillingAddress_Country_FullName], [c].[ShippingAddress_AddressLine1], [c].[ShippingAddress_AddressLine2], [c].[ShippingAddress_ZipCode], [c].[ShippingAddress_Country_Code], [c].[ShippingAddress_Country_FullName], [c0].[Id] AS [Id0], [c0].[Name] AS [Name0], [c0].[BillingAddress_AddressLine1] AS [BillingAddress_AddressLine10], [c0].[BillingAddress_AddressLine2] AS [BillingAddress_AddressLine20], [c0].[BillingAddress_ZipCode] AS [BillingAddress_ZipCode0], [c0].[BillingAddress_Country_Code] AS [BillingAddress_Country_Code0], [c0].[BillingAddress_Country_FullName] AS [BillingAddress_Country_FullName0], [c0].[ShippingAddress_AddressLine1] AS [ShippingAddress_AddressLine10], [c0].[ShippingAddress_AddressLine2] AS [ShippingAddress_AddressLine20], [c0].[ShippingAddress_ZipCode] AS [ShippingAddress_ZipCode0], [c0].[ShippingAddress_Country_Code] AS [ShippingAddress_Country_Code0], [c0].[ShippingAddress_Country_FullName] AS [ShippingAddress_Country_FullName0]
+ FROM [Customer] AS [c]
+ CROSS JOIN [Customer] AS [c0]
+ UNION
+ SELECT [c1].[Id], [c1].[Name], [c1].[BillingAddress_AddressLine1], [c1].[BillingAddress_AddressLine2], [c1].[BillingAddress_ZipCode], [c1].[BillingAddress_Country_Code], [c1].[BillingAddress_Country_FullName], [c1].[ShippingAddress_AddressLine1], [c1].[ShippingAddress_AddressLine2], [c1].[ShippingAddress_ZipCode], [c1].[ShippingAddress_Country_Code], [c1].[ShippingAddress_Country_FullName], [c2].[Id] AS [Id0], [c2].[Name] AS [Name0], [c2].[BillingAddress_AddressLine1] AS [BillingAddress_AddressLine10], [c2].[BillingAddress_AddressLine2] AS [BillingAddress_AddressLine20], [c2].[BillingAddress_ZipCode] AS [BillingAddress_ZipCode0], [c2].[BillingAddress_Country_Code] AS [BillingAddress_Country_Code0], [c2].[BillingAddress_Country_FullName] AS [BillingAddress_Country_FullName0], [c2].[ShippingAddress_AddressLine1] AS [ShippingAddress_AddressLine10], [c2].[ShippingAddress_AddressLine2] AS [ShippingAddress_AddressLine20], [c2].[ShippingAddress_ZipCode] AS [ShippingAddress_ZipCode0], [c2].[ShippingAddress_Country_Code] AS [ShippingAddress_Country_Code0], [c2].[ShippingAddress_Country_FullName] AS [ShippingAddress_Country_FullName0]
+ FROM [Customer] AS [c1]
+ CROSS JOIN [Customer] AS [c2]
+) AS [t]
+ORDER BY [t].[Id], [t].[Id0]
+""");
+ }
+
+ public override async Task Union_of_same_entity_with_nested_complex_type_projected_twice_with_double_pushdown(bool async)
+ {
+ await base.Union_of_same_entity_with_nested_complex_type_projected_twice_with_double_pushdown(async);
+
+ AssertSql(
+"""
+@__p_0='50'
+
+SELECT TOP(@__p_0) [t1].[Id], [t1].[Name], [t1].[BillingAddress_AddressLine1], [t1].[BillingAddress_AddressLine2], [t1].[BillingAddress_ZipCode], [t1].[BillingAddress_Country_Code], [t1].[BillingAddress_Country_FullName], [t1].[ShippingAddress_AddressLine1], [t1].[ShippingAddress_AddressLine2], [t1].[ShippingAddress_ZipCode], [t1].[ShippingAddress_Country_Code], [t1].[ShippingAddress_Country_FullName], [t1].[Id0], [t1].[Name0], [t1].[BillingAddress_AddressLine10], [t1].[BillingAddress_AddressLine20], [t1].[BillingAddress_ZipCode0], [t1].[BillingAddress_Country_Code0], [t1].[BillingAddress_Country_FullName0], [t1].[ShippingAddress_AddressLine10], [t1].[ShippingAddress_AddressLine20], [t1].[ShippingAddress_ZipCode0], [t1].[ShippingAddress_Country_Code0], [t1].[ShippingAddress_Country_FullName0]
+FROM (
+ SELECT DISTINCT [t0].[Id], [t0].[Name], [t0].[BillingAddress_AddressLine1], [t0].[BillingAddress_AddressLine2], [t0].[BillingAddress_ZipCode], [t0].[BillingAddress_Country_Code], [t0].[BillingAddress_Country_FullName], [t0].[ShippingAddress_AddressLine1], [t0].[ShippingAddress_AddressLine2], [t0].[ShippingAddress_ZipCode], [t0].[ShippingAddress_Country_Code], [t0].[ShippingAddress_Country_FullName], [t0].[Id0], [t0].[Name0], [t0].[BillingAddress_AddressLine10], [t0].[BillingAddress_AddressLine20], [t0].[BillingAddress_ZipCode0], [t0].[BillingAddress_Country_Code0], [t0].[BillingAddress_Country_FullName0], [t0].[ShippingAddress_AddressLine10], [t0].[ShippingAddress_AddressLine20], [t0].[ShippingAddress_ZipCode0], [t0].[ShippingAddress_Country_Code0], [t0].[ShippingAddress_Country_FullName0]
+ FROM (
+ SELECT TOP(@__p_0) [t].[Id], [t].[Name], [t].[BillingAddress_AddressLine1], [t].[BillingAddress_AddressLine2], [t].[BillingAddress_ZipCode], [t].[BillingAddress_Country_Code], [t].[BillingAddress_Country_FullName], [t].[ShippingAddress_AddressLine1], [t].[ShippingAddress_AddressLine2], [t].[ShippingAddress_ZipCode], [t].[ShippingAddress_Country_Code], [t].[ShippingAddress_Country_FullName], [t].[Id0], [t].[Name0], [t].[BillingAddress_AddressLine10], [t].[BillingAddress_AddressLine20], [t].[BillingAddress_ZipCode0], [t].[BillingAddress_Country_Code0], [t].[BillingAddress_Country_FullName0], [t].[ShippingAddress_AddressLine10], [t].[ShippingAddress_AddressLine20], [t].[ShippingAddress_ZipCode0], [t].[ShippingAddress_Country_Code0], [t].[ShippingAddress_Country_FullName0]
+ FROM (
+ SELECT [c].[Id], [c].[Name], [c].[BillingAddress_AddressLine1], [c].[BillingAddress_AddressLine2], [c].[BillingAddress_ZipCode], [c].[BillingAddress_Country_Code], [c].[BillingAddress_Country_FullName], [c].[ShippingAddress_AddressLine1], [c].[ShippingAddress_AddressLine2], [c].[ShippingAddress_ZipCode], [c].[ShippingAddress_Country_Code], [c].[ShippingAddress_Country_FullName], [c0].[Id] AS [Id0], [c0].[Name] AS [Name0], [c0].[BillingAddress_AddressLine1] AS [BillingAddress_AddressLine10], [c0].[BillingAddress_AddressLine2] AS [BillingAddress_AddressLine20], [c0].[BillingAddress_ZipCode] AS [BillingAddress_ZipCode0], [c0].[BillingAddress_Country_Code] AS [BillingAddress_Country_Code0], [c0].[BillingAddress_Country_FullName] AS [BillingAddress_Country_FullName0], [c0].[ShippingAddress_AddressLine1] AS [ShippingAddress_AddressLine10], [c0].[ShippingAddress_AddressLine2] AS [ShippingAddress_AddressLine20], [c0].[ShippingAddress_ZipCode] AS [ShippingAddress_ZipCode0], [c0].[ShippingAddress_Country_Code] AS [ShippingAddress_Country_Code0], [c0].[ShippingAddress_Country_FullName] AS [ShippingAddress_Country_FullName0]
+ FROM [Customer] AS [c]
+ CROSS JOIN [Customer] AS [c0]
+ UNION
+ SELECT [c1].[Id], [c1].[Name], [c1].[BillingAddress_AddressLine1], [c1].[BillingAddress_AddressLine2], [c1].[BillingAddress_ZipCode], [c1].[BillingAddress_Country_Code], [c1].[BillingAddress_Country_FullName], [c1].[ShippingAddress_AddressLine1], [c1].[ShippingAddress_AddressLine2], [c1].[ShippingAddress_ZipCode], [c1].[ShippingAddress_Country_Code], [c1].[ShippingAddress_Country_FullName], [c2].[Id] AS [Id0], [c2].[Name] AS [Name0], [c2].[BillingAddress_AddressLine1] AS [BillingAddress_AddressLine10], [c2].[BillingAddress_AddressLine2] AS [BillingAddress_AddressLine20], [c2].[BillingAddress_ZipCode] AS [BillingAddress_ZipCode0], [c2].[BillingAddress_Country_Code] AS [BillingAddress_Country_Code0], [c2].[BillingAddress_Country_FullName] AS [BillingAddress_Country_FullName0], [c2].[ShippingAddress_AddressLine1] AS [ShippingAddress_AddressLine10], [c2].[ShippingAddress_AddressLine2] AS [ShippingAddress_AddressLine20], [c2].[ShippingAddress_ZipCode] AS [ShippingAddress_ZipCode0], [c2].[ShippingAddress_Country_Code] AS [ShippingAddress_Country_Code0], [c2].[ShippingAddress_Country_FullName] AS [ShippingAddress_Country_FullName0]
+ FROM [Customer] AS [c1]
+ CROSS JOIN [Customer] AS [c2]
+ ) AS [t]
+ ORDER BY [t].[Id], [t].[Id0]
+ ) AS [t0]
+) AS [t1]
+ORDER BY [t1].[Id], [t1].[Id0]
+""");
+ }
+
+ public override async Task Union_of_same_nested_complex_type_projected_twice_with_pushdown(bool async)
+ {
+ await base.Union_of_same_nested_complex_type_projected_twice_with_pushdown(async);
+
+ AssertSql(
+"""
+@__p_0='50'
+
+SELECT TOP(@__p_0) [t].[BillingAddress_AddressLine1], [t].[BillingAddress_AddressLine2], [t].[BillingAddress_ZipCode], [t].[BillingAddress_Country_Code], [t].[BillingAddress_Country_FullName], [t].[BillingAddress_AddressLine10], [t].[BillingAddress_AddressLine20], [t].[BillingAddress_ZipCode0], [t].[BillingAddress_Country_Code0], [t].[BillingAddress_Country_FullName0]
+FROM (
+ SELECT [c].[BillingAddress_AddressLine1], [c].[BillingAddress_AddressLine2], [c].[BillingAddress_ZipCode], [c].[BillingAddress_Country_Code], [c].[BillingAddress_Country_FullName], [c0].[BillingAddress_AddressLine1] AS [BillingAddress_AddressLine10], [c0].[BillingAddress_AddressLine2] AS [BillingAddress_AddressLine20], [c0].[BillingAddress_ZipCode] AS [BillingAddress_ZipCode0], [c0].[BillingAddress_Country_Code] AS [BillingAddress_Country_Code0], [c0].[BillingAddress_Country_FullName] AS [BillingAddress_Country_FullName0]
+ FROM [Customer] AS [c]
+ CROSS JOIN [Customer] AS [c0]
+ UNION
+ SELECT [c1].[BillingAddress_AddressLine1], [c1].[BillingAddress_AddressLine2], [c1].[BillingAddress_ZipCode], [c1].[BillingAddress_Country_Code], [c1].[BillingAddress_Country_FullName], [c2].[BillingAddress_AddressLine1] AS [BillingAddress_AddressLine10], [c2].[BillingAddress_AddressLine2] AS [BillingAddress_AddressLine20], [c2].[BillingAddress_ZipCode] AS [BillingAddress_ZipCode0], [c2].[BillingAddress_Country_Code] AS [BillingAddress_Country_Code0], [c2].[BillingAddress_Country_FullName] AS [BillingAddress_Country_FullName0]
+ FROM [Customer] AS [c1]
+ CROSS JOIN [Customer] AS [c2]
+) AS [t]
+ORDER BY [t].[BillingAddress_ZipCode], [t].[BillingAddress_ZipCode0]
+""");
+ }
+
+ public override async Task Union_of_same_nested_complex_type_projected_twice_with_double_pushdown(bool async)
+ {
+ await base.Union_of_same_nested_complex_type_projected_twice_with_double_pushdown(async);
+
+ AssertSql(
+"""
+@__p_0='50'
+
+SELECT TOP(@__p_0) [t1].[BillingAddress_AddressLine1], [t1].[BillingAddress_AddressLine2], [t1].[BillingAddress_ZipCode], [t1].[BillingAddress_Country_Code], [t1].[BillingAddress_Country_FullName], [t1].[BillingAddress_AddressLine10], [t1].[BillingAddress_AddressLine20], [t1].[BillingAddress_ZipCode0], [t1].[BillingAddress_Country_Code0], [t1].[BillingAddress_Country_FullName0]
+FROM (
+ SELECT DISTINCT [t0].[BillingAddress_AddressLine1], [t0].[BillingAddress_AddressLine2], [t0].[BillingAddress_ZipCode], [t0].[BillingAddress_Country_Code], [t0].[BillingAddress_Country_FullName], [t0].[BillingAddress_AddressLine10], [t0].[BillingAddress_AddressLine20], [t0].[BillingAddress_ZipCode0], [t0].[BillingAddress_Country_Code0], [t0].[BillingAddress_Country_FullName0]
+ FROM (
+ SELECT TOP(@__p_0) [t].[BillingAddress_AddressLine1], [t].[BillingAddress_AddressLine2], [t].[BillingAddress_ZipCode], [t].[BillingAddress_Country_Code], [t].[BillingAddress_Country_FullName], [t].[BillingAddress_AddressLine10], [t].[BillingAddress_AddressLine20], [t].[BillingAddress_ZipCode0], [t].[BillingAddress_Country_Code0], [t].[BillingAddress_Country_FullName0]
+ FROM (
+ SELECT [c].[BillingAddress_AddressLine1], [c].[BillingAddress_AddressLine2], [c].[BillingAddress_ZipCode], [c].[BillingAddress_Country_Code], [c].[BillingAddress_Country_FullName], [c0].[BillingAddress_AddressLine1] AS [BillingAddress_AddressLine10], [c0].[BillingAddress_AddressLine2] AS [BillingAddress_AddressLine20], [c0].[BillingAddress_ZipCode] AS [BillingAddress_ZipCode0], [c0].[BillingAddress_Country_Code] AS [BillingAddress_Country_Code0], [c0].[BillingAddress_Country_FullName] AS [BillingAddress_Country_FullName0]
+ FROM [Customer] AS [c]
+ CROSS JOIN [Customer] AS [c0]
+ UNION
+ SELECT [c1].[BillingAddress_AddressLine1], [c1].[BillingAddress_AddressLine2], [c1].[BillingAddress_ZipCode], [c1].[BillingAddress_Country_Code], [c1].[BillingAddress_Country_FullName], [c2].[BillingAddress_AddressLine1] AS [BillingAddress_AddressLine10], [c2].[BillingAddress_AddressLine2] AS [BillingAddress_AddressLine20], [c2].[BillingAddress_ZipCode] AS [BillingAddress_ZipCode0], [c2].[BillingAddress_Country_Code] AS [BillingAddress_Country_Code0], [c2].[BillingAddress_Country_FullName] AS [BillingAddress_Country_FullName0]
+ FROM [Customer] AS [c1]
+ CROSS JOIN [Customer] AS [c2]
+ ) AS [t]
+ ORDER BY [t].[BillingAddress_ZipCode], [t].[BillingAddress_ZipCode0]
+ ) AS [t0]
+) AS [t1]
+ORDER BY [t1].[BillingAddress_ZipCode], [t1].[BillingAddress_ZipCode0]
+""");
+ }
+
+ public override async Task Same_entity_with_complex_type_projected_twice_with_pushdown_as_part_of_another_projection(bool async)
+ {
+ await base.Same_entity_with_complex_type_projected_twice_with_pushdown_as_part_of_another_projection(async);
+
+ AssertSql(
+"""
+SELECT [c].[Id], [t].[Id], [t].[Name], [t].[BillingAddress_AddressLine1], [t].[BillingAddress_AddressLine2], [t].[BillingAddress_ZipCode], [t].[BillingAddress_Country_Code], [t].[BillingAddress_Country_FullName], [t].[ShippingAddress_AddressLine1], [t].[ShippingAddress_AddressLine2], [t].[ShippingAddress_ZipCode], [t].[ShippingAddress_Country_Code], [t].[ShippingAddress_Country_FullName], [t].[Id0], [t].[Name0], [t].[BillingAddress_AddressLine10], [t].[BillingAddress_AddressLine20], [t].[BillingAddress_ZipCode0], [t].[BillingAddress_Country_Code0], [t].[BillingAddress_Country_FullName0], [t].[ShippingAddress_AddressLine10], [t].[ShippingAddress_AddressLine20], [t].[ShippingAddress_ZipCode0], [t].[ShippingAddress_Country_Code0], [t].[ShippingAddress_Country_FullName0], [t].[c]
+FROM [Customer] AS [c]
+OUTER APPLY (
+ SELECT TOP(1) [c0].[Id], [c0].[Name], [c0].[BillingAddress_AddressLine1], [c0].[BillingAddress_AddressLine2], [c0].[BillingAddress_ZipCode], [c0].[BillingAddress_Country_Code], [c0].[BillingAddress_Country_FullName], [c0].[ShippingAddress_AddressLine1], [c0].[ShippingAddress_AddressLine2], [c0].[ShippingAddress_ZipCode], [c0].[ShippingAddress_Country_Code], [c0].[ShippingAddress_Country_FullName], [c1].[Id] AS [Id0], [c1].[Name] AS [Name0], [c1].[BillingAddress_AddressLine1] AS [BillingAddress_AddressLine10], [c1].[BillingAddress_AddressLine2] AS [BillingAddress_AddressLine20], [c1].[BillingAddress_ZipCode] AS [BillingAddress_ZipCode0], [c1].[BillingAddress_Country_Code] AS [BillingAddress_Country_Code0], [c1].[BillingAddress_Country_FullName] AS [BillingAddress_Country_FullName0], [c1].[ShippingAddress_AddressLine1] AS [ShippingAddress_AddressLine10], [c1].[ShippingAddress_AddressLine2] AS [ShippingAddress_AddressLine20], [c1].[ShippingAddress_ZipCode] AS [ShippingAddress_ZipCode0], [c1].[ShippingAddress_Country_Code] AS [ShippingAddress_Country_Code0], [c1].[ShippingAddress_Country_FullName] AS [ShippingAddress_Country_FullName0], 1 AS [c]
+ FROM [Customer] AS [c0]
+ CROSS JOIN [Customer] AS [c1]
+ ORDER BY [c0].[Id], [c1].[Id] DESC
+) AS [t]
+""");
+ }
+
+ public override async Task Same_complex_type_projected_twice_with_pushdown_as_part_of_another_projection(bool async)
+ {
+ await base.Same_complex_type_projected_twice_with_pushdown_as_part_of_another_projection(async);
+
+ AssertSql("");
+ }
+
[ConditionalFact]
public virtual void Check_all_tests_overridden()
=> TestHelpers.AssertAllMethodsOverridden(GetType());
diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/AdHocAdvancedMappingsQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/AdHocAdvancedMappingsQuerySqliteTest.cs
new file mode 100644
index 00000000000..1807f23b4a2
--- /dev/null
+++ b/test/EFCore.Sqlite.FunctionalTests/Query/AdHocAdvancedMappingsQuerySqliteTest.cs
@@ -0,0 +1,10 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace Microsoft.EntityFrameworkCore.Query;
+
+public class AdHocAdvancedMappingsQuerySqliteTest : AdHocAdvancedMappingsQueryRelationalTestBase
+{
+ protected override ITestStoreFactory TestStoreFactory
+ => SqliteTestStoreFactory.Instance;
+}
diff --git a/test/EFCore.Sqlite.FunctionalTests/Query/ComplexTypeQuerySqliteTest.cs b/test/EFCore.Sqlite.FunctionalTests/Query/ComplexTypeQuerySqliteTest.cs
index 51c426cd289..ace097abb2a 100644
--- a/test/EFCore.Sqlite.FunctionalTests/Query/ComplexTypeQuerySqliteTest.cs
+++ b/test/EFCore.Sqlite.FunctionalTests/Query/ComplexTypeQuerySqliteTest.cs
@@ -1,6 +1,8 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using Microsoft.EntityFrameworkCore.Sqlite.Internal;
+
namespace Microsoft.EntityFrameworkCore.Query;
public class ComplexTypeQuerySqliteTest : ComplexTypeQueryRelationalTestBase<
@@ -740,6 +742,274 @@ public override async Task Union_two_different_struct_complex_type(bool async)
AssertSql();
}
+ public override async Task Project_same_entity_with_nested_complex_type_twice_with_pushdown(bool async)
+ {
+ await base.Project_same_entity_with_nested_complex_type_twice_with_pushdown(async);
+
+ AssertSql(
+"""
+SELECT "t"."Id", "t"."Name", "t"."BillingAddress_AddressLine1", "t"."BillingAddress_AddressLine2", "t"."BillingAddress_ZipCode", "t"."BillingAddress_Country_Code", "t"."BillingAddress_Country_FullName", "t"."ShippingAddress_AddressLine1", "t"."ShippingAddress_AddressLine2", "t"."ShippingAddress_ZipCode", "t"."ShippingAddress_Country_Code", "t"."ShippingAddress_Country_FullName", "t"."Id0", "t"."Name0", "t"."BillingAddress_AddressLine10", "t"."BillingAddress_AddressLine20", "t"."BillingAddress_ZipCode0", "t"."BillingAddress_Country_Code0", "t"."BillingAddress_Country_FullName0", "t"."ShippingAddress_AddressLine10", "t"."ShippingAddress_AddressLine20", "t"."ShippingAddress_ZipCode0", "t"."ShippingAddress_Country_Code0", "t"."ShippingAddress_Country_FullName0"
+FROM (
+ SELECT DISTINCT "c"."Id", "c"."Name", "c"."BillingAddress_AddressLine1", "c"."BillingAddress_AddressLine2", "c"."BillingAddress_ZipCode", "c"."BillingAddress_Country_Code", "c"."BillingAddress_Country_FullName", "c"."ShippingAddress_AddressLine1", "c"."ShippingAddress_AddressLine2", "c"."ShippingAddress_ZipCode", "c"."ShippingAddress_Country_Code", "c"."ShippingAddress_Country_FullName", "c0"."Id" AS "Id0", "c0"."Name" AS "Name0", "c0"."BillingAddress_AddressLine1" AS "BillingAddress_AddressLine10", "c0"."BillingAddress_AddressLine2" AS "BillingAddress_AddressLine20", "c0"."BillingAddress_ZipCode" AS "BillingAddress_ZipCode0", "c0"."BillingAddress_Country_Code" AS "BillingAddress_Country_Code0", "c0"."BillingAddress_Country_FullName" AS "BillingAddress_Country_FullName0", "c0"."ShippingAddress_AddressLine1" AS "ShippingAddress_AddressLine10", "c0"."ShippingAddress_AddressLine2" AS "ShippingAddress_AddressLine20", "c0"."ShippingAddress_ZipCode" AS "ShippingAddress_ZipCode0", "c0"."ShippingAddress_Country_Code" AS "ShippingAddress_Country_Code0", "c0"."ShippingAddress_Country_FullName" AS "ShippingAddress_Country_FullName0"
+ FROM "Customer" AS "c"
+ CROSS JOIN "Customer" AS "c0"
+) AS "t"
+""");
+ }
+
+ public override async Task Project_same_nested_complex_type_twice_with_pushdown(bool async)
+ {
+ await base.Project_same_nested_complex_type_twice_with_pushdown(async);
+
+ AssertSql(
+"""
+SELECT "t"."BillingAddress_AddressLine1", "t"."BillingAddress_AddressLine2", "t"."BillingAddress_ZipCode", "t"."BillingAddress_Country_Code", "t"."BillingAddress_Country_FullName", "t"."BillingAddress_AddressLine10", "t"."BillingAddress_AddressLine20", "t"."BillingAddress_ZipCode0", "t"."BillingAddress_Country_Code0", "t"."BillingAddress_Country_FullName0"
+FROM (
+ SELECT DISTINCT "c"."BillingAddress_AddressLine1", "c"."BillingAddress_AddressLine2", "c"."BillingAddress_ZipCode", "c"."BillingAddress_Country_Code", "c"."BillingAddress_Country_FullName", "c0"."BillingAddress_AddressLine1" AS "BillingAddress_AddressLine10", "c0"."BillingAddress_AddressLine2" AS "BillingAddress_AddressLine20", "c0"."BillingAddress_ZipCode" AS "BillingAddress_ZipCode0", "c0"."BillingAddress_Country_Code" AS "BillingAddress_Country_Code0", "c0"."BillingAddress_Country_FullName" AS "BillingAddress_Country_FullName0"
+ FROM "Customer" AS "c"
+ CROSS JOIN "Customer" AS "c0"
+) AS "t"
+""");
+ }
+
+ public override async Task Project_same_entity_with_nested_complex_type_twice_with_double_pushdown(bool async)
+ {
+ await base.Project_same_entity_with_nested_complex_type_twice_with_double_pushdown(async);
+
+ AssertSql(
+"""
+@__p_0='50'
+
+SELECT "t0"."Id", "t0"."Name", "t0"."BillingAddress_AddressLine1", "t0"."BillingAddress_AddressLine2", "t0"."BillingAddress_ZipCode", "t0"."BillingAddress_Country_Code", "t0"."BillingAddress_Country_FullName", "t0"."ShippingAddress_AddressLine1", "t0"."ShippingAddress_AddressLine2", "t0"."ShippingAddress_ZipCode", "t0"."ShippingAddress_Country_Code", "t0"."ShippingAddress_Country_FullName", "t0"."Id0", "t0"."Name0", "t0"."BillingAddress_AddressLine10", "t0"."BillingAddress_AddressLine20", "t0"."BillingAddress_ZipCode0", "t0"."BillingAddress_Country_Code0", "t0"."BillingAddress_Country_FullName0", "t0"."ShippingAddress_AddressLine10", "t0"."ShippingAddress_AddressLine20", "t0"."ShippingAddress_ZipCode0", "t0"."ShippingAddress_Country_Code0", "t0"."ShippingAddress_Country_FullName0"
+FROM (
+ SELECT DISTINCT "t"."Id", "t"."Name", "t"."BillingAddress_AddressLine1", "t"."BillingAddress_AddressLine2", "t"."BillingAddress_ZipCode", "t"."BillingAddress_Country_Code", "t"."BillingAddress_Country_FullName", "t"."ShippingAddress_AddressLine1", "t"."ShippingAddress_AddressLine2", "t"."ShippingAddress_ZipCode", "t"."ShippingAddress_Country_Code", "t"."ShippingAddress_Country_FullName", "t"."Id0", "t"."Name0", "t"."BillingAddress_AddressLine10", "t"."BillingAddress_AddressLine20", "t"."BillingAddress_ZipCode0", "t"."BillingAddress_Country_Code0", "t"."BillingAddress_Country_FullName0", "t"."ShippingAddress_AddressLine10", "t"."ShippingAddress_AddressLine20", "t"."ShippingAddress_ZipCode0", "t"."ShippingAddress_Country_Code0", "t"."ShippingAddress_Country_FullName0"
+ FROM (
+ SELECT "c"."Id", "c"."Name", "c"."BillingAddress_AddressLine1", "c"."BillingAddress_AddressLine2", "c"."BillingAddress_ZipCode", "c"."BillingAddress_Country_Code", "c"."BillingAddress_Country_FullName", "c"."ShippingAddress_AddressLine1", "c"."ShippingAddress_AddressLine2", "c"."ShippingAddress_ZipCode", "c"."ShippingAddress_Country_Code", "c"."ShippingAddress_Country_FullName", "c0"."Id" AS "Id0", "c0"."Name" AS "Name0", "c0"."BillingAddress_AddressLine1" AS "BillingAddress_AddressLine10", "c0"."BillingAddress_AddressLine2" AS "BillingAddress_AddressLine20", "c0"."BillingAddress_ZipCode" AS "BillingAddress_ZipCode0", "c0"."BillingAddress_Country_Code" AS "BillingAddress_Country_Code0", "c0"."BillingAddress_Country_FullName" AS "BillingAddress_Country_FullName0", "c0"."ShippingAddress_AddressLine1" AS "ShippingAddress_AddressLine10", "c0"."ShippingAddress_AddressLine2" AS "ShippingAddress_AddressLine20", "c0"."ShippingAddress_ZipCode" AS "ShippingAddress_ZipCode0", "c0"."ShippingAddress_Country_Code" AS "ShippingAddress_Country_Code0", "c0"."ShippingAddress_Country_FullName" AS "ShippingAddress_Country_FullName0"
+ FROM "Customer" AS "c"
+ CROSS JOIN "Customer" AS "c0"
+ ORDER BY "c"."Id", "c0"."Id"
+ LIMIT @__p_0
+ ) AS "t"
+) AS "t0"
+""");
+ }
+
+ public override async Task Project_same_nested_complex_type_twice_with_double_pushdown(bool async)
+ {
+ await base.Project_same_nested_complex_type_twice_with_double_pushdown(async);
+
+ AssertSql(
+"""
+@__p_0='50'
+
+SELECT "t0"."BillingAddress_AddressLine1", "t0"."BillingAddress_AddressLine2", "t0"."BillingAddress_ZipCode", "t0"."BillingAddress_Country_Code", "t0"."BillingAddress_Country_FullName", "t0"."BillingAddress_AddressLine10", "t0"."BillingAddress_AddressLine20", "t0"."BillingAddress_ZipCode0", "t0"."BillingAddress_Country_Code0", "t0"."BillingAddress_Country_FullName0"
+FROM (
+ SELECT DISTINCT "t"."BillingAddress_AddressLine1", "t"."BillingAddress_AddressLine2", "t"."BillingAddress_ZipCode", "t"."BillingAddress_Country_Code", "t"."BillingAddress_Country_FullName", "t"."BillingAddress_AddressLine10", "t"."BillingAddress_AddressLine20", "t"."BillingAddress_ZipCode0", "t"."BillingAddress_Country_Code0", "t"."BillingAddress_Country_FullName0"
+ FROM (
+ SELECT "c"."BillingAddress_AddressLine1", "c"."BillingAddress_AddressLine2", "c"."BillingAddress_ZipCode", "c"."BillingAddress_Country_Code", "c"."BillingAddress_Country_FullName", "c0"."BillingAddress_AddressLine1" AS "BillingAddress_AddressLine10", "c0"."BillingAddress_AddressLine2" AS "BillingAddress_AddressLine20", "c0"."BillingAddress_ZipCode" AS "BillingAddress_ZipCode0", "c0"."BillingAddress_Country_Code" AS "BillingAddress_Country_Code0", "c0"."BillingAddress_Country_FullName" AS "BillingAddress_Country_FullName0"
+ FROM "Customer" AS "c"
+ CROSS JOIN "Customer" AS "c0"
+ ORDER BY "c"."Id", "c0"."Id"
+ LIMIT @__p_0
+ ) AS "t"
+) AS "t0"
+""");
+ }
+
+ public override async Task Project_same_entity_with_struct_nested_complex_type_twice_with_pushdown(bool async)
+ {
+ await base.Project_same_entity_with_struct_nested_complex_type_twice_with_pushdown(async);
+
+ AssertSql(
+"""
+SELECT "t"."Id", "t"."Name", "t"."BillingAddress_AddressLine1", "t"."BillingAddress_AddressLine2", "t"."BillingAddress_ZipCode", "t"."BillingAddress_Country_Code", "t"."BillingAddress_Country_FullName", "t"."ShippingAddress_AddressLine1", "t"."ShippingAddress_AddressLine2", "t"."ShippingAddress_ZipCode", "t"."ShippingAddress_Country_Code", "t"."ShippingAddress_Country_FullName", "t"."Id0", "t"."Name0", "t"."BillingAddress_AddressLine10", "t"."BillingAddress_AddressLine20", "t"."BillingAddress_ZipCode0", "t"."BillingAddress_Country_Code0", "t"."BillingAddress_Country_FullName0", "t"."ShippingAddress_AddressLine10", "t"."ShippingAddress_AddressLine20", "t"."ShippingAddress_ZipCode0", "t"."ShippingAddress_Country_Code0", "t"."ShippingAddress_Country_FullName0"
+FROM (
+ SELECT DISTINCT "v"."Id", "v"."Name", "v"."BillingAddress_AddressLine1", "v"."BillingAddress_AddressLine2", "v"."BillingAddress_ZipCode", "v"."BillingAddress_Country_Code", "v"."BillingAddress_Country_FullName", "v"."ShippingAddress_AddressLine1", "v"."ShippingAddress_AddressLine2", "v"."ShippingAddress_ZipCode", "v"."ShippingAddress_Country_Code", "v"."ShippingAddress_Country_FullName", "v0"."Id" AS "Id0", "v0"."Name" AS "Name0", "v0"."BillingAddress_AddressLine1" AS "BillingAddress_AddressLine10", "v0"."BillingAddress_AddressLine2" AS "BillingAddress_AddressLine20", "v0"."BillingAddress_ZipCode" AS "BillingAddress_ZipCode0", "v0"."BillingAddress_Country_Code" AS "BillingAddress_Country_Code0", "v0"."BillingAddress_Country_FullName" AS "BillingAddress_Country_FullName0", "v0"."ShippingAddress_AddressLine1" AS "ShippingAddress_AddressLine10", "v0"."ShippingAddress_AddressLine2" AS "ShippingAddress_AddressLine20", "v0"."ShippingAddress_ZipCode" AS "ShippingAddress_ZipCode0", "v0"."ShippingAddress_Country_Code" AS "ShippingAddress_Country_Code0", "v0"."ShippingAddress_Country_FullName" AS "ShippingAddress_Country_FullName0"
+ FROM "ValuedCustomer" AS "v"
+ CROSS JOIN "ValuedCustomer" AS "v0"
+) AS "t"
+""");
+ }
+
+ public override async Task Project_same_struct_nested_complex_type_twice_with_pushdown(bool async)
+ {
+ await base.Project_same_struct_nested_complex_type_twice_with_pushdown(async);
+
+ AssertSql(
+"""
+SELECT "t"."BillingAddress_AddressLine1", "t"."BillingAddress_AddressLine2", "t"."BillingAddress_ZipCode", "t"."BillingAddress_Country_Code", "t"."BillingAddress_Country_FullName", "t"."BillingAddress_AddressLine10", "t"."BillingAddress_AddressLine20", "t"."BillingAddress_ZipCode0", "t"."BillingAddress_Country_Code0", "t"."BillingAddress_Country_FullName0"
+FROM (
+ SELECT DISTINCT "v"."BillingAddress_AddressLine1", "v"."BillingAddress_AddressLine2", "v"."BillingAddress_ZipCode", "v"."BillingAddress_Country_Code", "v"."BillingAddress_Country_FullName", "v0"."BillingAddress_AddressLine1" AS "BillingAddress_AddressLine10", "v0"."BillingAddress_AddressLine2" AS "BillingAddress_AddressLine20", "v0"."BillingAddress_ZipCode" AS "BillingAddress_ZipCode0", "v0"."BillingAddress_Country_Code" AS "BillingAddress_Country_Code0", "v0"."BillingAddress_Country_FullName" AS "BillingAddress_Country_FullName0"
+ FROM "ValuedCustomer" AS "v"
+ CROSS JOIN "ValuedCustomer" AS "v0"
+) AS "t"
+""");
+ }
+
+ public override async Task Project_same_entity_with_struct_nested_complex_type_twice_with_double_pushdown(bool async)
+ {
+ await base.Project_same_entity_with_struct_nested_complex_type_twice_with_double_pushdown(async);
+
+ AssertSql(
+"""
+@__p_0='50'
+
+SELECT "t0"."Id", "t0"."Name", "t0"."BillingAddress_AddressLine1", "t0"."BillingAddress_AddressLine2", "t0"."BillingAddress_ZipCode", "t0"."BillingAddress_Country_Code", "t0"."BillingAddress_Country_FullName", "t0"."ShippingAddress_AddressLine1", "t0"."ShippingAddress_AddressLine2", "t0"."ShippingAddress_ZipCode", "t0"."ShippingAddress_Country_Code", "t0"."ShippingAddress_Country_FullName", "t0"."Id0", "t0"."Name0", "t0"."BillingAddress_AddressLine10", "t0"."BillingAddress_AddressLine20", "t0"."BillingAddress_ZipCode0", "t0"."BillingAddress_Country_Code0", "t0"."BillingAddress_Country_FullName0", "t0"."ShippingAddress_AddressLine10", "t0"."ShippingAddress_AddressLine20", "t0"."ShippingAddress_ZipCode0", "t0"."ShippingAddress_Country_Code0", "t0"."ShippingAddress_Country_FullName0"
+FROM (
+ SELECT DISTINCT "t"."Id", "t"."Name", "t"."BillingAddress_AddressLine1", "t"."BillingAddress_AddressLine2", "t"."BillingAddress_ZipCode", "t"."BillingAddress_Country_Code", "t"."BillingAddress_Country_FullName", "t"."ShippingAddress_AddressLine1", "t"."ShippingAddress_AddressLine2", "t"."ShippingAddress_ZipCode", "t"."ShippingAddress_Country_Code", "t"."ShippingAddress_Country_FullName", "t"."Id0", "t"."Name0", "t"."BillingAddress_AddressLine10", "t"."BillingAddress_AddressLine20", "t"."BillingAddress_ZipCode0", "t"."BillingAddress_Country_Code0", "t"."BillingAddress_Country_FullName0", "t"."ShippingAddress_AddressLine10", "t"."ShippingAddress_AddressLine20", "t"."ShippingAddress_ZipCode0", "t"."ShippingAddress_Country_Code0", "t"."ShippingAddress_Country_FullName0"
+ FROM (
+ SELECT "v"."Id", "v"."Name", "v"."BillingAddress_AddressLine1", "v"."BillingAddress_AddressLine2", "v"."BillingAddress_ZipCode", "v"."BillingAddress_Country_Code", "v"."BillingAddress_Country_FullName", "v"."ShippingAddress_AddressLine1", "v"."ShippingAddress_AddressLine2", "v"."ShippingAddress_ZipCode", "v"."ShippingAddress_Country_Code", "v"."ShippingAddress_Country_FullName", "v0"."Id" AS "Id0", "v0"."Name" AS "Name0", "v0"."BillingAddress_AddressLine1" AS "BillingAddress_AddressLine10", "v0"."BillingAddress_AddressLine2" AS "BillingAddress_AddressLine20", "v0"."BillingAddress_ZipCode" AS "BillingAddress_ZipCode0", "v0"."BillingAddress_Country_Code" AS "BillingAddress_Country_Code0", "v0"."BillingAddress_Country_FullName" AS "BillingAddress_Country_FullName0", "v0"."ShippingAddress_AddressLine1" AS "ShippingAddress_AddressLine10", "v0"."ShippingAddress_AddressLine2" AS "ShippingAddress_AddressLine20", "v0"."ShippingAddress_ZipCode" AS "ShippingAddress_ZipCode0", "v0"."ShippingAddress_Country_Code" AS "ShippingAddress_Country_Code0", "v0"."ShippingAddress_Country_FullName" AS "ShippingAddress_Country_FullName0"
+ FROM "ValuedCustomer" AS "v"
+ CROSS JOIN "ValuedCustomer" AS "v0"
+ ORDER BY "v"."Id", "v0"."Id"
+ LIMIT @__p_0
+ ) AS "t"
+) AS "t0"
+""");
+ }
+
+ public override async Task Project_same_struct_nested_complex_type_twice_with_double_pushdown(bool async)
+ {
+ await base.Project_same_struct_nested_complex_type_twice_with_double_pushdown(async);
+
+ AssertSql(
+"""
+@__p_0='50'
+
+SELECT "t0"."BillingAddress_AddressLine1", "t0"."BillingAddress_AddressLine2", "t0"."BillingAddress_ZipCode", "t0"."BillingAddress_Country_Code", "t0"."BillingAddress_Country_FullName", "t0"."BillingAddress_AddressLine10", "t0"."BillingAddress_AddressLine20", "t0"."BillingAddress_ZipCode0", "t0"."BillingAddress_Country_Code0", "t0"."BillingAddress_Country_FullName0"
+FROM (
+ SELECT DISTINCT "t"."BillingAddress_AddressLine1", "t"."BillingAddress_AddressLine2", "t"."BillingAddress_ZipCode", "t"."BillingAddress_Country_Code", "t"."BillingAddress_Country_FullName", "t"."BillingAddress_AddressLine10", "t"."BillingAddress_AddressLine20", "t"."BillingAddress_ZipCode0", "t"."BillingAddress_Country_Code0", "t"."BillingAddress_Country_FullName0"
+ FROM (
+ SELECT "v"."BillingAddress_AddressLine1", "v"."BillingAddress_AddressLine2", "v"."BillingAddress_ZipCode", "v"."BillingAddress_Country_Code", "v"."BillingAddress_Country_FullName", "v0"."BillingAddress_AddressLine1" AS "BillingAddress_AddressLine10", "v0"."BillingAddress_AddressLine2" AS "BillingAddress_AddressLine20", "v0"."BillingAddress_ZipCode" AS "BillingAddress_ZipCode0", "v0"."BillingAddress_Country_Code" AS "BillingAddress_Country_Code0", "v0"."BillingAddress_Country_FullName" AS "BillingAddress_Country_FullName0"
+ FROM "ValuedCustomer" AS "v"
+ CROSS JOIN "ValuedCustomer" AS "v0"
+ ORDER BY "v"."Id", "v0"."Id"
+ LIMIT @__p_0
+ ) AS "t"
+) AS "t0"
+""");
+ }
+
+ public override async Task Union_of_same_entity_with_nested_complex_type_projected_twice_with_pushdown(bool async)
+ {
+ await base.Union_of_same_entity_with_nested_complex_type_projected_twice_with_pushdown(async);
+
+ AssertSql(
+"""
+@__p_0='50'
+
+SELECT "t"."Id", "t"."Name", "t"."BillingAddress_AddressLine1", "t"."BillingAddress_AddressLine2", "t"."BillingAddress_ZipCode", "t"."BillingAddress_Country_Code", "t"."BillingAddress_Country_FullName", "t"."ShippingAddress_AddressLine1", "t"."ShippingAddress_AddressLine2", "t"."ShippingAddress_ZipCode", "t"."ShippingAddress_Country_Code", "t"."ShippingAddress_Country_FullName", "t"."Id0", "t"."Name0", "t"."BillingAddress_AddressLine10", "t"."BillingAddress_AddressLine20", "t"."BillingAddress_ZipCode0", "t"."BillingAddress_Country_Code0", "t"."BillingAddress_Country_FullName0", "t"."ShippingAddress_AddressLine10", "t"."ShippingAddress_AddressLine20", "t"."ShippingAddress_ZipCode0", "t"."ShippingAddress_Country_Code0", "t"."ShippingAddress_Country_FullName0"
+FROM (
+ SELECT "c"."Id", "c"."Name", "c"."BillingAddress_AddressLine1", "c"."BillingAddress_AddressLine2", "c"."BillingAddress_ZipCode", "c"."BillingAddress_Country_Code", "c"."BillingAddress_Country_FullName", "c"."ShippingAddress_AddressLine1", "c"."ShippingAddress_AddressLine2", "c"."ShippingAddress_ZipCode", "c"."ShippingAddress_Country_Code", "c"."ShippingAddress_Country_FullName", "c0"."Id" AS "Id0", "c0"."Name" AS "Name0", "c0"."BillingAddress_AddressLine1" AS "BillingAddress_AddressLine10", "c0"."BillingAddress_AddressLine2" AS "BillingAddress_AddressLine20", "c0"."BillingAddress_ZipCode" AS "BillingAddress_ZipCode0", "c0"."BillingAddress_Country_Code" AS "BillingAddress_Country_Code0", "c0"."BillingAddress_Country_FullName" AS "BillingAddress_Country_FullName0", "c0"."ShippingAddress_AddressLine1" AS "ShippingAddress_AddressLine10", "c0"."ShippingAddress_AddressLine2" AS "ShippingAddress_AddressLine20", "c0"."ShippingAddress_ZipCode" AS "ShippingAddress_ZipCode0", "c0"."ShippingAddress_Country_Code" AS "ShippingAddress_Country_Code0", "c0"."ShippingAddress_Country_FullName" AS "ShippingAddress_Country_FullName0"
+ FROM "Customer" AS "c"
+ CROSS JOIN "Customer" AS "c0"
+ UNION
+ SELECT "c1"."Id", "c1"."Name", "c1"."BillingAddress_AddressLine1", "c1"."BillingAddress_AddressLine2", "c1"."BillingAddress_ZipCode", "c1"."BillingAddress_Country_Code", "c1"."BillingAddress_Country_FullName", "c1"."ShippingAddress_AddressLine1", "c1"."ShippingAddress_AddressLine2", "c1"."ShippingAddress_ZipCode", "c1"."ShippingAddress_Country_Code", "c1"."ShippingAddress_Country_FullName", "c2"."Id" AS "Id0", "c2"."Name" AS "Name0", "c2"."BillingAddress_AddressLine1" AS "BillingAddress_AddressLine10", "c2"."BillingAddress_AddressLine2" AS "BillingAddress_AddressLine20", "c2"."BillingAddress_ZipCode" AS "BillingAddress_ZipCode0", "c2"."BillingAddress_Country_Code" AS "BillingAddress_Country_Code0", "c2"."BillingAddress_Country_FullName" AS "BillingAddress_Country_FullName0", "c2"."ShippingAddress_AddressLine1" AS "ShippingAddress_AddressLine10", "c2"."ShippingAddress_AddressLine2" AS "ShippingAddress_AddressLine20", "c2"."ShippingAddress_ZipCode" AS "ShippingAddress_ZipCode0", "c2"."ShippingAddress_Country_Code" AS "ShippingAddress_Country_Code0", "c2"."ShippingAddress_Country_FullName" AS "ShippingAddress_Country_FullName0"
+ FROM "Customer" AS "c1"
+ CROSS JOIN "Customer" AS "c2"
+) AS "t"
+ORDER BY "t"."Id", "t"."Id0"
+LIMIT @__p_0
+""");
+ }
+
+ public override async Task Union_of_same_entity_with_nested_complex_type_projected_twice_with_double_pushdown(bool async)
+ {
+ await base.Union_of_same_entity_with_nested_complex_type_projected_twice_with_double_pushdown(async);
+
+ AssertSql(
+"""
+@__p_0='50'
+
+SELECT "t1"."Id", "t1"."Name", "t1"."BillingAddress_AddressLine1", "t1"."BillingAddress_AddressLine2", "t1"."BillingAddress_ZipCode", "t1"."BillingAddress_Country_Code", "t1"."BillingAddress_Country_FullName", "t1"."ShippingAddress_AddressLine1", "t1"."ShippingAddress_AddressLine2", "t1"."ShippingAddress_ZipCode", "t1"."ShippingAddress_Country_Code", "t1"."ShippingAddress_Country_FullName", "t1"."Id0", "t1"."Name0", "t1"."BillingAddress_AddressLine10", "t1"."BillingAddress_AddressLine20", "t1"."BillingAddress_ZipCode0", "t1"."BillingAddress_Country_Code0", "t1"."BillingAddress_Country_FullName0", "t1"."ShippingAddress_AddressLine10", "t1"."ShippingAddress_AddressLine20", "t1"."ShippingAddress_ZipCode0", "t1"."ShippingAddress_Country_Code0", "t1"."ShippingAddress_Country_FullName0"
+FROM (
+ SELECT DISTINCT "t0"."Id", "t0"."Name", "t0"."BillingAddress_AddressLine1", "t0"."BillingAddress_AddressLine2", "t0"."BillingAddress_ZipCode", "t0"."BillingAddress_Country_Code", "t0"."BillingAddress_Country_FullName", "t0"."ShippingAddress_AddressLine1", "t0"."ShippingAddress_AddressLine2", "t0"."ShippingAddress_ZipCode", "t0"."ShippingAddress_Country_Code", "t0"."ShippingAddress_Country_FullName", "t0"."Id0", "t0"."Name0", "t0"."BillingAddress_AddressLine10", "t0"."BillingAddress_AddressLine20", "t0"."BillingAddress_ZipCode0", "t0"."BillingAddress_Country_Code0", "t0"."BillingAddress_Country_FullName0", "t0"."ShippingAddress_AddressLine10", "t0"."ShippingAddress_AddressLine20", "t0"."ShippingAddress_ZipCode0", "t0"."ShippingAddress_Country_Code0", "t0"."ShippingAddress_Country_FullName0"
+ FROM (
+ SELECT "t"."Id", "t"."Name", "t"."BillingAddress_AddressLine1", "t"."BillingAddress_AddressLine2", "t"."BillingAddress_ZipCode", "t"."BillingAddress_Country_Code", "t"."BillingAddress_Country_FullName", "t"."ShippingAddress_AddressLine1", "t"."ShippingAddress_AddressLine2", "t"."ShippingAddress_ZipCode", "t"."ShippingAddress_Country_Code", "t"."ShippingAddress_Country_FullName", "t"."Id0", "t"."Name0", "t"."BillingAddress_AddressLine10", "t"."BillingAddress_AddressLine20", "t"."BillingAddress_ZipCode0", "t"."BillingAddress_Country_Code0", "t"."BillingAddress_Country_FullName0", "t"."ShippingAddress_AddressLine10", "t"."ShippingAddress_AddressLine20", "t"."ShippingAddress_ZipCode0", "t"."ShippingAddress_Country_Code0", "t"."ShippingAddress_Country_FullName0"
+ FROM (
+ SELECT "c"."Id", "c"."Name", "c"."BillingAddress_AddressLine1", "c"."BillingAddress_AddressLine2", "c"."BillingAddress_ZipCode", "c"."BillingAddress_Country_Code", "c"."BillingAddress_Country_FullName", "c"."ShippingAddress_AddressLine1", "c"."ShippingAddress_AddressLine2", "c"."ShippingAddress_ZipCode", "c"."ShippingAddress_Country_Code", "c"."ShippingAddress_Country_FullName", "c0"."Id" AS "Id0", "c0"."Name" AS "Name0", "c0"."BillingAddress_AddressLine1" AS "BillingAddress_AddressLine10", "c0"."BillingAddress_AddressLine2" AS "BillingAddress_AddressLine20", "c0"."BillingAddress_ZipCode" AS "BillingAddress_ZipCode0", "c0"."BillingAddress_Country_Code" AS "BillingAddress_Country_Code0", "c0"."BillingAddress_Country_FullName" AS "BillingAddress_Country_FullName0", "c0"."ShippingAddress_AddressLine1" AS "ShippingAddress_AddressLine10", "c0"."ShippingAddress_AddressLine2" AS "ShippingAddress_AddressLine20", "c0"."ShippingAddress_ZipCode" AS "ShippingAddress_ZipCode0", "c0"."ShippingAddress_Country_Code" AS "ShippingAddress_Country_Code0", "c0"."ShippingAddress_Country_FullName" AS "ShippingAddress_Country_FullName0"
+ FROM "Customer" AS "c"
+ CROSS JOIN "Customer" AS "c0"
+ UNION
+ SELECT "c1"."Id", "c1"."Name", "c1"."BillingAddress_AddressLine1", "c1"."BillingAddress_AddressLine2", "c1"."BillingAddress_ZipCode", "c1"."BillingAddress_Country_Code", "c1"."BillingAddress_Country_FullName", "c1"."ShippingAddress_AddressLine1", "c1"."ShippingAddress_AddressLine2", "c1"."ShippingAddress_ZipCode", "c1"."ShippingAddress_Country_Code", "c1"."ShippingAddress_Country_FullName", "c2"."Id" AS "Id0", "c2"."Name" AS "Name0", "c2"."BillingAddress_AddressLine1" AS "BillingAddress_AddressLine10", "c2"."BillingAddress_AddressLine2" AS "BillingAddress_AddressLine20", "c2"."BillingAddress_ZipCode" AS "BillingAddress_ZipCode0", "c2"."BillingAddress_Country_Code" AS "BillingAddress_Country_Code0", "c2"."BillingAddress_Country_FullName" AS "BillingAddress_Country_FullName0", "c2"."ShippingAddress_AddressLine1" AS "ShippingAddress_AddressLine10", "c2"."ShippingAddress_AddressLine2" AS "ShippingAddress_AddressLine20", "c2"."ShippingAddress_ZipCode" AS "ShippingAddress_ZipCode0", "c2"."ShippingAddress_Country_Code" AS "ShippingAddress_Country_Code0", "c2"."ShippingAddress_Country_FullName" AS "ShippingAddress_Country_FullName0"
+ FROM "Customer" AS "c1"
+ CROSS JOIN "Customer" AS "c2"
+ ) AS "t"
+ ORDER BY "t"."Id", "t"."Id0"
+ LIMIT @__p_0
+ ) AS "t0"
+) AS "t1"
+ORDER BY "t1"."Id", "t1"."Id0"
+LIMIT @__p_0
+""");
+ }
+
+ public override async Task Union_of_same_nested_complex_type_projected_twice_with_pushdown(bool async)
+ {
+ await base.Union_of_same_nested_complex_type_projected_twice_with_pushdown(async);
+
+ AssertSql(
+"""
+@__p_0='50'
+
+SELECT "t"."BillingAddress_AddressLine1", "t"."BillingAddress_AddressLine2", "t"."BillingAddress_ZipCode", "t"."BillingAddress_Country_Code", "t"."BillingAddress_Country_FullName", "t"."BillingAddress_AddressLine10", "t"."BillingAddress_AddressLine20", "t"."BillingAddress_ZipCode0", "t"."BillingAddress_Country_Code0", "t"."BillingAddress_Country_FullName0"
+FROM (
+ SELECT "c"."BillingAddress_AddressLine1", "c"."BillingAddress_AddressLine2", "c"."BillingAddress_ZipCode", "c"."BillingAddress_Country_Code", "c"."BillingAddress_Country_FullName", "c0"."BillingAddress_AddressLine1" AS "BillingAddress_AddressLine10", "c0"."BillingAddress_AddressLine2" AS "BillingAddress_AddressLine20", "c0"."BillingAddress_ZipCode" AS "BillingAddress_ZipCode0", "c0"."BillingAddress_Country_Code" AS "BillingAddress_Country_Code0", "c0"."BillingAddress_Country_FullName" AS "BillingAddress_Country_FullName0"
+ FROM "Customer" AS "c"
+ CROSS JOIN "Customer" AS "c0"
+ UNION
+ SELECT "c1"."BillingAddress_AddressLine1", "c1"."BillingAddress_AddressLine2", "c1"."BillingAddress_ZipCode", "c1"."BillingAddress_Country_Code", "c1"."BillingAddress_Country_FullName", "c2"."BillingAddress_AddressLine1" AS "BillingAddress_AddressLine10", "c2"."BillingAddress_AddressLine2" AS "BillingAddress_AddressLine20", "c2"."BillingAddress_ZipCode" AS "BillingAddress_ZipCode0", "c2"."BillingAddress_Country_Code" AS "BillingAddress_Country_Code0", "c2"."BillingAddress_Country_FullName" AS "BillingAddress_Country_FullName0"
+ FROM "Customer" AS "c1"
+ CROSS JOIN "Customer" AS "c2"
+) AS "t"
+ORDER BY "t"."BillingAddress_ZipCode", "t"."BillingAddress_ZipCode0"
+LIMIT @__p_0
+""");
+ }
+
+ public override async Task Union_of_same_nested_complex_type_projected_twice_with_double_pushdown(bool async)
+ {
+ await base.Union_of_same_nested_complex_type_projected_twice_with_double_pushdown(async);
+
+ AssertSql(
+"""
+@__p_0='50'
+
+SELECT "t1"."BillingAddress_AddressLine1", "t1"."BillingAddress_AddressLine2", "t1"."BillingAddress_ZipCode", "t1"."BillingAddress_Country_Code", "t1"."BillingAddress_Country_FullName", "t1"."BillingAddress_AddressLine10", "t1"."BillingAddress_AddressLine20", "t1"."BillingAddress_ZipCode0", "t1"."BillingAddress_Country_Code0", "t1"."BillingAddress_Country_FullName0"
+FROM (
+ SELECT DISTINCT "t0"."BillingAddress_AddressLine1", "t0"."BillingAddress_AddressLine2", "t0"."BillingAddress_ZipCode", "t0"."BillingAddress_Country_Code", "t0"."BillingAddress_Country_FullName", "t0"."BillingAddress_AddressLine10", "t0"."BillingAddress_AddressLine20", "t0"."BillingAddress_ZipCode0", "t0"."BillingAddress_Country_Code0", "t0"."BillingAddress_Country_FullName0"
+ FROM (
+ SELECT "t"."BillingAddress_AddressLine1", "t"."BillingAddress_AddressLine2", "t"."BillingAddress_ZipCode", "t"."BillingAddress_Country_Code", "t"."BillingAddress_Country_FullName", "t"."BillingAddress_AddressLine10", "t"."BillingAddress_AddressLine20", "t"."BillingAddress_ZipCode0", "t"."BillingAddress_Country_Code0", "t"."BillingAddress_Country_FullName0"
+ FROM (
+ SELECT "c"."BillingAddress_AddressLine1", "c"."BillingAddress_AddressLine2", "c"."BillingAddress_ZipCode", "c"."BillingAddress_Country_Code", "c"."BillingAddress_Country_FullName", "c0"."BillingAddress_AddressLine1" AS "BillingAddress_AddressLine10", "c0"."BillingAddress_AddressLine2" AS "BillingAddress_AddressLine20", "c0"."BillingAddress_ZipCode" AS "BillingAddress_ZipCode0", "c0"."BillingAddress_Country_Code" AS "BillingAddress_Country_Code0", "c0"."BillingAddress_Country_FullName" AS "BillingAddress_Country_FullName0"
+ FROM "Customer" AS "c"
+ CROSS JOIN "Customer" AS "c0"
+ UNION
+ SELECT "c1"."BillingAddress_AddressLine1", "c1"."BillingAddress_AddressLine2", "c1"."BillingAddress_ZipCode", "c1"."BillingAddress_Country_Code", "c1"."BillingAddress_Country_FullName", "c2"."BillingAddress_AddressLine1" AS "BillingAddress_AddressLine10", "c2"."BillingAddress_AddressLine2" AS "BillingAddress_AddressLine20", "c2"."BillingAddress_ZipCode" AS "BillingAddress_ZipCode0", "c2"."BillingAddress_Country_Code" AS "BillingAddress_Country_Code0", "c2"."BillingAddress_Country_FullName" AS "BillingAddress_Country_FullName0"
+ FROM "Customer" AS "c1"
+ CROSS JOIN "Customer" AS "c2"
+ ) AS "t"
+ ORDER BY "t"."BillingAddress_ZipCode", "t"."BillingAddress_ZipCode0"
+ LIMIT @__p_0
+ ) AS "t0"
+) AS "t1"
+ORDER BY "t1"."BillingAddress_ZipCode", "t1"."BillingAddress_ZipCode0"
+LIMIT @__p_0
+""");
+ }
+
+ public override async Task Same_entity_with_complex_type_projected_twice_with_pushdown_as_part_of_another_projection(bool async)
+ => Assert.Equal(
+ SqliteStrings.ApplyNotSupported,
+ (await Assert.ThrowsAsync(
+ () => base.Same_entity_with_complex_type_projected_twice_with_pushdown_as_part_of_another_projection(async))).Message);
+
+ public override async Task Same_complex_type_projected_twice_with_pushdown_as_part_of_another_projection(bool async)
+ => Assert.Equal(
+ SqliteStrings.ApplyNotSupported,
+ (await Assert.ThrowsAsync(
+ () => base.Same_complex_type_projected_twice_with_pushdown_as_part_of_another_projection(async))).Message);
+
[ConditionalFact]
public virtual void Check_all_tests_overridden()
=> TestHelpers.AssertAllMethodsOverridden(GetType());
From 88a162bcd211da87154b42061115e33608e4a2d6 Mon Sep 17 00:00:00 2001
From: Andriy Svyryd
Date: Fri, 8 Mar 2024 12:22:45 -0800
Subject: [PATCH 16/22] [release/8.0] Retry on 203 (#33261)
Fixes #33260
---
.../Storage/Internal/SqlServerDatabaseCreator.cs | 4 +++-
.../Internal/SqlServerTransientExceptionDetector.cs | 11 +++++++++++
2 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/src/EFCore.SqlServer/Storage/Internal/SqlServerDatabaseCreator.cs b/src/EFCore.SqlServer/Storage/Internal/SqlServerDatabaseCreator.cs
index c85be77e61c..589440790a1 100644
--- a/src/EFCore.SqlServer/Storage/Internal/SqlServerDatabaseCreator.cs
+++ b/src/EFCore.SqlServer/Storage/Internal/SqlServerDatabaseCreator.cs
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System.ComponentModel;
using System.Transactions;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore.SqlServer.Internal;
@@ -322,7 +323,8 @@ private bool RetryOnExistsFailure(SqlException exception)
// Microsoft.Data.SqlClient.SqlException: Unable to open the physical file xxxxxxx.
// And (Number 18456)
// Microsoft.Data.SqlClient.SqlException: Login failed for user 'xxxxxxx'.
- if (exception.Number is 233 or -2 or 4060 or 1832 or 5120 or 18456)
+ if ((exception.Number is 203 && exception.InnerException is Win32Exception)
+ || (exception.Number is 233 or -2 or 4060 or 1832 or 5120 or 18456))
{
ClearPool();
return true;
diff --git a/src/EFCore.SqlServer/Storage/Internal/SqlServerTransientExceptionDetector.cs b/src/EFCore.SqlServer/Storage/Internal/SqlServerTransientExceptionDetector.cs
index 766d0c0504d..6b11941e6b3 100644
--- a/src/EFCore.SqlServer/Storage/Internal/SqlServerTransientExceptionDetector.cs
+++ b/src/EFCore.SqlServer/Storage/Internal/SqlServerTransientExceptionDetector.cs
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System.ComponentModel;
using Microsoft.Data.SqlClient;
namespace Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal;
@@ -670,6 +671,16 @@ public static bool ShouldRetryOn(Exception? ex)
// allowed connections) on the server. (provider: TCP Provider, error: 0 - An existing connection was forcibly closed by
// the remote host.)
case 233:
+ return true;
+ // SQL Error Code: 203
+ // A connection was successfully established with the server, but then an error occurred during the pre-login handshake.
+ // (provider: TCP Provider, error: 0 - 20) ---> System.ComponentModel.Win32Exception (203): Unknown error: 203
+ case 203:
+ if (ex.InnerException is Win32Exception)
+ {
+ return true;
+ }
+ continue;
// SQL Error Code: 121
// The semaphore timeout period has expired
case 121:
From 1b12224410fdae2dfd1ebca9209e2701b1748352 Mon Sep 17 00:00:00 2001
From: "dotnet-maestro[bot]"
<42748379+dotnet-maestro[bot]@users.noreply.github.com>
Date: Wed, 13 Mar 2024 12:06:24 -0700
Subject: [PATCH 17/22] [release/6.0] Update dependencies from dotnet/arcade
(#33310)
Microsoft.DotNet.Arcade.Sdk , Microsoft.DotNet.Helix.Sdk
From Version 6.0.0-beta.24113.1 -> To Version 6.0.0-beta.24162.4
Co-authored-by: dotnet-maestro[bot]
---
eng/Version.Details.xml | 8 +-
eng/common/SetupNugetSources.ps1 | 26 +-
eng/common/templates-official/job/job.yml | 276 +++++++++++++++++
.../templates-official/job/onelocbuild.yml | 109 +++++++
.../job/publish-build-assets.yml | 121 ++++++++
.../templates-official/job/source-build.yml | 64 ++++
.../job/source-index-stage1.yml | 59 ++++
.../templates-official/jobs/codeql-build.yml | 31 ++
eng/common/templates-official/jobs/jobs.yml | 100 +++++++
.../templates-official/jobs/source-build.yml | 46 +++
.../post-build/common-variables.yml | 26 ++
.../post-build/post-build.yml | 277 ++++++++++++++++++
.../post-build/setup-maestro-vars.yml | 70 +++++
.../post-build/trigger-subscription.yml | 13 +
.../steps/add-build-to-channel.yml | 13 +
.../steps/component-governance.yml | 10 +
.../steps/execute-codeql.yml | 32 ++
.../steps/generate-sbom.yml | 44 +++
.../templates-official/steps/publish-logs.yml | 23 ++
.../templates-official/steps/retain-build.yml | 28 ++
.../steps/send-to-helix.yml | 94 ++++++
.../templates-official/steps/source-build.yml | 108 +++++++
.../variables/sdl-variables.yml | 7 +
global.json | 8 +-
24 files changed, 1572 insertions(+), 21 deletions(-)
create mode 100644 eng/common/templates-official/job/job.yml
create mode 100644 eng/common/templates-official/job/onelocbuild.yml
create mode 100644 eng/common/templates-official/job/publish-build-assets.yml
create mode 100644 eng/common/templates-official/job/source-build.yml
create mode 100644 eng/common/templates-official/job/source-index-stage1.yml
create mode 100644 eng/common/templates-official/jobs/codeql-build.yml
create mode 100644 eng/common/templates-official/jobs/jobs.yml
create mode 100644 eng/common/templates-official/jobs/source-build.yml
create mode 100644 eng/common/templates-official/post-build/common-variables.yml
create mode 100644 eng/common/templates-official/post-build/post-build.yml
create mode 100644 eng/common/templates-official/post-build/setup-maestro-vars.yml
create mode 100644 eng/common/templates-official/post-build/trigger-subscription.yml
create mode 100644 eng/common/templates-official/steps/add-build-to-channel.yml
create mode 100644 eng/common/templates-official/steps/component-governance.yml
create mode 100644 eng/common/templates-official/steps/execute-codeql.yml
create mode 100644 eng/common/templates-official/steps/generate-sbom.yml
create mode 100644 eng/common/templates-official/steps/publish-logs.yml
create mode 100644 eng/common/templates-official/steps/retain-build.yml
create mode 100644 eng/common/templates-official/steps/send-to-helix.yml
create mode 100644 eng/common/templates-official/steps/source-build.yml
create mode 100644 eng/common/templates-official/variables/sdl-variables.yml
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index 8a51eb1c660..f5f4b5fd540 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -47,13 +47,13 @@
-
+
https://github.com/dotnet/arcade
- 96facbceaca1e4eb498055c005088764d3b38dff
+ c80f6c7bcfdd0e62a3012f9a97ab52be477c7d75
-
+
https://github.com/dotnet/arcade
- 96facbceaca1e4eb498055c005088764d3b38dff
+ c80f6c7bcfdd0e62a3012f9a97ab52be477c7d75
diff --git a/eng/common/SetupNugetSources.ps1 b/eng/common/SetupNugetSources.ps1
index 18823840b11..0182856edd0 100644
--- a/eng/common/SetupNugetSources.ps1
+++ b/eng/common/SetupNugetSources.ps1
@@ -35,7 +35,7 @@ Set-StrictMode -Version 2.0
. $PSScriptRoot\tools.ps1
# Add source entry to PackageSources
-function AddPackageSource($sources, $SourceName, $SourceEndPoint, $creds, $Username, $Password) {
+function AddPackageSource($sources, $SourceName, $SourceEndPoint, $creds, $Username, $pwd) {
$packageSource = $sources.SelectSingleNode("add[@key='$SourceName']")
if ($packageSource -eq $null)
@@ -49,11 +49,11 @@ function AddPackageSource($sources, $SourceName, $SourceEndPoint, $creds, $Usern
Write-Host "Package source $SourceName already present."
}
- AddCredential -Creds $creds -Source $SourceName -Username $Username -Password $Password
+ AddCredential -Creds $creds -Source $SourceName -Username $Username -Password $pwd
}
# Add a credential node for the specified source
-function AddCredential($creds, $source, $username, $password) {
+function AddCredential($creds, $source, $username, $pwd) {
# Looks for credential configuration for the given SourceName. Create it if none is found.
$sourceElement = $creds.SelectSingleNode($Source)
if ($sourceElement -eq $null)
@@ -82,17 +82,17 @@ function AddCredential($creds, $source, $username, $password) {
$passwordElement.SetAttribute("key", "ClearTextPassword")
$sourceElement.AppendChild($passwordElement) | Out-Null
}
- $passwordElement.SetAttribute("value", $Password)
+ $passwordElement.SetAttribute("value", $pwd)
}
-function InsertMaestroPrivateFeedCredentials($Sources, $Creds, $Username, $Password) {
+function InsertMaestroPrivateFeedCredentials($Sources, $Creds, $Username, $pwd) {
$maestroPrivateSources = $Sources.SelectNodes("add[contains(@key,'darc-int')]")
Write-Host "Inserting credentials for $($maestroPrivateSources.Count) Maestro's private feeds."
ForEach ($PackageSource in $maestroPrivateSources) {
Write-Host "`tInserting credential for Maestro's feed:" $PackageSource.Key
- AddCredential -Creds $creds -Source $PackageSource.Key -Username $Username -Password $Password
+ AddCredential -Creds $creds -Source $PackageSource.Key -Username $Username -pwd $pwd
}
}
@@ -144,24 +144,24 @@ if ($disabledSources -ne $null) {
$userName = "dn-bot"
# Insert credential nodes for Maestro's private feeds
-InsertMaestroPrivateFeedCredentials -Sources $sources -Creds $creds -Username $userName -Password $Password
+InsertMaestroPrivateFeedCredentials -Sources $sources -Creds $creds -Username $userName -pwd $Password
$dotnet31Source = $sources.SelectSingleNode("add[@key='dotnet3.1']")
if ($dotnet31Source -ne $null) {
- AddPackageSource -Sources $sources -SourceName "dotnet3.1-internal" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal/nuget/v2" -Creds $creds -Username $userName -Password $Password
- AddPackageSource -Sources $sources -SourceName "dotnet3.1-internal-transport" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal-transport/nuget/v2" -Creds $creds -Username $userName -Password $Password
+ AddPackageSource -Sources $sources -SourceName "dotnet3.1-internal" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal/nuget/v2" -Creds $creds -Username $userName -pwd $Password
+ AddPackageSource -Sources $sources -SourceName "dotnet3.1-internal-transport" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal-transport/nuget/v2" -Creds $creds -Username $userName -pwd $Password
}
$dotnet5Source = $sources.SelectSingleNode("add[@key='dotnet5']")
if ($dotnet5Source -ne $null) {
- AddPackageSource -Sources $sources -SourceName "dotnet5-internal" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet5-internal/nuget/v2" -Creds $creds -Username $userName -Password $Password
- AddPackageSource -Sources $sources -SourceName "dotnet5-internal-transport" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet5-internal-transport/nuget/v2" -Creds $creds -Username $userName -Password $Password
+ AddPackageSource -Sources $sources -SourceName "dotnet5-internal" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet5-internal/nuget/v2" -Creds $creds -Username $userName -pwd $Password
+ AddPackageSource -Sources $sources -SourceName "dotnet5-internal-transport" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet5-internal-transport/nuget/v2" -Creds $creds -Username $userName -pwd $Password
}
$dotnet6Source = $sources.SelectSingleNode("add[@key='dotnet6']")
if ($dotnet6Source -ne $null) {
- AddPackageSource -Sources $sources -SourceName "dotnet6-internal" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet6-internal/nuget/v2" -Creds $creds -Username $userName -Password $Password
- AddPackageSource -Sources $sources -SourceName "dotnet6-internal-transport" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet6-internal-transport/nuget/v2" -Creds $creds -Username $userName -Password $Password
+ AddPackageSource -Sources $sources -SourceName "dotnet6-internal" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet6-internal/nuget/v2" -Creds $creds -Username $userName -pwd $Password
+ AddPackageSource -Sources $sources -SourceName "dotnet6-internal-transport" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet6-internal-transport/nuget/v2" -Creds $creds -Username $userName -pwd $Password
}
$doc.Save($filename)
diff --git a/eng/common/templates-official/job/job.yml b/eng/common/templates-official/job/job.yml
new file mode 100644
index 00000000000..616bfc38696
--- /dev/null
+++ b/eng/common/templates-official/job/job.yml
@@ -0,0 +1,276 @@
+# Internal resources (telemetry, microbuild) can only be accessed from non-public projects,
+# and some (Microbuild) should only be applied to non-PR cases for internal builds.
+
+parameters:
+# Job schema parameters - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#job
+ cancelTimeoutInMinutes: ''
+ condition: ''
+ container: ''
+ continueOnError: false
+ dependsOn: ''
+ displayName: ''
+ pool: ''
+ steps: []
+ strategy: ''
+ timeoutInMinutes: ''
+ variables: []
+ workspace: ''
+ templateContext: ''
+
+# Job base template specific parameters
+ # See schema documentation - https://github.com/dotnet/arcade/blob/master/Documentation/AzureDevOps/TemplateSchema.md
+ artifacts: ''
+ enableMicrobuild: false
+ enablePublishBuildArtifacts: false
+ enablePublishBuildAssets: false
+ enablePublishTestResults: false
+ enablePublishUsingPipelines: false
+ disableComponentGovernance: ''
+ mergeTestResults: false
+ testRunTitle: ''
+ testResultsFormat: ''
+ name: ''
+ preSteps: []
+ runAsPublic: false
+# Sbom related params
+ enableSbom: true
+ PackageVersion: 6.0.0
+ BuildDropPath: '$(Build.SourcesDirectory)/artifacts'
+
+jobs:
+- job: ${{ parameters.name }}
+
+ ${{ if ne(parameters.cancelTimeoutInMinutes, '') }}:
+ cancelTimeoutInMinutes: ${{ parameters.cancelTimeoutInMinutes }}
+
+ ${{ if ne(parameters.condition, '') }}:
+ condition: ${{ parameters.condition }}
+
+ ${{ if ne(parameters.container, '') }}:
+ container: ${{ parameters.container }}
+
+ ${{ if ne(parameters.continueOnError, '') }}:
+ continueOnError: ${{ parameters.continueOnError }}
+
+ ${{ if ne(parameters.dependsOn, '') }}:
+ dependsOn: ${{ parameters.dependsOn }}
+
+ ${{ if ne(parameters.displayName, '') }}:
+ displayName: ${{ parameters.displayName }}
+
+ ${{ if ne(parameters.pool, '') }}:
+ pool: ${{ parameters.pool }}
+
+ ${{ if ne(parameters.strategy, '') }}:
+ strategy: ${{ parameters.strategy }}
+
+ ${{ if ne(parameters.timeoutInMinutes, '') }}:
+ timeoutInMinutes: ${{ parameters.timeoutInMinutes }}
+
+ ${{ if ne(parameters.templateContext, '') }}:
+ templateContext: ${{ parameters.templateContext }}
+
+ variables:
+ - ${{ if ne(parameters.enableTelemetry, 'false') }}:
+ - name: DOTNET_CLI_TELEMETRY_PROFILE
+ value: '$(Build.Repository.Uri)'
+ - ${{ if eq(parameters.enableRichCodeNavigation, 'true') }}:
+ - name: EnableRichCodeNavigation
+ value: 'true'
+ # Retry signature validation up to three times, waiting 2 seconds between attempts.
+ # See https://learn.microsoft.com/en-us/nuget/reference/errors-and-warnings/nu3028#retry-untrusted-root-failures
+ - name: NUGET_EXPERIMENTAL_CHAIN_BUILD_RETRY_POLICY
+ value: 3,2000
+ - ${{ each variable in parameters.variables }}:
+ # handle name-value variable syntax
+ # example:
+ # - name: [key]
+ # value: [value]
+ - ${{ if ne(variable.name, '') }}:
+ - name: ${{ variable.name }}
+ value: ${{ variable.value }}
+
+ # handle variable groups
+ - ${{ if ne(variable.group, '') }}:
+ - group: ${{ variable.group }}
+
+ # handle key-value variable syntax.
+ # example:
+ # - [key]: [value]
+ - ${{ if and(eq(variable.name, ''), eq(variable.group, '')) }}:
+ - ${{ each pair in variable }}:
+ - name: ${{ pair.key }}
+ value: ${{ pair.value }}
+
+ # DotNet-HelixApi-Access provides 'HelixApiAccessToken' for internal builds
+ - ${{ if and(eq(parameters.enableTelemetry, 'true'), eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
+ - group: DotNet-HelixApi-Access
+
+ ${{ if ne(parameters.workspace, '') }}:
+ workspace: ${{ parameters.workspace }}
+
+ steps:
+ - ${{ if ne(parameters.preSteps, '') }}:
+ - ${{ each preStep in parameters.preSteps }}:
+ - ${{ preStep }}
+
+ - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
+ - ${{ if eq(parameters.enableMicrobuild, 'true') }}:
+ - task: MicroBuildSigningPlugin@3
+ displayName: Install MicroBuild plugin
+ inputs:
+ signType: $(_SignType)
+ zipSources: false
+ feedSource: https://dnceng.pkgs.visualstudio.com/_packaging/MicroBuildToolset/nuget/v3/index.json
+ env:
+ TeamName: $(_TeamName)
+ continueOnError: ${{ parameters.continueOnError }}
+ condition: and(succeeded(), in(variables['_SignType'], 'real', 'test'), eq(variables['Agent.Os'], 'Windows_NT'))
+
+ - task: NuGetAuthenticate@1
+
+ - ${{ if or(eq(parameters.artifacts.download, 'true'), ne(parameters.artifacts.download, '')) }}:
+ - task: DownloadPipelineArtifact@2
+ inputs:
+ buildType: current
+ artifactName: ${{ coalesce(parameters.artifacts.download.name, 'Artifacts_$(Agent.OS)_$(_BuildConfig)') }}
+ targetPath: ${{ coalesce(parameters.artifacts.download.path, 'artifacts') }}
+ itemPattern: ${{ coalesce(parameters.artifacts.download.pattern, '**') }}
+
+ - ${{ each step in parameters.steps }}:
+ - ${{ step }}
+
+ - ${{ if eq(parameters.enableRichCodeNavigation, true) }}:
+ - task: RichCodeNavIndexer@0
+ displayName: RichCodeNav Upload
+ inputs:
+ languages: ${{ coalesce(parameters.richCodeNavigationLanguage, 'csharp') }}
+ environment: ${{ coalesce(parameters.richCodeNavigationEnvironment, 'production') }}
+ richNavLogOutputDirectory: $(Build.SourcesDirectory)/artifacts/bin
+ continueOnError: true
+
+ - template: /eng/common/templates-official/steps/component-governance.yml
+ parameters:
+ ${{ if eq(parameters.disableComponentGovernance, '') }}:
+ ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest'), eq(parameters.runAsPublic, 'false'), or(startsWith(variables['Build.SourceBranch'], 'refs/heads/release/'), startsWith(variables['Build.SourceBranch'], 'refs/heads/dotnet/'), startsWith(variables['Build.SourceBranch'], 'refs/heads/microsoft/'), eq(variables['Build.SourceBranch'], 'refs/heads/main'))) }}:
+ disableComponentGovernance: false
+ ${{ else }}:
+ disableComponentGovernance: true
+ ${{ else }}:
+ disableComponentGovernance: ${{ parameters.disableComponentGovernance }}
+
+ - ${{ if eq(parameters.enableMicrobuild, 'true') }}:
+ - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
+ - task: MicroBuildCleanup@1
+ displayName: Execute Microbuild cleanup tasks
+ condition: and(always(), in(variables['_SignType'], 'real', 'test'), eq(variables['Agent.Os'], 'Windows_NT'))
+ continueOnError: ${{ parameters.continueOnError }}
+ env:
+ TeamName: $(_TeamName)
+
+ - ${{ if ne(parameters.artifacts.publish, '') }}:
+ - ${{ if or(eq(parameters.artifacts.publish.artifacts, 'true'), ne(parameters.artifacts.publish.artifacts, '')) }}:
+ - task: CopyFiles@2
+ displayName: Gather binaries for publish to artifacts
+ inputs:
+ SourceFolder: 'artifacts/bin'
+ Contents: '**'
+ TargetFolder: '$(Build.ArtifactStagingDirectory)/artifacts/bin'
+ - task: CopyFiles@2
+ displayName: Gather packages for publish to artifacts
+ inputs:
+ SourceFolder: 'artifacts/packages'
+ Contents: '**'
+ TargetFolder: '$(Build.ArtifactStagingDirectory)/artifacts/packages'
+ - task: 1ES.PublishBuildArtifacts@1
+ displayName: Publish pipeline artifacts
+ inputs:
+ PathtoPublish: '$(Build.ArtifactStagingDirectory)/artifacts'
+ PublishLocation: Container
+ ArtifactName: ${{ coalesce(parameters.artifacts.publish.artifacts.name , 'Artifacts_$(Agent.Os)_$(_BuildConfig)') }}
+ continueOnError: true
+ condition: always()
+ - ${{ if or(eq(parameters.artifacts.publish.logs, 'true'), ne(parameters.artifacts.publish.logs, '')) }}:
+ - task: 1ES.PublishPipelineArtifact@1
+ inputs:
+ targetPath: 'artifacts/log'
+ artifactName: ${{ coalesce(parameters.artifacts.publish.logs.name, 'Logs_Build_$(Agent.Os)_$(_BuildConfig)') }}
+ displayName: 'Publish logs'
+ continueOnError: true
+ condition: always()
+
+ - ${{ if or(eq(parameters.artifacts.publish.manifests, 'true'), ne(parameters.artifacts.publish.manifests, '')) }}:
+ - ${{ if and(ne(parameters.enablePublishUsingPipelines, 'true'), eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
+ - task: CopyFiles@2
+ displayName: Gather Asset Manifests
+ inputs:
+ SourceFolder: '$(Build.SourcesDirectory)/artifacts/log/$(_BuildConfig)/AssetManifest'
+ TargetFolder: '$(Build.ArtifactStagingDirectory)/AssetManifests'
+ continueOnError: ${{ parameters.continueOnError }}
+ condition: and(succeeded(), eq(variables['_DotNetPublishToBlobFeed'], 'true'))
+
+ - task: 1ES.PublishBuildArtifacts@1
+ displayName: Push Asset Manifests
+ inputs:
+ PathtoPublish: '$(Build.ArtifactStagingDirectory)/AssetManifests'
+ PublishLocation: Container
+ ArtifactName: AssetManifests
+ continueOnError: ${{ parameters.continueOnError }}
+ condition: and(succeeded(), eq(variables['_DotNetPublishToBlobFeed'], 'true'))
+
+ - ${{ if ne(parameters.enablePublishBuildArtifacts, 'false') }}:
+ - task: 1ES.PublishBuildArtifacts@1
+ displayName: Publish Logs
+ inputs:
+ PathtoPublish: '$(Build.SourcesDirectory)/artifacts/log/$(_BuildConfig)'
+ PublishLocation: Container
+ ArtifactName: ${{ coalesce(parameters.enablePublishBuildArtifacts.artifactName, '$(Agent.Os)_$(Agent.JobName)' ) }}
+ continueOnError: true
+ condition: always()
+
+ - ${{ if or(and(eq(parameters.enablePublishTestResults, 'true'), eq(parameters.testResultsFormat, '')), eq(parameters.testResultsFormat, 'xunit')) }}:
+ - task: PublishTestResults@2
+ displayName: Publish XUnit Test Results
+ inputs:
+ testResultsFormat: 'xUnit'
+ testResultsFiles: '*.xml'
+ searchFolder: '$(Build.SourcesDirectory)/artifacts/TestResults/$(_BuildConfig)'
+ testRunTitle: ${{ coalesce(parameters.testRunTitle, parameters.name, '$(System.JobName)') }}-xunit
+ mergeTestResults: ${{ parameters.mergeTestResults }}
+ continueOnError: true
+ condition: always()
+ - ${{ if or(and(eq(parameters.enablePublishTestResults, 'true'), eq(parameters.testResultsFormat, '')), eq(parameters.testResultsFormat, 'vstest')) }}:
+ - task: PublishTestResults@2
+ displayName: Publish TRX Test Results
+ inputs:
+ testResultsFormat: 'VSTest'
+ testResultsFiles: '*.trx'
+ searchFolder: '$(Build.SourcesDirectory)/artifacts/TestResults/$(_BuildConfig)'
+ testRunTitle: ${{ coalesce(parameters.testRunTitle, parameters.name, '$(System.JobName)') }}-trx
+ mergeTestResults: ${{ parameters.mergeTestResults }}
+ continueOnError: true
+ condition: always()
+
+ - ${{ if and(eq(parameters.enablePublishBuildAssets, true), ne(parameters.enablePublishUsingPipelines, 'true'), eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
+ - task: CopyFiles@2
+ displayName: Gather Asset Manifests
+ inputs:
+ SourceFolder: '$(Build.SourcesDirectory)/artifacts/log/$(_BuildConfig)/AssetManifest'
+ TargetFolder: '$(Build.StagingDirectory)/AssetManifests'
+ continueOnError: ${{ parameters.continueOnError }}
+ condition: and(succeeded(), eq(variables['_DotNetPublishToBlobFeed'], 'true'))
+
+ - task: 1ES.PublishBuildArtifacts@1
+ displayName: Push Asset Manifests
+ inputs:
+ PathtoPublish: '$(Build.StagingDirectory)/AssetManifests'
+ PublishLocation: Container
+ ArtifactName: AssetManifests
+ continueOnError: ${{ parameters.continueOnError }}
+ condition: and(succeeded(), eq(variables['_DotNetPublishToBlobFeed'], 'true'))
+
+ - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest'), eq(parameters.enableSbom, 'true')) }}:
+ - template: /eng/common/templates-official/steps/generate-sbom.yml
+ parameters:
+ PackageVersion: ${{ parameters.packageVersion}}
+ BuildDropPath: ${{ parameters.buildDropPath }}
diff --git a/eng/common/templates-official/job/onelocbuild.yml b/eng/common/templates-official/job/onelocbuild.yml
new file mode 100644
index 00000000000..e0e9a4bc512
--- /dev/null
+++ b/eng/common/templates-official/job/onelocbuild.yml
@@ -0,0 +1,109 @@
+parameters:
+ # Optional: dependencies of the job
+ dependsOn: ''
+
+ # Optional: A defined YAML pool - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#pool
+ pool: ''
+
+ CeapexPat: $(dn-bot-ceapex-package-r) # PAT for the loc AzDO instance https://dev.azure.com/ceapex
+ GithubPat: $(BotAccount-dotnet-bot-repo-PAT)
+
+ SourcesDirectory: $(Build.SourcesDirectory)
+ CreatePr: true
+ AutoCompletePr: false
+ ReusePr: true
+ UseLfLineEndings: true
+ UseCheckedInLocProjectJson: false
+ LanguageSet: VS_Main_Languages
+ LclSource: lclFilesInRepo
+ LclPackageId: ''
+ RepoType: gitHub
+ GitHubOrg: dotnet
+ MirrorRepo: ''
+ MirrorBranch: main
+ condition: ''
+
+jobs:
+- job: OneLocBuild
+
+ dependsOn: ${{ parameters.dependsOn }}
+
+ displayName: OneLocBuild
+
+ ${{ if ne(parameters.pool, '') }}:
+ pool: ${{ parameters.pool }}
+ ${{ if eq(parameters.pool, '') }}:
+ pool:
+ # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com)
+ ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}:
+ name: AzurePipelines-EO
+ image: 1ESPT-Windows2022
+ demands: Cmd
+ os: windows
+ # If it's not devdiv, it's dnceng
+ ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}:
+ name: NetCore1ESPool-Svc-Internal
+ image: 1es-windows-2022-pt
+ os: windows
+
+ variables:
+ - group: OneLocBuildVariables # Contains the CeapexPat and GithubPat
+ - name: _GenerateLocProjectArguments
+ value: -SourcesDirectory ${{ parameters.SourcesDirectory }}
+ -LanguageSet "${{ parameters.LanguageSet }}"
+ -CreateNeutralXlfs
+ - ${{ if eq(parameters.UseCheckedInLocProjectJson, 'true') }}:
+ - name: _GenerateLocProjectArguments
+ value: ${{ variables._GenerateLocProjectArguments }} -UseCheckedInLocProjectJson
+
+
+ steps:
+ - task: Powershell@2
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/common/generate-locproject.ps1
+ arguments: $(_GenerateLocProjectArguments)
+ displayName: Generate LocProject.json
+ condition: ${{ parameters.condition }}
+
+ - task: OneLocBuild@2
+ displayName: OneLocBuild
+ env:
+ SYSTEM_ACCESSTOKEN: $(System.AccessToken)
+ inputs:
+ locProj: eng/Localize/LocProject.json
+ outDir: $(Build.ArtifactStagingDirectory)
+ lclSource: ${{ parameters.LclSource }}
+ lclPackageId: ${{ parameters.LclPackageId }}
+ isCreatePrSelected: ${{ parameters.CreatePr }}
+ ${{ if eq(parameters.CreatePr, true) }}:
+ isAutoCompletePrSelected: ${{ parameters.AutoCompletePr }}
+ isUseLfLineEndingsSelected: ${{ parameters.UseLfLineEndings }}
+ ${{ if eq(parameters.RepoType, 'gitHub') }}:
+ isShouldReusePrSelected: ${{ parameters.ReusePr }}
+ packageSourceAuth: patAuth
+ patVariable: ${{ parameters.CeapexPat }}
+ ${{ if eq(parameters.RepoType, 'gitHub') }}:
+ repoType: ${{ parameters.RepoType }}
+ gitHubPatVariable: "${{ parameters.GithubPat }}"
+ ${{ if ne(parameters.MirrorRepo, '') }}:
+ isMirrorRepoSelected: true
+ gitHubOrganization: ${{ parameters.GitHubOrg }}
+ mirrorRepo: ${{ parameters.MirrorRepo }}
+ mirrorBranch: ${{ parameters.MirrorBranch }}
+ condition: ${{ parameters.condition }}
+
+ - task: 1ES.PublishBuildArtifacts@1
+ displayName: Publish Localization Files
+ inputs:
+ PathtoPublish: '$(Build.ArtifactStagingDirectory)/loc'
+ PublishLocation: Container
+ ArtifactName: Loc
+ condition: ${{ parameters.condition }}
+
+ - task: 1ES.PublishBuildArtifacts@1
+ displayName: Publish LocProject.json
+ inputs:
+ PathtoPublish: '$(Build.SourcesDirectory)/eng/Localize/'
+ PublishLocation: Container
+ ArtifactName: Loc
+ condition: ${{ parameters.condition }}
\ No newline at end of file
diff --git a/eng/common/templates-official/job/publish-build-assets.yml b/eng/common/templates-official/job/publish-build-assets.yml
new file mode 100644
index 00000000000..9498aa412db
--- /dev/null
+++ b/eng/common/templates-official/job/publish-build-assets.yml
@@ -0,0 +1,121 @@
+parameters:
+ configuration: 'Debug'
+
+ # Optional: condition for the job to run
+ condition: ''
+
+ # Optional: 'true' if future jobs should run even if this job fails
+ continueOnError: false
+
+ # Optional: dependencies of the job
+ dependsOn: ''
+
+ # Optional: Include PublishBuildArtifacts task
+ enablePublishBuildArtifacts: false
+
+ # Optional: A defined YAML pool - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#pool
+ pool: {}
+
+ # Optional: should run as a public build even in the internal project
+ # if 'true', the build won't run any of the internal only steps, even if it is running in non-public projects.
+ runAsPublic: false
+
+ # Optional: whether the build's artifacts will be published using release pipelines or direct feed publishing
+ publishUsingPipelines: false
+
+jobs:
+- job: Asset_Registry_Publish
+
+ dependsOn: ${{ parameters.dependsOn }}
+
+ displayName: Publish to Build Asset Registry
+
+ pool: ${{ parameters.pool }}
+
+ variables:
+ - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
+ - name: _BuildConfig
+ value: ${{ parameters.configuration }}
+ - group: Publish-Build-Assets
+ - group: AzureDevOps-Artifact-Feeds-Pats
+ - name: runCodesignValidationInjection
+ value: false
+
+ steps:
+ - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
+ - task: DownloadBuildArtifacts@0
+ displayName: Download artifact
+ inputs:
+ artifactName: AssetManifests
+ downloadPath: '$(Build.StagingDirectory)/Download'
+ checkDownloadedFiles: true
+ condition: ${{ parameters.condition }}
+ continueOnError: ${{ parameters.continueOnError }}
+
+ - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
+ - task: NuGetAuthenticate@1
+
+ - task: PowerShell@2
+ displayName: Enable cross-org NuGet feed authentication
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/common/enable-cross-org-publishing.ps1
+ arguments: -token $(dn-bot-all-orgs-artifact-feeds-rw)
+
+ - task: PowerShell@2
+ displayName: Publish Build Assets
+ inputs:
+ filePath: eng\common\sdk-task.ps1
+ arguments: -task PublishBuildAssets -restore -msbuildEngine dotnet
+ /p:ManifestsPath='$(Build.StagingDirectory)/Download/AssetManifests'
+ /p:BuildAssetRegistryToken=$(MaestroAccessToken)
+ /p:MaestroApiEndpoint=https://maestro.dot.net
+ /p:PublishUsingPipelines=${{ parameters.publishUsingPipelines }}
+ /p:Configuration=$(_BuildConfig)
+ /p:OfficialBuildId=$(Build.BuildNumber)
+ condition: ${{ parameters.condition }}
+ continueOnError: ${{ parameters.continueOnError }}
+
+ - task: powershell@2
+ displayName: Create ReleaseConfigs Artifact
+ inputs:
+ targetType: inline
+ script: |
+ Add-Content -Path "$(Build.StagingDirectory)/ReleaseConfigs.txt" -Value $(BARBuildId)
+ Add-Content -Path "$(Build.StagingDirectory)/ReleaseConfigs.txt" -Value "$(DefaultChannels)"
+ Add-Content -Path "$(Build.StagingDirectory)/ReleaseConfigs.txt" -Value $(IsStableBuild)
+
+ - task: 1ES.PublishBuildArtifacts@1
+ displayName: Publish ReleaseConfigs Artifact
+ inputs:
+ PathtoPublish: '$(Build.StagingDirectory)/ReleaseConfigs.txt'
+ PublishLocation: Container
+ ArtifactName: ReleaseConfigs
+
+ - task: powershell@2
+ displayName: Check if SymbolPublishingExclusionsFile.txt exists
+ inputs:
+ targetType: inline
+ script: |
+ $symbolExclusionfile = "$(Build.SourcesDirectory)/eng/SymbolPublishingExclusionsFile.txt"
+ if(Test-Path -Path $symbolExclusionfile)
+ {
+ Write-Host "SymbolExclusionFile exists"
+ Write-Host "##vso[task.setvariable variable=SymbolExclusionFile]true"
+ }
+ else{
+ Write-Host "Symbols Exclusion file does not exists"
+ Write-Host "##vso[task.setvariable variable=SymbolExclusionFile]false"
+ }
+
+ - task: 1ES.PublishBuildArtifacts@1
+ displayName: Publish SymbolPublishingExclusionsFile Artifact
+ condition: eq(variables['SymbolExclusionFile'], 'true')
+ inputs:
+ PathtoPublish: '$(Build.SourcesDirectory)/eng/SymbolPublishingExclusionsFile.txt'
+ PublishLocation: Container
+ ArtifactName: ReleaseConfigs
+
+ - ${{ if eq(parameters.enablePublishBuildArtifacts, 'true') }}:
+ - template: /eng/common/templates-official/steps/publish-logs.yml
+ parameters:
+ JobLabel: 'Publish_Artifacts_Logs'
diff --git a/eng/common/templates-official/job/source-build.yml b/eng/common/templates-official/job/source-build.yml
new file mode 100644
index 00000000000..96be5e6e115
--- /dev/null
+++ b/eng/common/templates-official/job/source-build.yml
@@ -0,0 +1,64 @@
+parameters:
+ # This template adds arcade-powered source-build to CI. The template produces a server job with a
+ # default ID 'Source_Build_Complete' to put in a dependency list if necessary.
+
+ # Specifies the prefix for source-build jobs added to pipeline. Use this if disambiguation needed.
+ jobNamePrefix: 'Source_Build'
+
+ # Defines the platform on which to run the job. By default, a linux-x64 machine, suitable for
+ # managed-only repositories. This is an object with these properties:
+ #
+ # name: ''
+ # The name of the job. This is included in the job ID.
+ # targetRID: ''
+ # The name of the target RID to use, instead of the one auto-detected by Arcade.
+ # nonPortable: false
+ # Enables non-portable mode. This means a more specific RID (e.g. fedora.32-x64 rather than
+ # linux-x64), and compiling against distro-provided packages rather than portable ones.
+ # skipPublishValidation: false
+ # Disables publishing validation. By default, a check is performed to ensure no packages are
+ # published by source-build.
+ # container: ''
+ # A container to use. Runs in docker.
+ # pool: {}
+ # A pool to use. Runs directly on an agent.
+ # buildScript: ''
+ # Specifies the build script to invoke to perform the build in the repo. The default
+ # './build.sh' should work for typical Arcade repositories, but this is customizable for
+ # difficult situations.
+ # jobProperties: {}
+ # A list of job properties to inject at the top level, for potential extensibility beyond
+ # container and pool.
+ platform: {}
+
+jobs:
+- job: ${{ parameters.jobNamePrefix }}_${{ parameters.platform.name }}
+ displayName: Source-Build (${{ parameters.platform.name }})
+
+ ${{ each property in parameters.platform.jobProperties }}:
+ ${{ property.key }}: ${{ property.value }}
+
+ ${{ if ne(parameters.platform.container, '') }}:
+ container: ${{ parameters.platform.container }}
+
+ ${{ if eq(parameters.platform.pool, '') }}:
+ # The default VM host AzDO pool. This should be capable of running Docker containers: almost all
+ # source-build builds run in Docker, including the default managed platform.
+ pool:
+ ${{ if eq(variables['System.TeamProject'], 'public') }}:
+ name: NetCore-Svc-Public
+ demands: ImageOverride -equals Build.Ubuntu.1804.Amd64.Open
+ ${{ if eq(variables['System.TeamProject'], 'internal') }}:
+ name: NetCore1ESPool-Svc-Internal
+ image: 1es-mariner-2-pt
+ os: linux
+ ${{ if ne(parameters.platform.pool, '') }}:
+ pool: ${{ parameters.platform.pool }}
+
+ workspace:
+ clean: all
+
+ steps:
+ - template: /eng/common/templates-official/steps/source-build.yml
+ parameters:
+ platform: ${{ parameters.platform }}
diff --git a/eng/common/templates-official/job/source-index-stage1.yml b/eng/common/templates-official/job/source-index-stage1.yml
new file mode 100644
index 00000000000..3d8b0b966cb
--- /dev/null
+++ b/eng/common/templates-official/job/source-index-stage1.yml
@@ -0,0 +1,59 @@
+parameters:
+ runAsPublic: false
+ sourceIndexPackageVersion: 1.0.1-20210614.1
+ sourceIndexPackageSource: https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json
+ sourceIndexBuildCommand: powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -Command "eng/common/build.ps1 -restore -build -binarylog -ci"
+ preSteps: []
+ binlogPath: artifacts/log/Debug/Build.binlog
+ pool:
+ name: NetCore1ESPool-Svc-Internal
+ image: 1es-windows-2022-pt
+ os: windows
+ condition: ''
+ dependsOn: ''
+
+jobs:
+- job: SourceIndexStage1
+ dependsOn: ${{ parameters.dependsOn }}
+ condition: ${{ parameters.condition }}
+ variables:
+ - name: SourceIndexPackageVersion
+ value: ${{ parameters.sourceIndexPackageVersion }}
+ - name: SourceIndexPackageSource
+ value: ${{ parameters.sourceIndexPackageSource }}
+ - name: BinlogPath
+ value: ${{ parameters.binlogPath }}
+ - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
+ - group: source-dot-net stage1 variables
+
+ pool: ${{ parameters.pool }}
+ steps:
+ - ${{ each preStep in parameters.preSteps }}:
+ - ${{ preStep }}
+
+ - task: UseDotNet@2
+ displayName: Use .NET Core sdk 3.1
+ inputs:
+ packageType: sdk
+ version: 3.1.x
+ installationPath: $(Agent.TempDirectory)/dotnet
+ workingDirectory: $(Agent.TempDirectory)
+
+ - script: |
+ $(Agent.TempDirectory)/dotnet/dotnet tool install BinLogToSln --version $(SourceIndexPackageVersion) --add-source $(SourceIndexPackageSource) --tool-path $(Agent.TempDirectory)/.source-index/tools
+ $(Agent.TempDirectory)/dotnet/dotnet tool install UploadIndexStage1 --version $(SourceIndexPackageVersion) --add-source $(SourceIndexPackageSource) --tool-path $(Agent.TempDirectory)/.source-index/tools
+ displayName: Download Tools
+ # Set working directory to temp directory so 'dotnet' doesn't try to use global.json and use the repo's sdk.
+ workingDirectory: $(Agent.TempDirectory)
+
+ - script: ${{ parameters.sourceIndexBuildCommand }}
+ displayName: Build Repository
+
+ - script: $(Agent.TempDirectory)/.source-index/tools/BinLogToSln -i $(BinlogPath) -r $(Build.SourcesDirectory) -n $(Build.Repository.Name) -o .source-index/stage1output
+ displayName: Process Binlog into indexable sln
+
+ - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
+ - script: $(Agent.TempDirectory)/.source-index/tools/UploadIndexStage1 -i .source-index/stage1output -n $(Build.Repository.Name)
+ displayName: Upload stage1 artifacts to source index
+ env:
+ BLOB_CONTAINER_URL: $(source-dot-net-stage1-blob-container-url)
diff --git a/eng/common/templates-official/jobs/codeql-build.yml b/eng/common/templates-official/jobs/codeql-build.yml
new file mode 100644
index 00000000000..0bf7ee29f40
--- /dev/null
+++ b/eng/common/templates-official/jobs/codeql-build.yml
@@ -0,0 +1,31 @@
+parameters:
+ # See schema documentation in /Documentation/AzureDevOps/TemplateSchema.md
+ continueOnError: false
+ # Required: A collection of jobs to run - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#job
+ jobs: []
+ # Optional: if specified, restore and use this version of Guardian instead of the default.
+ overrideGuardianVersion: ''
+
+jobs:
+- template: /eng/common/templates-official/jobs/jobs.yml
+ parameters:
+ enableMicrobuild: false
+ enablePublishBuildArtifacts: false
+ enablePublishTestResults: false
+ enablePublishBuildAssets: false
+ enablePublishUsingPipelines: false
+ enableTelemetry: true
+
+ variables:
+ - group: Publish-Build-Assets
+ # The Guardian version specified in 'eng/common/sdl/packages.config'. This value must be kept in
+ # sync with the packages.config file.
+ - name: DefaultGuardianVersion
+ value: 0.110.1
+ - name: GuardianPackagesConfigFile
+ value: $(Build.SourcesDirectory)\eng\common\sdl\packages.config
+ - name: GuardianVersion
+ value: ${{ coalesce(parameters.overrideGuardianVersion, '$(DefaultGuardianVersion)') }}
+
+ jobs: ${{ parameters.jobs }}
+
diff --git a/eng/common/templates-official/jobs/jobs.yml b/eng/common/templates-official/jobs/jobs.yml
new file mode 100644
index 00000000000..669ccd48f7f
--- /dev/null
+++ b/eng/common/templates-official/jobs/jobs.yml
@@ -0,0 +1,100 @@
+parameters:
+ # See schema documentation in /Documentation/AzureDevOps/TemplateSchema.md
+ continueOnError: false
+
+ # Optional: Include PublishBuildArtifacts task
+ enablePublishBuildArtifacts: false
+
+ # Optional: Enable publishing using release pipelines
+ enablePublishUsingPipelines: false
+
+ # Optional: Enable running the source-build jobs to build repo from source
+ enableSourceBuild: false
+
+ # Optional: Parameters for source-build template.
+ # See /eng/common/templates-official/jobs/source-build.yml for options
+ sourceBuildParameters: []
+
+ graphFileGeneration:
+ # Optional: Enable generating the graph files at the end of the build
+ enabled: false
+ # Optional: Include toolset dependencies in the generated graph files
+ includeToolset: false
+
+ # Required: A collection of jobs to run - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#job
+ jobs: []
+
+ # Optional: Override automatically derived dependsOn value for "publish build assets" job
+ publishBuildAssetsDependsOn: ''
+
+ # Optional: should run as a public build even in the internal project
+ # if 'true', the build won't run any of the internal only steps, even if it is running in non-public projects.
+ runAsPublic: false
+
+ enableSourceIndex: false
+ sourceIndexParams: {}
+
+# Internal resources (telemetry, microbuild) can only be accessed from non-public projects,
+# and some (Microbuild) should only be applied to non-PR cases for internal builds.
+
+jobs:
+- ${{ each job in parameters.jobs }}:
+ - template: ../job/job.yml
+ parameters:
+ # pass along parameters
+ ${{ each parameter in parameters }}:
+ ${{ if ne(parameter.key, 'jobs') }}:
+ ${{ parameter.key }}: ${{ parameter.value }}
+
+ # pass along job properties
+ ${{ each property in job }}:
+ ${{ if ne(property.key, 'job') }}:
+ ${{ property.key }}: ${{ property.value }}
+
+ name: ${{ job.job }}
+
+- ${{ if eq(parameters.enableSourceBuild, true) }}:
+ - template: /eng/common/templates-official/jobs/source-build.yml
+ parameters:
+ allCompletedJobId: Source_Build_Complete
+ ${{ each parameter in parameters.sourceBuildParameters }}:
+ ${{ parameter.key }}: ${{ parameter.value }}
+
+- ${{ if eq(parameters.enableSourceIndex, 'true') }}:
+ - template: ../job/source-index-stage1.yml
+ parameters:
+ runAsPublic: ${{ parameters.runAsPublic }}
+ ${{ each parameter in parameters.sourceIndexParams }}:
+ ${{ parameter.key }}: ${{ parameter.value }}
+
+- ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
+
+ - ${{ if or(eq(parameters.enablePublishBuildAssets, true), eq(parameters.artifacts.publish.manifests, 'true'), ne(parameters.artifacts.publish.manifests, '')) }}:
+ - template: ../job/publish-build-assets.yml
+ parameters:
+ continueOnError: ${{ parameters.continueOnError }}
+ dependsOn:
+ - ${{ if ne(parameters.publishBuildAssetsDependsOn, '') }}:
+ - ${{ each job in parameters.publishBuildAssetsDependsOn }}:
+ - ${{ job.job }}
+ - ${{ if eq(parameters.publishBuildAssetsDependsOn, '') }}:
+ - ${{ each job in parameters.jobs }}:
+ - ${{ job.job }}
+ - ${{ if eq(parameters.enableSourceBuild, true) }}:
+ - Source_Build_Complete
+ pool:
+ # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com)
+ ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}:
+ name: AzurePipelines-EO
+ image: 1ESPT-Windows2022
+ demands: Cmd
+ os: windows
+ # If it's not devdiv, it's dnceng
+ ${{ else }}:
+ name: NetCore1ESPool-Svc-Internal
+ image: 1es-windows-2022-pt
+ os: windows
+
+ runAsPublic: ${{ parameters.runAsPublic }}
+ publishUsingPipelines: ${{ parameters.enablePublishUsingPipelines }}
+ enablePublishBuildArtifacts: ${{ parameters.enablePublishBuildArtifacts }}
diff --git a/eng/common/templates-official/jobs/source-build.yml b/eng/common/templates-official/jobs/source-build.yml
new file mode 100644
index 00000000000..2159009dc8e
--- /dev/null
+++ b/eng/common/templates-official/jobs/source-build.yml
@@ -0,0 +1,46 @@
+parameters:
+ # This template adds arcade-powered source-build to CI. A job is created for each platform, as
+ # well as an optional server job that completes when all platform jobs complete.
+
+ # The name of the "join" job for all source-build platforms. If set to empty string, the job is
+ # not included. Existing repo pipelines can use this job depend on all source-build jobs
+ # completing without maintaining a separate list of every single job ID: just depend on this one
+ # server job. By default, not included. Recommended name if used: 'Source_Build_Complete'.
+ allCompletedJobId: ''
+
+ # See /eng/common/templates-official/job/source-build.yml
+ jobNamePrefix: 'Source_Build'
+
+ # This is the default platform provided by Arcade, intended for use by a managed-only repo.
+ defaultManagedPlatform:
+ name: 'Managed'
+ container: 'mcr.microsoft.com/dotnet-buildtools/prereqs:centos-7-3e800f1-20190501005343'
+
+ # Defines the platforms on which to run build jobs. One job is created for each platform, and the
+ # object in this array is sent to the job template as 'platform'. If no platforms are specified,
+ # one job runs on 'defaultManagedPlatform'.
+ platforms: []
+
+jobs:
+
+- ${{ if ne(parameters.allCompletedJobId, '') }}:
+ - job: ${{ parameters.allCompletedJobId }}
+ displayName: Source-Build Complete
+ pool: server
+ dependsOn:
+ - ${{ each platform in parameters.platforms }}:
+ - ${{ parameters.jobNamePrefix }}_${{ platform.name }}
+ - ${{ if eq(length(parameters.platforms), 0) }}:
+ - ${{ parameters.jobNamePrefix }}_${{ parameters.defaultManagedPlatform.name }}
+
+- ${{ each platform in parameters.platforms }}:
+ - template: /eng/common/templates-official/job/source-build.yml
+ parameters:
+ jobNamePrefix: ${{ parameters.jobNamePrefix }}
+ platform: ${{ platform }}
+
+- ${{ if eq(length(parameters.platforms), 0) }}:
+ - template: /eng/common/templates-official/job/source-build.yml
+ parameters:
+ jobNamePrefix: ${{ parameters.jobNamePrefix }}
+ platform: ${{ parameters.defaultManagedPlatform }}
diff --git a/eng/common/templates-official/post-build/common-variables.yml b/eng/common/templates-official/post-build/common-variables.yml
new file mode 100644
index 00000000000..fae340f4d20
--- /dev/null
+++ b/eng/common/templates-official/post-build/common-variables.yml
@@ -0,0 +1,26 @@
+variables:
+ - group: AzureDevOps-Artifact-Feeds-Pats
+ - group: DotNet-Blob-Feed
+ - group: DotNet-DotNetCli-Storage
+ - group: DotNet-MSRC-Storage
+ - group: Publish-Build-Assets
+
+ # Whether the build is internal or not
+ - name: IsInternalBuild
+ value: ${{ and(ne(variables['System.TeamProject'], 'public'), contains(variables['Build.SourceBranch'], 'internal')) }}
+
+ # Default Maestro++ API Endpoint and API Version
+ - name: MaestroApiEndPoint
+ value: "https://maestro.dot.net"
+ - name: MaestroApiAccessToken
+ value: $(MaestroAccessToken)
+ - name: MaestroApiVersion
+ value: "2020-02-20"
+
+ - name: SourceLinkCLIVersion
+ value: 3.0.0
+ - name: SymbolToolVersion
+ value: 1.0.1
+
+ - name: runCodesignValidationInjection
+ value: false
diff --git a/eng/common/templates-official/post-build/post-build.yml b/eng/common/templates-official/post-build/post-build.yml
new file mode 100644
index 00000000000..80bfa4946c6
--- /dev/null
+++ b/eng/common/templates-official/post-build/post-build.yml
@@ -0,0 +1,277 @@
+parameters:
+ # Which publishing infra should be used. THIS SHOULD MATCH THE VERSION ON THE BUILD MANIFEST.
+ # Publishing V1 is no longer supported
+ # Publishing V2 is no longer supported
+ # Publishing V3 is the default
+ - name: publishingInfraVersion
+ displayName: Which version of publishing should be used to promote the build definition?
+ type: number
+ default: 3
+ values:
+ - 3
+
+ - name: BARBuildId
+ displayName: BAR Build Id
+ type: number
+ default: 0
+
+ - name: PromoteToChannelIds
+ displayName: Channel to promote BARBuildId to
+ type: string
+ default: ''
+
+ - name: enableSourceLinkValidation
+ displayName: Enable SourceLink validation
+ type: boolean
+ default: false
+
+ - name: enableSigningValidation
+ displayName: Enable signing validation
+ type: boolean
+ default: true
+
+ - name: enableSymbolValidation
+ displayName: Enable symbol validation
+ type: boolean
+ default: false
+
+ - name: enableNugetValidation
+ displayName: Enable NuGet validation
+ type: boolean
+ default: true
+
+ - name: publishInstallersAndChecksums
+ displayName: Publish installers and checksums
+ type: boolean
+ default: true
+
+ - name: SDLValidationParameters
+ type: object
+ default:
+ enable: false
+ continueOnError: false
+ params: ''
+ artifactNames: ''
+ downloadArtifacts: true
+
+ # These parameters let the user customize the call to sdk-task.ps1 for publishing
+ # symbols & general artifacts as well as for signing validation
+ - name: symbolPublishingAdditionalParameters
+ displayName: Symbol publishing additional parameters
+ type: string
+ default: ''
+
+ - name: artifactsPublishingAdditionalParameters
+ displayName: Artifact publishing additional parameters
+ type: string
+ default: ''
+
+ - name: signingValidationAdditionalParameters
+ displayName: Signing validation additional parameters
+ type: string
+ default: ''
+
+ # Which stages should finish execution before post-build stages start
+ - name: validateDependsOn
+ type: object
+ default:
+ - build
+
+ - name: publishDependsOn
+ type: object
+ default:
+ - Validate
+
+stages:
+- ${{ if or(eq( parameters.enableNugetValidation, 'true'), eq(parameters.enableSigningValidation, 'true'), eq(parameters.enableSourceLinkValidation, 'true'), eq(parameters.SDLValidationParameters.enable, 'true')) }}:
+ - stage: Validate
+ dependsOn: ${{ parameters.validateDependsOn }}
+ displayName: Validate Build Assets
+ variables:
+ - template: common-variables.yml
+ jobs:
+ - job:
+ displayName: NuGet Validation
+ condition: eq( ${{ parameters.enableNugetValidation }}, 'true')
+ pool:
+ # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com)
+ ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}:
+ name: AzurePipelines-EO
+ image: 1ESPT-Windows2022
+ demands: Cmd
+ os: windows
+ # If it's not devdiv, it's dnceng
+ ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}:
+ name: NetCore1ESPool-Svc-Internal
+ image: 1es-windows-2022-pt
+ os: windows
+
+ steps:
+ - template: setup-maestro-vars.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+
+ - task: DownloadBuildArtifacts@0
+ displayName: Download Package Artifacts
+ inputs:
+ buildType: specific
+ buildVersionToDownload: specific
+ project: $(AzDOProjectName)
+ pipeline: $(AzDOPipelineId)
+ buildId: $(AzDOBuildId)
+ artifactName: PackageArtifacts
+ checkDownloadedFiles: true
+
+ - task: PowerShell@2
+ displayName: Validate
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/common/post-build/nuget-validation.ps1
+ arguments: -PackagesPath $(Build.ArtifactStagingDirectory)/PackageArtifacts/
+ -ToolDestinationPath $(Agent.BuildDirectory)/Extract/
+
+ - job:
+ displayName: Signing Validation
+ condition: and( eq( ${{ parameters.enableSigningValidation }}, 'true'), ne( variables['PostBuildSign'], 'true'))
+ pool:
+ # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com)
+ ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}:
+ name: AzurePipelines-EO
+ demands: Cmd
+ os: windows
+ # If it's not devdiv, it's dnceng
+ ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}:
+ name: NetCore1ESPool-Svc-Internal
+ image: 1es-windows-2022-pt
+ os: windows
+ steps:
+ - template: setup-maestro-vars.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+
+ - task: DownloadBuildArtifacts@0
+ displayName: Download Package Artifacts
+ inputs:
+ buildType: specific
+ buildVersionToDownload: specific
+ project: $(AzDOProjectName)
+ pipeline: $(AzDOPipelineId)
+ buildId: $(AzDOBuildId)
+ artifactName: PackageArtifacts
+ checkDownloadedFiles: true
+ itemPattern: |
+ **
+ !**/Microsoft.SourceBuild.Intermediate.*.nupkg
+
+ # This is necessary whenever we want to publish/restore to an AzDO private feed
+ # Since sdk-task.ps1 tries to restore packages we need to do this authentication here
+ # otherwise it'll complain about accessing a private feed.
+ - task: NuGetAuthenticate@1
+ displayName: 'Authenticate to AzDO Feeds'
+
+ - task: PowerShell@2
+ displayName: Enable cross-org publishing
+ inputs:
+ filePath: eng\common\enable-cross-org-publishing.ps1
+ arguments: -token $(dn-bot-dnceng-artifact-feeds-rw)
+
+ # Signing validation will optionally work with the buildmanifest file which is downloaded from
+ # Azure DevOps above.
+ - task: PowerShell@2
+ displayName: Validate
+ inputs:
+ filePath: eng\common\sdk-task.ps1
+ arguments: -task SigningValidation -restore -msbuildEngine vs
+ /p:PackageBasePath='$(Build.ArtifactStagingDirectory)/PackageArtifacts'
+ /p:SignCheckExclusionsFile='$(Build.SourcesDirectory)/eng/SignCheckExclusionsFile.txt'
+ ${{ parameters.signingValidationAdditionalParameters }}
+
+ - template: ../steps/publish-logs.yml
+ parameters:
+ StageLabel: 'Validation'
+ JobLabel: 'Signing'
+
+ - job:
+ displayName: SourceLink Validation
+ condition: eq( ${{ parameters.enableSourceLinkValidation }}, 'true')
+ pool:
+ # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com)
+ ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}:
+ name: AzurePipelines-EO
+ image: 1ESPT-Windows2022
+ demands: Cmd
+ os: windows
+ # If it's not devdiv, it's dnceng
+ ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}:
+ name: NetCore1ESPool-Svc-Internal
+ image: 1es-windows-2022-pt
+ os: windows
+ steps:
+ - template: setup-maestro-vars.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+
+ - task: DownloadBuildArtifacts@0
+ displayName: Download Blob Artifacts
+ inputs:
+ buildType: specific
+ buildVersionToDownload: specific
+ project: $(AzDOProjectName)
+ pipeline: $(AzDOPipelineId)
+ buildId: $(AzDOBuildId)
+ artifactName: BlobArtifacts
+ checkDownloadedFiles: true
+
+ - task: PowerShell@2
+ displayName: Validate
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/common/post-build/sourcelink-validation.ps1
+ arguments: -InputPath $(Build.ArtifactStagingDirectory)/BlobArtifacts/
+ -ExtractPath $(Agent.BuildDirectory)/Extract/
+ -GHRepoName $(Build.Repository.Name)
+ -GHCommit $(Build.SourceVersion)
+ -SourcelinkCliVersion $(SourceLinkCLIVersion)
+ continueOnError: true
+
+- stage: publish_using_darc
+ ${{ if or(eq(parameters.enableNugetValidation, 'true'), eq(parameters.enableSigningValidation, 'true'), eq(parameters.enableSourceLinkValidation, 'true'), eq(parameters.SDLValidationParameters.enable, 'true')) }}:
+ dependsOn: ${{ parameters.publishDependsOn }}
+ ${{ if and(ne(parameters.enableNugetValidation, 'true'), ne(parameters.enableSigningValidation, 'true'), ne(parameters.enableSourceLinkValidation, 'true'), ne(parameters.SDLValidationParameters.enable, 'true')) }}:
+ dependsOn: ${{ parameters.validateDependsOn }}
+ displayName: Publish using Darc
+ variables:
+ - template: common-variables.yml
+ jobs:
+ - job:
+ displayName: Publish Using Darc
+ timeoutInMinutes: 120
+ pool:
+ # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com)
+ ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}:
+ name: AzurePipelines-EO
+ demands: Cmd
+ os: windows
+ # If it's not devdiv, it's dnceng
+ ${{ else }}:
+ name: NetCore1ESPool-Svc-Internal
+ image: 1es-windows-2022-pt
+ os: windows
+ steps:
+ - template: setup-maestro-vars.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+
+ - task: PowerShell@2
+ displayName: Publish Using Darc
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1
+ arguments: -BuildId $(BARBuildId)
+ -PublishingInfraVersion ${{ parameters.publishingInfraVersion }}
+ -AzdoToken '$(publishing-dnceng-devdiv-code-r-build-re)'
+ -MaestroToken '$(MaestroApiAccessToken)'
+ -WaitPublishingFinish true
+ -ArtifactsPublishingAdditionalParameters '${{ parameters.artifactsPublishingAdditionalParameters }}'
+ -SymbolPublishingAdditionalParameters '${{ parameters.symbolPublishingAdditionalParameters }}'
diff --git a/eng/common/templates-official/post-build/setup-maestro-vars.yml b/eng/common/templates-official/post-build/setup-maestro-vars.yml
new file mode 100644
index 00000000000..0c87f149a4a
--- /dev/null
+++ b/eng/common/templates-official/post-build/setup-maestro-vars.yml
@@ -0,0 +1,70 @@
+parameters:
+ BARBuildId: ''
+ PromoteToChannelIds: ''
+
+steps:
+ - ${{ if eq(coalesce(parameters.PromoteToChannelIds, 0), 0) }}:
+ - task: DownloadBuildArtifacts@0
+ displayName: Download Release Configs
+ inputs:
+ buildType: current
+ artifactName: ReleaseConfigs
+ checkDownloadedFiles: true
+
+ - task: PowerShell@2
+ name: setReleaseVars
+ displayName: Set Release Configs Vars
+ inputs:
+ targetType: inline
+ pwsh: true
+ script: |
+ try {
+ if (!$Env:PromoteToMaestroChannels -or $Env:PromoteToMaestroChannels.Trim() -eq '') {
+ $Content = Get-Content $(Build.StagingDirectory)/ReleaseConfigs/ReleaseConfigs.txt
+
+ $BarId = $Content | Select -Index 0
+ $Channels = $Content | Select -Index 1
+ $IsStableBuild = $Content | Select -Index 2
+
+ $AzureDevOpsProject = $Env:System_TeamProject
+ $AzureDevOpsBuildDefinitionId = $Env:System_DefinitionId
+ $AzureDevOpsBuildId = $Env:Build_BuildId
+ }
+ else {
+ $buildApiEndpoint = "${Env:MaestroApiEndPoint}/api/builds/${Env:BARBuildId}?api-version=${Env:MaestroApiVersion}"
+
+ $apiHeaders = New-Object 'System.Collections.Generic.Dictionary[[String],[String]]'
+ $apiHeaders.Add('Accept', 'application/json')
+ $apiHeaders.Add('Authorization',"Bearer ${Env:MAESTRO_API_TOKEN}")
+
+ $buildInfo = try { Invoke-WebRequest -Method Get -Uri $buildApiEndpoint -Headers $apiHeaders | ConvertFrom-Json } catch { Write-Host "Error: $_" }
+
+ $BarId = $Env:BARBuildId
+ $Channels = $Env:PromoteToMaestroChannels -split ","
+ $Channels = $Channels -join "]["
+ $Channels = "[$Channels]"
+
+ $IsStableBuild = $buildInfo.stable
+ $AzureDevOpsProject = $buildInfo.azureDevOpsProject
+ $AzureDevOpsBuildDefinitionId = $buildInfo.azureDevOpsBuildDefinitionId
+ $AzureDevOpsBuildId = $buildInfo.azureDevOpsBuildId
+ }
+
+ Write-Host "##vso[task.setvariable variable=BARBuildId]$BarId"
+ Write-Host "##vso[task.setvariable variable=TargetChannels]$Channels"
+ Write-Host "##vso[task.setvariable variable=IsStableBuild]$IsStableBuild"
+
+ Write-Host "##vso[task.setvariable variable=AzDOProjectName]$AzureDevOpsProject"
+ Write-Host "##vso[task.setvariable variable=AzDOPipelineId]$AzureDevOpsBuildDefinitionId"
+ Write-Host "##vso[task.setvariable variable=AzDOBuildId]$AzureDevOpsBuildId"
+ }
+ catch {
+ Write-Host $_
+ Write-Host $_.Exception
+ Write-Host $_.ScriptStackTrace
+ exit 1
+ }
+ env:
+ MAESTRO_API_TOKEN: $(MaestroApiAccessToken)
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToMaestroChannels: ${{ parameters.PromoteToChannelIds }}
diff --git a/eng/common/templates-official/post-build/trigger-subscription.yml b/eng/common/templates-official/post-build/trigger-subscription.yml
new file mode 100644
index 00000000000..da669030daf
--- /dev/null
+++ b/eng/common/templates-official/post-build/trigger-subscription.yml
@@ -0,0 +1,13 @@
+parameters:
+ ChannelId: 0
+
+steps:
+- task: PowerShell@2
+ displayName: Triggering subscriptions
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/common/post-build/trigger-subscriptions.ps1
+ arguments: -SourceRepo $(Build.Repository.Uri)
+ -ChannelId ${{ parameters.ChannelId }}
+ -MaestroApiAccessToken $(MaestroAccessToken)
+ -MaestroApiEndPoint $(MaestroApiEndPoint)
+ -MaestroApiVersion $(MaestroApiVersion)
diff --git a/eng/common/templates-official/steps/add-build-to-channel.yml b/eng/common/templates-official/steps/add-build-to-channel.yml
new file mode 100644
index 00000000000..f67a210d62f
--- /dev/null
+++ b/eng/common/templates-official/steps/add-build-to-channel.yml
@@ -0,0 +1,13 @@
+parameters:
+ ChannelId: 0
+
+steps:
+- task: PowerShell@2
+ displayName: Add Build to Channel
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/common/post-build/add-build-to-channel.ps1
+ arguments: -BuildId $(BARBuildId)
+ -ChannelId ${{ parameters.ChannelId }}
+ -MaestroApiAccessToken $(MaestroApiAccessToken)
+ -MaestroApiEndPoint $(MaestroApiEndPoint)
+ -MaestroApiVersion $(MaestroApiVersion)
diff --git a/eng/common/templates-official/steps/component-governance.yml b/eng/common/templates-official/steps/component-governance.yml
new file mode 100644
index 00000000000..babc2757d8d
--- /dev/null
+++ b/eng/common/templates-official/steps/component-governance.yml
@@ -0,0 +1,10 @@
+parameters:
+ disableComponentGovernance: false
+
+steps:
+- ${{ if eq(parameters.disableComponentGovernance, 'true') }}:
+ - script: "echo ##vso[task.setvariable variable=skipComponentGovernanceDetection]true"
+ displayName: Set skipComponentGovernanceDetection variable
+- ${{ if ne(parameters.disableComponentGovernance, 'true') }}:
+ - task: ComponentGovernanceComponentDetection@0
+ continueOnError: true
\ No newline at end of file
diff --git a/eng/common/templates-official/steps/execute-codeql.yml b/eng/common/templates-official/steps/execute-codeql.yml
new file mode 100644
index 00000000000..9b4a5ffa30a
--- /dev/null
+++ b/eng/common/templates-official/steps/execute-codeql.yml
@@ -0,0 +1,32 @@
+parameters:
+ # Language that should be analyzed. Defaults to csharp
+ language: csharp
+ # Build Commands
+ buildCommands: ''
+ overrideParameters: '' # Optional: to override values for parameters.
+ additionalParameters: '' # Optional: parameters that need user specific values eg: '-SourceToolsList @("abc","def") -ArtifactToolsList @("ghi","jkl")'
+ # Optional: if specified, restore and use this version of Guardian instead of the default.
+ overrideGuardianVersion: ''
+ # Optional: if true, publish the '.gdn' folder as a pipeline artifact. This can help with in-depth
+ # diagnosis of problems with specific tool configurations.
+ publishGuardianDirectoryToPipeline: false
+ # The script to run to execute all SDL tools. Use this if you want to use a script to define SDL
+ # parameters rather than relying on YAML. It may be better to use a local script, because you can
+ # reproduce results locally without piecing together a command based on the YAML.
+ executeAllSdlToolsScript: 'eng/common/sdl/execute-all-sdl-tools.ps1'
+ # There is some sort of bug (has been reported) in Azure DevOps where if this parameter is named
+ # 'continueOnError', the parameter value is not correctly picked up.
+ # This can also be remedied by the caller (post-build.yml) if it does not use a nested parameter
+ # optional: determines whether to continue the build if the step errors;
+ sdlContinueOnError: false
+
+steps:
+- template: /eng/common/templates-official/steps/execute-sdl.yml
+ parameters:
+ overrideGuardianVersion: ${{ parameters.overrideGuardianVersion }}
+ executeAllSdlToolsScript: ${{ parameters.executeAllSdlToolsScript }}
+ overrideParameters: ${{ parameters.overrideParameters }}
+ additionalParameters: '${{ parameters.additionalParameters }}
+ -CodeQLAdditionalRunConfigParams @("BuildCommands < ${{ parameters.buildCommands }}", "Language < ${{ parameters.language }}")'
+ publishGuardianDirectoryToPipeline: ${{ parameters.publishGuardianDirectoryToPipeline }}
+ sdlContinueOnError: ${{ parameters.sdlContinueOnError }}
\ No newline at end of file
diff --git a/eng/common/templates-official/steps/generate-sbom.yml b/eng/common/templates-official/steps/generate-sbom.yml
new file mode 100644
index 00000000000..7fc4f358023
--- /dev/null
+++ b/eng/common/templates-official/steps/generate-sbom.yml
@@ -0,0 +1,44 @@
+# BuildDropPath - The root folder of the drop directory for which the manifest file will be generated.
+# PackageName - The name of the package this SBOM represents.
+# PackageVersion - The version of the package this SBOM represents.
+# ManifestDirPath - The path of the directory where the generated manifest files will be placed
+
+parameters:
+ PackageVersion: 6.0.0
+ BuildDropPath: '$(Build.SourcesDirectory)/artifacts'
+ PackageName: '.NET'
+ ManifestDirPath: $(Build.ArtifactStagingDirectory)/sbom
+ sbomContinueOnError: true
+
+steps:
+- task: PowerShell@2
+ displayName: Prep for SBOM generation in (Non-linux)
+ condition: or(eq(variables['Agent.Os'], 'Windows_NT'), eq(variables['Agent.Os'], 'Darwin'))
+ inputs:
+ filePath: ./eng/common/generate-sbom-prep.ps1
+ arguments: ${{parameters.manifestDirPath}}
+
+# Chmodding is a workaround for https://github.com/dotnet/arcade/issues/8461
+- script: |
+ chmod +x ./eng/common/generate-sbom-prep.sh
+ ./eng/common/generate-sbom-prep.sh ${{parameters.manifestDirPath}}
+ displayName: Prep for SBOM generation in (Linux)
+ condition: eq(variables['Agent.Os'], 'Linux')
+ continueOnError: ${{ parameters.sbomContinueOnError }}
+
+- task: AzureArtifacts.manifest-generator-task.manifest-generator-task.ManifestGeneratorTask@0
+ displayName: 'Generate SBOM manifest'
+ continueOnError: ${{ parameters.sbomContinueOnError }}
+ inputs:
+ PackageName: ${{ parameters.packageName }}
+ BuildDropPath: ${{ parameters.buildDropPath }}
+ PackageVersion: ${{ parameters.packageVersion }}
+ ManifestDirPath: ${{ parameters.manifestDirPath }}
+
+- task: 1ES.PublishPipelineArtifact@1
+ displayName: Publish SBOM manifest
+ continueOnError: ${{parameters.sbomContinueOnError}}
+ inputs:
+ targetPath: '${{parameters.manifestDirPath}}'
+ artifactName: $(ARTIFACT_NAME)
+
diff --git a/eng/common/templates-official/steps/publish-logs.yml b/eng/common/templates-official/steps/publish-logs.yml
new file mode 100644
index 00000000000..04012fed182
--- /dev/null
+++ b/eng/common/templates-official/steps/publish-logs.yml
@@ -0,0 +1,23 @@
+parameters:
+ StageLabel: ''
+ JobLabel: ''
+
+steps:
+- task: Powershell@2
+ displayName: Prepare Binlogs to Upload
+ inputs:
+ targetType: inline
+ script: |
+ New-Item -ItemType Directory $(Build.SourcesDirectory)/PostBuildLogs/${{parameters.StageLabel}}/${{parameters.JobLabel}}/
+ Move-Item -Path $(Build.SourcesDirectory)/artifacts/log/Debug/* $(Build.SourcesDirectory)/PostBuildLogs/${{parameters.StageLabel}}/${{parameters.JobLabel}}/
+ continueOnError: true
+ condition: always()
+
+- task: 1ES.PublishBuildArtifacts@1
+ displayName: Publish Logs
+ inputs:
+ PathtoPublish: '$(Build.SourcesDirectory)/PostBuildLogs'
+ PublishLocation: Container
+ ArtifactName: PostBuildLogs
+ continueOnError: true
+ condition: always()
diff --git a/eng/common/templates-official/steps/retain-build.yml b/eng/common/templates-official/steps/retain-build.yml
new file mode 100644
index 00000000000..83d97a26a01
--- /dev/null
+++ b/eng/common/templates-official/steps/retain-build.yml
@@ -0,0 +1,28 @@
+parameters:
+ # Optional azure devops PAT with build execute permissions for the build's organization,
+ # only needed if the build that should be retained ran on a different organization than
+ # the pipeline where this template is executing from
+ Token: ''
+ # Optional BuildId to retain, defaults to the current running build
+ BuildId: ''
+ # Azure devops Organization URI for the build in the https://dev.azure.com/ format.
+ # Defaults to the organization the current pipeline is running on
+ AzdoOrgUri: '$(System.CollectionUri)'
+ # Azure devops project for the build. Defaults to the project the current pipeline is running on
+ AzdoProject: '$(System.TeamProject)'
+
+steps:
+ - task: powershell@2
+ inputs:
+ targetType: 'filePath'
+ filePath: eng/common/retain-build.ps1
+ pwsh: true
+ arguments: >
+ -AzdoOrgUri: ${{parameters.AzdoOrgUri}}
+ -AzdoProject ${{parameters.AzdoProject}}
+ -Token ${{coalesce(parameters.Token, '$env:SYSTEM_ACCESSTOKEN') }}
+ -BuildId ${{coalesce(parameters.BuildId, '$env:BUILD_ID')}}
+ displayName: Enable permanent build retention
+ env:
+ SYSTEM_ACCESSTOKEN: $(System.AccessToken)
+ BUILD_ID: $(Build.BuildId)
\ No newline at end of file
diff --git a/eng/common/templates-official/steps/send-to-helix.yml b/eng/common/templates-official/steps/send-to-helix.yml
new file mode 100644
index 00000000000..cd02ae1607f
--- /dev/null
+++ b/eng/common/templates-official/steps/send-to-helix.yml
@@ -0,0 +1,94 @@
+# Please remember to update the documentation if you make changes to these parameters!
+parameters:
+ HelixSource: 'pr/default' # required -- sources must start with pr/, official/, prodcon/, or agent/
+ HelixType: 'tests/default/' # required -- Helix telemetry which identifies what type of data this is; should include "test" for clarity and must end in '/'
+ HelixBuild: $(Build.BuildNumber) # required -- the build number Helix will use to identify this -- automatically set to the AzDO build number
+ HelixTargetQueues: '' # required -- semicolon delimited list of Helix queues to test on; see https://helix.dot.net/ for a list of queues
+ HelixAccessToken: '' # required -- access token to make Helix API requests; should be provided by the appropriate variable group
+ HelixConfiguration: '' # optional -- additional property attached to a job
+ HelixPreCommands: '' # optional -- commands to run before Helix work item execution
+ HelixPostCommands: '' # optional -- commands to run after Helix work item execution
+ WorkItemDirectory: '' # optional -- a payload directory to zip up and send to Helix; requires WorkItemCommand; incompatible with XUnitProjects
+ WorkItemCommand: '' # optional -- a command to execute on the payload; requires WorkItemDirectory; incompatible with XUnitProjects
+ WorkItemTimeout: '' # optional -- a timeout in TimeSpan.Parse-ready value (e.g. 00:02:00) for the work item command; requires WorkItemDirectory; incompatible with XUnitProjects
+ CorrelationPayloadDirectory: '' # optional -- a directory to zip up and send to Helix as a correlation payload
+ XUnitProjects: '' # optional -- semicolon delimited list of XUnitProjects to parse and send to Helix; requires XUnitRuntimeTargetFramework, XUnitPublishTargetFramework, XUnitRunnerVersion, and IncludeDotNetCli=true
+ XUnitWorkItemTimeout: '' # optional -- the workitem timeout in seconds for all workitems created from the xUnit projects specified by XUnitProjects
+ XUnitPublishTargetFramework: '' # optional -- framework to use to publish your xUnit projects
+ XUnitRuntimeTargetFramework: '' # optional -- framework to use for the xUnit console runner
+ XUnitRunnerVersion: '' # optional -- version of the xUnit nuget package you wish to use on Helix; required for XUnitProjects
+ IncludeDotNetCli: false # optional -- true will download a version of the .NET CLI onto the Helix machine as a correlation payload; requires DotNetCliPackageType and DotNetCliVersion
+ DotNetCliPackageType: '' # optional -- either 'sdk', 'runtime' or 'aspnetcore-runtime'; determines whether the sdk or runtime will be sent to Helix; see https://raw.githubusercontent.com/dotnet/core/main/release-notes/releases-index.json
+ DotNetCliVersion: '' # optional -- version of the CLI to send to Helix; based on this: https://raw.githubusercontent.com/dotnet/core/main/release-notes/releases-index.json
+ EnableXUnitReporter: false # optional -- true enables XUnit result reporting to Mission Control
+ WaitForWorkItemCompletion: true # optional -- true will make the task wait until work items have been completed and fail the build if work items fail. False is "fire and forget."
+ IsExternal: false # [DEPRECATED] -- doesn't do anything, jobs are external if HelixAccessToken is empty and Creator is set
+ HelixBaseUri: 'https://helix.dot.net/' # optional -- sets the Helix API base URI (allows targeting int)
+ Creator: '' # optional -- if the build is external, use this to specify who is sending the job
+ DisplayNamePrefix: 'Run Tests' # optional -- rename the beginning of the displayName of the steps in AzDO
+ condition: succeeded() # optional -- condition for step to execute; defaults to succeeded()
+ continueOnError: false # optional -- determines whether to continue the build if the step errors; defaults to false
+
+steps:
+ - powershell: 'powershell "$env:BUILD_SOURCESDIRECTORY\eng\common\msbuild.ps1 $env:BUILD_SOURCESDIRECTORY\eng\common\helixpublish.proj /restore /t:Test /bl:$env:BUILD_SOURCESDIRECTORY\artifacts\log\$env:BuildConfig\SendToHelix.binlog"'
+ displayName: ${{ parameters.DisplayNamePrefix }} (Windows)
+ env:
+ BuildConfig: $(_BuildConfig)
+ HelixSource: ${{ parameters.HelixSource }}
+ HelixType: ${{ parameters.HelixType }}
+ HelixBuild: ${{ parameters.HelixBuild }}
+ HelixConfiguration: ${{ parameters.HelixConfiguration }}
+ HelixTargetQueues: ${{ parameters.HelixTargetQueues }}
+ HelixAccessToken: ${{ parameters.HelixAccessToken }}
+ HelixPreCommands: ${{ parameters.HelixPreCommands }}
+ HelixPostCommands: ${{ parameters.HelixPostCommands }}
+ WorkItemDirectory: ${{ parameters.WorkItemDirectory }}
+ WorkItemCommand: ${{ parameters.WorkItemCommand }}
+ WorkItemTimeout: ${{ parameters.WorkItemTimeout }}
+ CorrelationPayloadDirectory: ${{ parameters.CorrelationPayloadDirectory }}
+ XUnitProjects: ${{ parameters.XUnitProjects }}
+ XUnitWorkItemTimeout: ${{ parameters.XUnitWorkItemTimeout }}
+ XUnitPublishTargetFramework: ${{ parameters.XUnitPublishTargetFramework }}
+ XUnitRuntimeTargetFramework: ${{ parameters.XUnitRuntimeTargetFramework }}
+ XUnitRunnerVersion: ${{ parameters.XUnitRunnerVersion }}
+ IncludeDotNetCli: ${{ parameters.IncludeDotNetCli }}
+ DotNetCliPackageType: ${{ parameters.DotNetCliPackageType }}
+ DotNetCliVersion: ${{ parameters.DotNetCliVersion }}
+ EnableXUnitReporter: ${{ parameters.EnableXUnitReporter }}
+ WaitForWorkItemCompletion: ${{ parameters.WaitForWorkItemCompletion }}
+ HelixBaseUri: ${{ parameters.HelixBaseUri }}
+ Creator: ${{ parameters.Creator }}
+ SYSTEM_ACCESSTOKEN: $(System.AccessToken)
+ condition: and(${{ parameters.condition }}, eq(variables['Agent.Os'], 'Windows_NT'))
+ continueOnError: ${{ parameters.continueOnError }}
+ - script: $BUILD_SOURCESDIRECTORY/eng/common/msbuild.sh $BUILD_SOURCESDIRECTORY/eng/common/helixpublish.proj /restore /t:Test /bl:$BUILD_SOURCESDIRECTORY/artifacts/log/$BuildConfig/SendToHelix.binlog
+ displayName: ${{ parameters.DisplayNamePrefix }} (Unix)
+ env:
+ BuildConfig: $(_BuildConfig)
+ HelixSource: ${{ parameters.HelixSource }}
+ HelixType: ${{ parameters.HelixType }}
+ HelixBuild: ${{ parameters.HelixBuild }}
+ HelixConfiguration: ${{ parameters.HelixConfiguration }}
+ HelixTargetQueues: ${{ parameters.HelixTargetQueues }}
+ HelixAccessToken: ${{ parameters.HelixAccessToken }}
+ HelixPreCommands: ${{ parameters.HelixPreCommands }}
+ HelixPostCommands: ${{ parameters.HelixPostCommands }}
+ WorkItemDirectory: ${{ parameters.WorkItemDirectory }}
+ WorkItemCommand: ${{ parameters.WorkItemCommand }}
+ WorkItemTimeout: ${{ parameters.WorkItemTimeout }}
+ CorrelationPayloadDirectory: ${{ parameters.CorrelationPayloadDirectory }}
+ XUnitProjects: ${{ parameters.XUnitProjects }}
+ XUnitWorkItemTimeout: ${{ parameters.XUnitWorkItemTimeout }}
+ XUnitPublishTargetFramework: ${{ parameters.XUnitPublishTargetFramework }}
+ XUnitRuntimeTargetFramework: ${{ parameters.XUnitRuntimeTargetFramework }}
+ XUnitRunnerVersion: ${{ parameters.XUnitRunnerVersion }}
+ IncludeDotNetCli: ${{ parameters.IncludeDotNetCli }}
+ DotNetCliPackageType: ${{ parameters.DotNetCliPackageType }}
+ DotNetCliVersion: ${{ parameters.DotNetCliVersion }}
+ EnableXUnitReporter: ${{ parameters.EnableXUnitReporter }}
+ WaitForWorkItemCompletion: ${{ parameters.WaitForWorkItemCompletion }}
+ HelixBaseUri: ${{ parameters.HelixBaseUri }}
+ Creator: ${{ parameters.Creator }}
+ SYSTEM_ACCESSTOKEN: $(System.AccessToken)
+ condition: and(${{ parameters.condition }}, ne(variables['Agent.Os'], 'Windows_NT'))
+ continueOnError: ${{ parameters.continueOnError }}
diff --git a/eng/common/templates-official/steps/source-build.yml b/eng/common/templates-official/steps/source-build.yml
new file mode 100644
index 00000000000..9eb7e51456a
--- /dev/null
+++ b/eng/common/templates-official/steps/source-build.yml
@@ -0,0 +1,108 @@
+parameters:
+ # This template adds arcade-powered source-build to CI.
+
+ # This is a 'steps' template, and is intended for advanced scenarios where the existing build
+ # infra has a careful build methodology that must be followed. For example, a repo
+ # (dotnet/runtime) might choose to clone the GitHub repo only once and store it as a pipeline
+ # artifact for all subsequent jobs to use, to reduce dependence on a strong network connection to
+ # GitHub. Using this steps template leaves room for that infra to be included.
+
+ # Defines the platform on which to run the steps. See 'eng/common/templates-official/job/source-build.yml'
+ # for details. The entire object is described in the 'job' template for simplicity, even though
+ # the usage of the properties on this object is split between the 'job' and 'steps' templates.
+ platform: {}
+
+steps:
+# Build. Keep it self-contained for simple reusability. (No source-build-specific job variables.)
+- script: |
+ set -x
+ df -h
+
+ # If building on the internal project, the artifact feeds variable may be available (usually only if needed)
+ # In that case, call the feed setup script to add internal feeds corresponding to public ones.
+ # In addition, add an msbuild argument to copy the WIP from the repo to the target build location.
+ # This is because SetupNuGetSources.sh will alter the current NuGet.config file, and we need to preserve those
+ # changes.
+ $internalRestoreArgs=
+ if [ '$(dn-bot-dnceng-artifact-feeds-rw)' != '$''(dn-bot-dnceng-artifact-feeds-rw)' ]; then
+ # Temporarily work around https://github.com/dotnet/arcade/issues/7709
+ chmod +x $(Build.SourcesDirectory)/eng/common/SetupNugetSources.sh
+ $(Build.SourcesDirectory)/eng/common/SetupNugetSources.sh $(Build.SourcesDirectory)/NuGet.config $(dn-bot-dnceng-artifact-feeds-rw)
+ internalRestoreArgs='/p:CopyWipIntoInnerSourceBuildRepo=true'
+
+ # The 'Copy WIP' feature of source build uses git stash to apply changes from the original repo.
+ # This only works if there is a username/email configured, which won't be the case in most CI runs.
+ git config --get user.email
+ if [ $? -ne 0 ]; then
+ git config user.email dn-bot@microsoft.com
+ git config user.name dn-bot
+ fi
+ fi
+
+ # If building on the internal project, the internal storage variable may be available (usually only if needed)
+ # In that case, add variables to allow the download of internal runtimes if the specified versions are not found
+ # in the default public locations.
+ internalRuntimeDownloadArgs=
+ if [ '$(dotnetbuilds-internal-container-read-token-base64)' != '$''(dotnetbuilds-internal-container-read-token-base64)' ]; then
+ internalRuntimeDownloadArgs='/p:DotNetRuntimeSourceFeed=https://dotnetbuilds.blob.core.windows.net/internal /p:DotNetRuntimeSourceFeedKey=$(dotnetbuilds-internal-container-read-token-base64) --runtimesourcefeed https://dotnetbuilds.blob.core.windows.net/internal --runtimesourcefeedkey $(dotnetbuilds-internal-container-read-token-base64)'
+ fi
+
+ buildConfig=Release
+ # Check if AzDO substitutes in a build config from a variable, and use it if so.
+ if [ '$(_BuildConfig)' != '$''(_BuildConfig)' ]; then
+ buildConfig='$(_BuildConfig)'
+ fi
+
+ officialBuildArgs=
+ if [ '${{ and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}' = 'True' ]; then
+ officialBuildArgs='/p:DotNetPublishUsingPipelines=true /p:OfficialBuildId=$(BUILD.BUILDNUMBER)'
+ fi
+
+ targetRidArgs=
+ if [ '${{ parameters.platform.targetRID }}' != '' ]; then
+ targetRidArgs='/p:TargetRid=${{ parameters.platform.targetRID }}'
+ fi
+
+ runtimeOsArgs=
+ if [ '${{ parameters.platform.runtimeOS }}' != '' ]; then
+ runtimeOsArgs='/p:RuntimeOS=${{ parameters.platform.runtimeOS }}'
+ fi
+
+ publishArgs=
+ if [ '${{ parameters.platform.skipPublishValidation }}' != 'true' ]; then
+ publishArgs='--publish'
+ fi
+
+ ${{ coalesce(parameters.platform.buildScript, './build.sh') }} --ci \
+ --configuration $buildConfig \
+ --restore --build --pack $publishArgs -bl \
+ $officialBuildArgs \
+ $internalRuntimeDownloadArgs \
+ $internalRestoreArgs \
+ $targetRidArgs \
+ $runtimeOsArgs \
+ /p:SourceBuildNonPortable=${{ parameters.platform.nonPortable }} \
+ /p:ArcadeBuildFromSource=true
+ displayName: Build
+
+# Upload build logs for diagnosis.
+- task: CopyFiles@2
+ displayName: Prepare BuildLogs staging directory
+ inputs:
+ SourceFolder: '$(Build.SourcesDirectory)'
+ Contents: |
+ **/*.log
+ **/*.binlog
+ artifacts/source-build/self/prebuilt-report/**
+ TargetFolder: '$(Build.StagingDirectory)/BuildLogs'
+ CleanTargetFolder: true
+ continueOnError: true
+ condition: succeededOrFailed()
+
+- task: 1ES.PublishPipelineArtifact@1
+ displayName: Publish BuildLogs
+ inputs:
+ targetPath: '$(Build.StagingDirectory)/BuildLogs'
+ artifactName: BuildLogs_SourceBuild_${{ parameters.platform.name }}_Attempt$(System.JobAttempt)
+ continueOnError: true
+ condition: succeededOrFailed()
diff --git a/eng/common/templates-official/variables/sdl-variables.yml b/eng/common/templates-official/variables/sdl-variables.yml
new file mode 100644
index 00000000000..1a860bd0406
--- /dev/null
+++ b/eng/common/templates-official/variables/sdl-variables.yml
@@ -0,0 +1,7 @@
+variables:
+# The Guardian version specified in 'eng/common/sdl/packages.config'. This value must be kept in
+# sync with the packages.config file.
+- name: DefaultGuardianVersion
+ value: 0.110.1
+- name: GuardianPackagesConfigFile
+ value: $(Build.SourcesDirectory)\eng\common\sdl\packages.config
\ No newline at end of file
diff --git a/global.json b/global.json
index dd25ff87ed9..acb4f8439ae 100644
--- a/global.json
+++ b/global.json
@@ -1,6 +1,6 @@
{
"tools": {
- "dotnet": "6.0.126",
+ "dotnet": "6.0.127",
"runtimes": {
"dotnet": [
"3.1.32",
@@ -13,12 +13,12 @@
}
},
"sdk": {
- "version": "6.0.126",
+ "version": "6.0.127",
"allowPrerelease": true,
"rollForward": "latestMajor"
},
"msbuild-sdks": {
- "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.24113.1",
- "Microsoft.DotNet.Helix.Sdk": "6.0.0-beta.24113.1"
+ "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.24162.4",
+ "Microsoft.DotNet.Helix.Sdk": "6.0.0-beta.24162.4"
}
}
From 451bcf11e7574201cea3c912e7129e022df4be83 Mon Sep 17 00:00:00 2001
From: DotNet Bot
Date: Wed, 13 Mar 2024 19:51:15 +0000
Subject: [PATCH 18/22] [internal/release/8.0] Update dependencies from
dnceng/internal/dotnet-runtime
---
NuGet.config | 6 ++++++
eng/Version.Details.xml | 16 ++++++++--------
eng/Versions.props | 8 ++++----
3 files changed, 18 insertions(+), 12 deletions(-)
diff --git a/NuGet.config b/NuGet.config
index 8d9f70a526f..a1b47285ada 100644
--- a/NuGet.config
+++ b/NuGet.config
@@ -5,6 +5,9 @@
+
+
+
@@ -19,6 +22,9 @@
+
+
+
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index 3a8e051bb81..c4015b3a472 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -29,9 +29,9 @@
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
5535e31a712343a63f5d7d796cd874e563e5ac14
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 9f4b1f5d664afdfc80e1508ab7ed099dff210fbd
+ 5cff8b8eb04adfca21ccdec7e88b9ee7b3952fee
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
@@ -41,18 +41,18 @@
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
9f4b1f5d664afdfc80e1508ab7ed099dff210fbd
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 9f4b1f5d664afdfc80e1508ab7ed099dff210fbd
+ 5cff8b8eb04adfca21ccdec7e88b9ee7b3952fee
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 9f4b1f5d664afdfc80e1508ab7ed099dff210fbd
+ 5cff8b8eb04adfca21ccdec7e88b9ee7b3952fee
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 9f4b1f5d664afdfc80e1508ab7ed099dff210fbd
+ 5cff8b8eb04adfca21ccdec7e88b9ee7b3952fee
diff --git a/eng/Versions.props b/eng/Versions.props
index 0c8eae85ffc..9cddc6aea32 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -24,12 +24,12 @@
8.0.0
8.0.0
8.0.0
- 8.0.3-servicing.24114.23
+ 8.0.4-servicing.24162.12
8.0.0
8.0.3
- 8.0.3
- 8.0.3
- 8.0.3-servicing.24114.23
+ 8.0.4
+ 8.0.4
+ 8.0.4-servicing.24162.12
8.0.0-beta.24113.2
From c76c3e56762aa1b9872f3f853b17f369fe3d373a Mon Sep 17 00:00:00 2001
From: DotNet Bot
Date: Thu, 14 Mar 2024 04:05:15 +0000
Subject: [PATCH 19/22] [internal/release/8.0] Update dependencies from
dnceng/internal/dotnet-runtime
---
NuGet.config | 4 ++--
eng/Version.Details.xml | 12 ++++++------
eng/Versions.props | 4 ++--
3 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/NuGet.config b/NuGet.config
index a1b47285ada..5dc7c38899e 100644
--- a/NuGet.config
+++ b/NuGet.config
@@ -7,7 +7,7 @@
-
+
@@ -22,7 +22,7 @@
-
+
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index c4015b3a472..a0bfd425990 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -29,9 +29,9 @@
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
5535e31a712343a63f5d7d796cd874e563e5ac14
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 5cff8b8eb04adfca21ccdec7e88b9ee7b3952fee
+ 38f2042434044be9a09065b23b7ef342a313a498
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
@@ -43,16 +43,16 @@
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 5cff8b8eb04adfca21ccdec7e88b9ee7b3952fee
+ 38f2042434044be9a09065b23b7ef342a313a498
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 5cff8b8eb04adfca21ccdec7e88b9ee7b3952fee
+ 38f2042434044be9a09065b23b7ef342a313a498
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 5cff8b8eb04adfca21ccdec7e88b9ee7b3952fee
+ 38f2042434044be9a09065b23b7ef342a313a498
diff --git a/eng/Versions.props b/eng/Versions.props
index 9cddc6aea32..b6a57bfe799 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -24,12 +24,12 @@
8.0.0
8.0.0
8.0.0
- 8.0.4-servicing.24162.12
+ 8.0.4-servicing.24163.26
8.0.0
8.0.3
8.0.4
8.0.4
- 8.0.4-servicing.24162.12
+ 8.0.4-servicing.24163.26
8.0.0-beta.24113.2
From c83ddc9b6532240f9f35ea6f22afdb24aa3ea27d Mon Sep 17 00:00:00 2001
From: "dotnet-maestro[bot]"
<42748379+dotnet-maestro[bot]@users.noreply.github.com>
Date: Fri, 15 Mar 2024 16:58:38 -0700
Subject: [PATCH 20/22] [release/8.0] Update dependencies from dotnet/arcade
(#33334)
Microsoft.DotNet.Arcade.Sdk , Microsoft.DotNet.Build.Tasks.Templating , Microsoft.DotNet.Helix.Sdk
From Version 8.0.0-beta.24113.2 -> To Version 8.0.0-beta.24165.4
Co-authored-by: dotnet-maestro[bot]
---
NuGet.config | 2 -
eng/Version.Details.xml | 12 +-
eng/Versions.props | 2 +-
eng/common/SetupNugetSources.ps1 | 10 +-
eng/common/post-build/publish-using-darc.ps1 | 4 +-
eng/common/templates-official/job/job.yml | 71 +++++-------
.../templates-official/job/onelocbuild.yml | 45 ++++----
.../job/publish-build-assets.yml | 86 +++++++++-----
.../templates-official/job/source-build.yml | 7 +-
.../job/source-index-stage1.yml | 25 ++--
.../templates-official/jobs/codeql-build.yml | 2 +-
eng/common/templates-official/jobs/jobs.yml | 27 ++---
.../templates-official/jobs/source-build.yml | 2 +-
.../post-build/common-variables.yml | 6 +-
.../post-build/post-build.yml | 108 ++++++++++--------
.../templates-official/steps/build-reason.yml | 12 ++
.../steps/component-governance.yml | 5 +-
.../templates-official/steps/execute-sdl.yml | 88 ++++++++++++++
.../steps/generate-sbom.yml | 6 +-
.../steps/send-to-helix.yml | 13 +--
.../templates-official/steps/source-build.yml | 25 +++-
.../variables/pool-providers.yml | 45 ++++++++
.../variables/sdl-variables.yml | 2 +-
eng/common/templates/job/job.yml | 4 +
.../templates/job/publish-build-assets.yml | 8 +-
.../templates/post-build/post-build.yml | 12 +-
eng/common/templates/steps/generate-sbom.yml | 2 +-
global.json | 4 +-
28 files changed, 422 insertions(+), 213 deletions(-)
create mode 100644 eng/common/templates-official/steps/build-reason.yml
create mode 100644 eng/common/templates-official/steps/execute-sdl.yml
create mode 100644 eng/common/templates-official/variables/pool-providers.yml
diff --git a/NuGet.config b/NuGet.config
index 8d9f70a526f..77b2bf048ad 100644
--- a/NuGet.config
+++ b/NuGet.config
@@ -4,7 +4,6 @@
-
@@ -19,7 +18,6 @@
-
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index 3a8e051bb81..b807ce76cb1 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -56,17 +56,17 @@
-
+
https://github.com/dotnet/arcade
- da98edc4c3ea539f109ea320672136ceb32591a7
+ f311667e0587f19c3fa9553a909975662107a351
-
+
https://github.com/dotnet/arcade
- da98edc4c3ea539f109ea320672136ceb32591a7
+ f311667e0587f19c3fa9553a909975662107a351
-
+
https://github.com/dotnet/arcade
- da98edc4c3ea539f109ea320672136ceb32591a7
+ f311667e0587f19c3fa9553a909975662107a351
diff --git a/eng/Versions.props b/eng/Versions.props
index 0c8eae85ffc..01398f9cd76 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -32,7 +32,7 @@
8.0.3-servicing.24114.23
- 8.0.0-beta.24113.2
+ 8.0.0-beta.24165.4
diff --git a/eng/common/SetupNugetSources.ps1 b/eng/common/SetupNugetSources.ps1
index fd530c85d0b..efa2fd72bfa 100644
--- a/eng/common/SetupNugetSources.ps1
+++ b/eng/common/SetupNugetSources.ps1
@@ -48,8 +48,7 @@ function AddPackageSource($sources, $SourceName, $SourceEndPoint, $creds, $Usern
else {
Write-Host "Package source $SourceName already present."
}
-
- AddCredential -Creds $creds -Source $SourceName -Username $Username -Password $pwd
+ AddCredential -Creds $creds -Source $SourceName -Username $Username -pwd $pwd
}
# Add a credential node for the specified source
@@ -82,6 +81,7 @@ function AddCredential($creds, $source, $username, $pwd) {
$passwordElement.SetAttribute("key", "ClearTextPassword")
$sourceElement.AppendChild($passwordElement) | Out-Null
}
+
$passwordElement.SetAttribute("value", $pwd)
}
@@ -159,9 +159,9 @@ foreach ($dotnetVersion in $dotnetVersions) {
$feedPrefix = "dotnet" + $dotnetVersion;
$dotnetSource = $sources.SelectSingleNode("add[@key='$feedPrefix']")
if ($dotnetSource -ne $null) {
- AddPackageSource -Sources $sources -SourceName "$feedPrefix-internal" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/$feedPrefix-internal/nuget/v2" -Creds $creds -Username $userName -Password $Password
- AddPackageSource -Sources $sources -SourceName "$feedPrefix-internal-transport" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/$feedPrefix-internal-transport/nuget/v2" -Creds $creds -Username $userName -Password $Password
+ AddPackageSource -Sources $sources -SourceName "$feedPrefix-internal" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/$feedPrefix-internal/nuget/v2" -Creds $creds -Username $userName -pwd $Password
+ AddPackageSource -Sources $sources -SourceName "$feedPrefix-internal-transport" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/$feedPrefix-internal-transport/nuget/v2" -Creds $creds -Username $userName -pwd $Password
}
}
-$doc.Save($filename)
+$doc.Save($filename)
\ No newline at end of file
diff --git a/eng/common/post-build/publish-using-darc.ps1 b/eng/common/post-build/publish-using-darc.ps1
index 1e779fec4dd..5a3a32ea8d7 100644
--- a/eng/common/post-build/publish-using-darc.ps1
+++ b/eng/common/post-build/publish-using-darc.ps1
@@ -12,7 +12,7 @@ param(
try {
. $PSScriptRoot\post-build-utils.ps1
- $darc = Get-Darc
+ $darc = Get-Darc
$optionalParams = [System.Collections.ArrayList]::new()
@@ -46,7 +46,7 @@ try {
}
Write-Host 'done.'
-}
+}
catch {
Write-Host $_
Write-PipelineTelemetryError -Category 'PromoteBuild' -Message "There was an error while trying to publish build '$BuildId' to default channels."
diff --git a/eng/common/templates-official/job/job.yml b/eng/common/templates-official/job/job.yml
index 616bfc38696..a2709d10562 100644
--- a/eng/common/templates-official/job/job.yml
+++ b/eng/common/templates-official/job/job.yml
@@ -25,7 +25,9 @@ parameters:
enablePublishBuildAssets: false
enablePublishTestResults: false
enablePublishUsingPipelines: false
+ enableBuildRetry: false
disableComponentGovernance: ''
+ componentGovernanceIgnoreDirectories: ''
mergeTestResults: false
testRunTitle: ''
testResultsFormat: ''
@@ -34,7 +36,7 @@ parameters:
runAsPublic: false
# Sbom related params
enableSbom: true
- PackageVersion: 6.0.0
+ PackageVersion: 7.0.0
BuildDropPath: '$(Build.SourcesDirectory)/artifacts'
jobs:
@@ -94,10 +96,20 @@ jobs:
- ${{ if ne(variable.group, '') }}:
- group: ${{ variable.group }}
+ # handle template variable syntax
+ # example:
+ # - template: path/to/template.yml
+ # parameters:
+ # [key]: [value]
+ - ${{ if ne(variable.template, '') }}:
+ - template: ${{ variable.template }}
+ ${{ if ne(variable.parameters, '') }}:
+ parameters: ${{ variable.parameters }}
+
# handle key-value variable syntax.
# example:
# - [key]: [value]
- - ${{ if and(eq(variable.name, ''), eq(variable.group, '')) }}:
+ - ${{ if and(eq(variable.name, ''), eq(variable.group, ''), eq(variable.template, '')) }}:
- ${{ each pair in variable }}:
- name: ${{ pair.key }}
value: ${{ pair.value }}
@@ -127,9 +139,10 @@ jobs:
continueOnError: ${{ parameters.continueOnError }}
condition: and(succeeded(), in(variables['_SignType'], 'real', 'test'), eq(variables['Agent.Os'], 'Windows_NT'))
+ - ${{ if and(eq(parameters.runAsPublic, 'false'), eq(variables['System.TeamProject'], 'internal')) }}:
- task: NuGetAuthenticate@1
- - ${{ if or(eq(parameters.artifacts.download, 'true'), ne(parameters.artifacts.download, '')) }}:
+ - ${{ if and(ne(parameters.artifacts.download, 'false'), ne(parameters.artifacts.download, '')) }}:
- task: DownloadPipelineArtifact@2
inputs:
buildType: current
@@ -147,6 +160,7 @@ jobs:
languages: ${{ coalesce(parameters.richCodeNavigationLanguage, 'csharp') }}
environment: ${{ coalesce(parameters.richCodeNavigationEnvironment, 'production') }}
richNavLogOutputDirectory: $(Build.SourcesDirectory)/artifacts/bin
+ uploadRichNavArtifacts: ${{ coalesce(parameters.richCodeNavigationUploadArtifacts, false) }}
continueOnError: true
- template: /eng/common/templates-official/steps/component-governance.yml
@@ -158,6 +172,7 @@ jobs:
disableComponentGovernance: true
${{ else }}:
disableComponentGovernance: ${{ parameters.disableComponentGovernance }}
+ componentGovernanceIgnoreDirectories: ${{ parameters.componentGovernanceIgnoreDirectories }}
- ${{ if eq(parameters.enableMicrobuild, 'true') }}:
- ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
@@ -169,7 +184,7 @@ jobs:
TeamName: $(_TeamName)
- ${{ if ne(parameters.artifacts.publish, '') }}:
- - ${{ if or(eq(parameters.artifacts.publish.artifacts, 'true'), ne(parameters.artifacts.publish.artifacts, '')) }}:
+ - ${{ if and(ne(parameters.artifacts.publish.artifacts, 'false'), ne(parameters.artifacts.publish.artifacts, '')) }}:
- task: CopyFiles@2
displayName: Gather binaries for publish to artifacts
inputs:
@@ -190,7 +205,7 @@ jobs:
ArtifactName: ${{ coalesce(parameters.artifacts.publish.artifacts.name , 'Artifacts_$(Agent.Os)_$(_BuildConfig)') }}
continueOnError: true
condition: always()
- - ${{ if or(eq(parameters.artifacts.publish.logs, 'true'), ne(parameters.artifacts.publish.logs, '')) }}:
+ - ${{ if and(ne(parameters.artifacts.publish.logs, 'false'), ne(parameters.artifacts.publish.logs, '')) }}:
- task: 1ES.PublishPipelineArtifact@1
inputs:
targetPath: 'artifacts/log'
@@ -199,25 +214,6 @@ jobs:
continueOnError: true
condition: always()
- - ${{ if or(eq(parameters.artifacts.publish.manifests, 'true'), ne(parameters.artifacts.publish.manifests, '')) }}:
- - ${{ if and(ne(parameters.enablePublishUsingPipelines, 'true'), eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
- - task: CopyFiles@2
- displayName: Gather Asset Manifests
- inputs:
- SourceFolder: '$(Build.SourcesDirectory)/artifacts/log/$(_BuildConfig)/AssetManifest'
- TargetFolder: '$(Build.ArtifactStagingDirectory)/AssetManifests'
- continueOnError: ${{ parameters.continueOnError }}
- condition: and(succeeded(), eq(variables['_DotNetPublishToBlobFeed'], 'true'))
-
- - task: 1ES.PublishBuildArtifacts@1
- displayName: Push Asset Manifests
- inputs:
- PathtoPublish: '$(Build.ArtifactStagingDirectory)/AssetManifests'
- PublishLocation: Container
- ArtifactName: AssetManifests
- continueOnError: ${{ parameters.continueOnError }}
- condition: and(succeeded(), eq(variables['_DotNetPublishToBlobFeed'], 'true'))
-
- ${{ if ne(parameters.enablePublishBuildArtifacts, 'false') }}:
- task: 1ES.PublishBuildArtifacts@1
displayName: Publish Logs
@@ -250,27 +246,18 @@ jobs:
mergeTestResults: ${{ parameters.mergeTestResults }}
continueOnError: true
condition: always()
-
- - ${{ if and(eq(parameters.enablePublishBuildAssets, true), ne(parameters.enablePublishUsingPipelines, 'true'), eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
- - task: CopyFiles@2
- displayName: Gather Asset Manifests
- inputs:
- SourceFolder: '$(Build.SourcesDirectory)/artifacts/log/$(_BuildConfig)/AssetManifest'
- TargetFolder: '$(Build.StagingDirectory)/AssetManifests'
- continueOnError: ${{ parameters.continueOnError }}
- condition: and(succeeded(), eq(variables['_DotNetPublishToBlobFeed'], 'true'))
-
- - task: 1ES.PublishBuildArtifacts@1
- displayName: Push Asset Manifests
- inputs:
- PathtoPublish: '$(Build.StagingDirectory)/AssetManifests'
- PublishLocation: Container
- ArtifactName: AssetManifests
- continueOnError: ${{ parameters.continueOnError }}
- condition: and(succeeded(), eq(variables['_DotNetPublishToBlobFeed'], 'true'))
- ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest'), eq(parameters.enableSbom, 'true')) }}:
- template: /eng/common/templates-official/steps/generate-sbom.yml
parameters:
PackageVersion: ${{ parameters.packageVersion}}
BuildDropPath: ${{ parameters.buildDropPath }}
+ IgnoreDirectories: ${{ parameters.componentGovernanceIgnoreDirectories }}
+
+ - ${{ if eq(parameters.enableBuildRetry, 'true') }}:
+ - task: 1ES.PublishPipelineArtifact@1
+ inputs:
+ targetPath: '$(Build.SourcesDirectory)\eng\common\BuildConfiguration'
+ artifactName: 'BuildConfiguration'
+ displayName: 'Publish build retry configuration'
+ continueOnError: true
\ No newline at end of file
diff --git a/eng/common/templates-official/job/onelocbuild.yml b/eng/common/templates-official/job/onelocbuild.yml
index e0e9a4bc512..ba9ba493032 100644
--- a/eng/common/templates-official/job/onelocbuild.yml
+++ b/eng/common/templates-official/job/onelocbuild.yml
@@ -14,6 +14,7 @@ parameters:
ReusePr: true
UseLfLineEndings: true
UseCheckedInLocProjectJson: false
+ SkipLocProjectJsonGeneration: false
LanguageSet: VS_Main_Languages
LclSource: lclFilesInRepo
LclPackageId: ''
@@ -22,13 +23,25 @@ parameters:
MirrorRepo: ''
MirrorBranch: main
condition: ''
+ JobNameSuffix: ''
jobs:
-- job: OneLocBuild
+- job: OneLocBuild${{ parameters.JobNameSuffix }}
dependsOn: ${{ parameters.dependsOn }}
- displayName: OneLocBuild
+ displayName: OneLocBuild${{ parameters.JobNameSuffix }}
+
+ variables:
+ - group: OneLocBuildVariables # Contains the CeapexPat and GithubPat
+ - name: _GenerateLocProjectArguments
+ value: -SourcesDirectory ${{ parameters.SourcesDirectory }}
+ -LanguageSet "${{ parameters.LanguageSet }}"
+ -CreateNeutralXlfs
+ - ${{ if eq(parameters.UseCheckedInLocProjectJson, 'true') }}:
+ - name: _GenerateLocProjectArguments
+ value: ${{ variables._GenerateLocProjectArguments }} -UseCheckedInLocProjectJson
+ - template: /eng/common/templates-official/variables/pool-providers.yml
${{ if ne(parameters.pool, '') }}:
pool: ${{ parameters.pool }}
@@ -42,28 +55,18 @@ jobs:
os: windows
# If it's not devdiv, it's dnceng
${{ if ne(variables['System.TeamProject'], 'DevDiv') }}:
- name: NetCore1ESPool-Svc-Internal
+ name: $(DncEngInternalBuildPool)
image: 1es-windows-2022-pt
os: windows
- variables:
- - group: OneLocBuildVariables # Contains the CeapexPat and GithubPat
- - name: _GenerateLocProjectArguments
- value: -SourcesDirectory ${{ parameters.SourcesDirectory }}
- -LanguageSet "${{ parameters.LanguageSet }}"
- -CreateNeutralXlfs
- - ${{ if eq(parameters.UseCheckedInLocProjectJson, 'true') }}:
- - name: _GenerateLocProjectArguments
- value: ${{ variables._GenerateLocProjectArguments }} -UseCheckedInLocProjectJson
-
-
steps:
- - task: Powershell@2
- inputs:
- filePath: $(Build.SourcesDirectory)/eng/common/generate-locproject.ps1
- arguments: $(_GenerateLocProjectArguments)
- displayName: Generate LocProject.json
- condition: ${{ parameters.condition }}
+ - ${{ if ne(parameters.SkipLocProjectJsonGeneration, 'true') }}:
+ - task: Powershell@2
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/common/generate-locproject.ps1
+ arguments: $(_GenerateLocProjectArguments)
+ displayName: Generate LocProject.json
+ condition: ${{ parameters.condition }}
- task: OneLocBuild@2
displayName: OneLocBuild
@@ -75,8 +78,8 @@ jobs:
lclSource: ${{ parameters.LclSource }}
lclPackageId: ${{ parameters.LclPackageId }}
isCreatePrSelected: ${{ parameters.CreatePr }}
+ isAutoCompletePrSelected: ${{ parameters.AutoCompletePr }}
${{ if eq(parameters.CreatePr, true) }}:
- isAutoCompletePrSelected: ${{ parameters.AutoCompletePr }}
isUseLfLineEndingsSelected: ${{ parameters.UseLfLineEndings }}
${{ if eq(parameters.RepoType, 'gitHub') }}:
isShouldReusePrSelected: ${{ parameters.ReusePr }}
diff --git a/eng/common/templates-official/job/publish-build-assets.yml b/eng/common/templates-official/job/publish-build-assets.yml
index 9498aa412db..53138622fe7 100644
--- a/eng/common/templates-official/job/publish-build-assets.yml
+++ b/eng/common/templates-official/job/publish-build-assets.yml
@@ -23,24 +23,46 @@ parameters:
# Optional: whether the build's artifacts will be published using release pipelines or direct feed publishing
publishUsingPipelines: false
+ # Optional: whether the build's artifacts will be published using release pipelines or direct feed publishing
+ publishAssetsImmediately: false
+
+ artifactsPublishingAdditionalParameters: ''
+
+ signingValidationAdditionalParameters: ''
+
jobs:
- job: Asset_Registry_Publish
dependsOn: ${{ parameters.dependsOn }}
+ timeoutInMinutes: 150
- displayName: Publish to Build Asset Registry
-
- pool: ${{ parameters.pool }}
+ ${{ if eq(parameters.publishAssetsImmediately, 'true') }}:
+ displayName: Publish Assets
+ ${{ else }}:
+ displayName: Publish to Build Asset Registry
variables:
+ - template: /eng/common/templates-official/variables/pool-providers.yml
- ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
- - name: _BuildConfig
- value: ${{ parameters.configuration }}
- group: Publish-Build-Assets
- group: AzureDevOps-Artifact-Feeds-Pats
- name: runCodesignValidationInjection
value: false
-
+ - ${{ if eq(parameters.publishAssetsImmediately, 'true') }}:
+ - template: /eng/common/templates-official/post-build/common-variables.yml
+
+ pool:
+ # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com)
+ ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}:
+ name: AzurePipelines-EO
+ image: 1ESPT-Windows2022
+ demands: Cmd
+ os: windows
+ # If it's not devdiv, it's dnceng
+ ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}:
+ name: $(DncEngInternalBuildPool)
+ image: 1es-windows-2022-pt
+ os: windows
steps:
- ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
- task: DownloadBuildArtifacts@0
@@ -51,15 +73,8 @@ jobs:
checkDownloadedFiles: true
condition: ${{ parameters.condition }}
continueOnError: ${{ parameters.continueOnError }}
-
- - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
- - task: NuGetAuthenticate@1
-
- - task: PowerShell@2
- displayName: Enable cross-org NuGet feed authentication
- inputs:
- filePath: $(Build.SourcesDirectory)/eng/common/enable-cross-org-publishing.ps1
- arguments: -token $(dn-bot-all-orgs-artifact-feeds-rw)
+
+ - task: NuGetAuthenticate@1
- task: PowerShell@2
displayName: Publish Build Assets
@@ -68,26 +83,27 @@ jobs:
arguments: -task PublishBuildAssets -restore -msbuildEngine dotnet
/p:ManifestsPath='$(Build.StagingDirectory)/Download/AssetManifests'
/p:BuildAssetRegistryToken=$(MaestroAccessToken)
- /p:MaestroApiEndpoint=https://maestro.dot.net
+ /p:MaestroApiEndpoint=https://maestro-prod.westus2.cloudapp.azure.com
/p:PublishUsingPipelines=${{ parameters.publishUsingPipelines }}
- /p:Configuration=$(_BuildConfig)
/p:OfficialBuildId=$(Build.BuildNumber)
condition: ${{ parameters.condition }}
continueOnError: ${{ parameters.continueOnError }}
-
+
- task: powershell@2
displayName: Create ReleaseConfigs Artifact
inputs:
targetType: inline
script: |
- Add-Content -Path "$(Build.StagingDirectory)/ReleaseConfigs.txt" -Value $(BARBuildId)
- Add-Content -Path "$(Build.StagingDirectory)/ReleaseConfigs.txt" -Value "$(DefaultChannels)"
- Add-Content -Path "$(Build.StagingDirectory)/ReleaseConfigs.txt" -Value $(IsStableBuild)
-
+ New-Item -Path "$(Build.StagingDirectory)/ReleaseConfigs" -ItemType Directory -Force
+ $filePath = "$(Build.StagingDirectory)/ReleaseConfigs/ReleaseConfigs.txt"
+ Add-Content -Path $filePath -Value $(BARBuildId)
+ Add-Content -Path $filePath -Value "$(DefaultChannels)"
+ Add-Content -Path $filePath -Value $(IsStableBuild)
+
- task: 1ES.PublishBuildArtifacts@1
displayName: Publish ReleaseConfigs Artifact
inputs:
- PathtoPublish: '$(Build.StagingDirectory)/ReleaseConfigs.txt'
+ PathtoPublish: '$(Build.StagingDirectory)/ReleaseConfigs'
PublishLocation: Container
ArtifactName: ReleaseConfigs
@@ -109,13 +125,31 @@ jobs:
- task: 1ES.PublishBuildArtifacts@1
displayName: Publish SymbolPublishingExclusionsFile Artifact
- condition: eq(variables['SymbolExclusionFile'], 'true')
+ condition: eq(variables['SymbolExclusionFile'], 'true')
inputs:
PathtoPublish: '$(Build.SourcesDirectory)/eng/SymbolPublishingExclusionsFile.txt'
PublishLocation: Container
ArtifactName: ReleaseConfigs
-
+
+ - ${{ if eq(parameters.publishAssetsImmediately, 'true') }}:
+ - template: /eng/common/templates-official/post-build/setup-maestro-vars.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+
+ - task: PowerShell@2
+ displayName: Publish Using Darc
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1
+ arguments: -BuildId $(BARBuildId)
+ -PublishingInfraVersion 3
+ -AzdoToken '$(publishing-dnceng-devdiv-code-r-build-re)'
+ -MaestroToken '$(MaestroApiAccessToken)'
+ -WaitPublishingFinish true
+ -ArtifactsPublishingAdditionalParameters '${{ parameters.artifactsPublishingAdditionalParameters }}'
+ -SymbolPublishingAdditionalParameters '${{ parameters.symbolPublishingAdditionalParameters }}'
+
- ${{ if eq(parameters.enablePublishBuildArtifacts, 'true') }}:
- template: /eng/common/templates-official/steps/publish-logs.yml
parameters:
- JobLabel: 'Publish_Artifacts_Logs'
+ JobLabel: 'Publish_Artifacts_Logs'
diff --git a/eng/common/templates-official/job/source-build.yml b/eng/common/templates-official/job/source-build.yml
index 96be5e6e115..8aba3b44bb2 100644
--- a/eng/common/templates-official/job/source-build.yml
+++ b/eng/common/templates-official/job/source-build.yml
@@ -44,14 +44,17 @@ jobs:
${{ if eq(parameters.platform.pool, '') }}:
# The default VM host AzDO pool. This should be capable of running Docker containers: almost all
# source-build builds run in Docker, including the default managed platform.
+ # /eng/common/templates-official/variables/pool-providers.yml can't be used here (some customers declare variables already), so duplicate its logic
pool:
${{ if eq(variables['System.TeamProject'], 'public') }}:
- name: NetCore-Svc-Public
+ name: $[replace(replace(eq(contains(coalesce(variables['System.PullRequest.TargetBranch'], variables['Build.SourceBranch'], 'refs/heads/main'), 'release'), 'true'), True, 'NetCore-Svc-Public' ), False, 'NetCore-Public')]
demands: ImageOverride -equals Build.Ubuntu.1804.Amd64.Open
+
${{ if eq(variables['System.TeamProject'], 'internal') }}:
- name: NetCore1ESPool-Svc-Internal
+ name: $[replace(replace(eq(contains(coalesce(variables['System.PullRequest.TargetBranch'], variables['Build.SourceBranch'], 'refs/heads/main'), 'release'), 'true'), True, 'NetCore1ESPool-Svc-Internal'), False, 'NetCore1ESPool-Internal')]
image: 1es-mariner-2-pt
os: linux
+
${{ if ne(parameters.platform.pool, '') }}:
pool: ${{ parameters.platform.pool }}
diff --git a/eng/common/templates-official/job/source-index-stage1.yml b/eng/common/templates-official/job/source-index-stage1.yml
index 3d8b0b966cb..4b633739170 100644
--- a/eng/common/templates-official/job/source-index-stage1.yml
+++ b/eng/common/templates-official/job/source-index-stage1.yml
@@ -1,16 +1,13 @@
parameters:
runAsPublic: false
- sourceIndexPackageVersion: 1.0.1-20210614.1
+ sourceIndexPackageVersion: 1.0.1-20230228.2
sourceIndexPackageSource: https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json
sourceIndexBuildCommand: powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -Command "eng/common/build.ps1 -restore -build -binarylog -ci"
preSteps: []
binlogPath: artifacts/log/Debug/Build.binlog
- pool:
- name: NetCore1ESPool-Svc-Internal
- image: 1es-windows-2022-pt
- os: windows
condition: ''
dependsOn: ''
+ pool: ''
jobs:
- job: SourceIndexStage1
@@ -25,17 +22,29 @@ jobs:
value: ${{ parameters.binlogPath }}
- ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
- group: source-dot-net stage1 variables
+ - template: /eng/common/templates-official/variables/pool-providers.yml
+
+ ${{ if ne(parameters.pool, '') }}:
+ pool: ${{ parameters.pool }}
+ ${{ if eq(parameters.pool, '') }}:
+ pool:
+ ${{ if eq(variables['System.TeamProject'], 'public') }}:
+ name: $(DncEngPublicBuildPool)
+ demands: ImageOverride -equals windows.vs2019.amd64.open
+ ${{ if eq(variables['System.TeamProject'], 'internal') }}:
+ name: $(DncEngInternalBuildPool)
+ image: 1es-windows-2022-pt
+ os: windows
- pool: ${{ parameters.pool }}
steps:
- ${{ each preStep in parameters.preSteps }}:
- ${{ preStep }}
- task: UseDotNet@2
- displayName: Use .NET Core sdk 3.1
+ displayName: Use .NET Core SDK 6
inputs:
packageType: sdk
- version: 3.1.x
+ version: 6.0.x
installationPath: $(Agent.TempDirectory)/dotnet
workingDirectory: $(Agent.TempDirectory)
diff --git a/eng/common/templates-official/jobs/codeql-build.yml b/eng/common/templates-official/jobs/codeql-build.yml
index 0bf7ee29f40..b68d3c2f319 100644
--- a/eng/common/templates-official/jobs/codeql-build.yml
+++ b/eng/common/templates-official/jobs/codeql-build.yml
@@ -21,7 +21,7 @@ jobs:
# The Guardian version specified in 'eng/common/sdl/packages.config'. This value must be kept in
# sync with the packages.config file.
- name: DefaultGuardianVersion
- value: 0.110.1
+ value: 0.109.0
- name: GuardianPackagesConfigFile
value: $(Build.SourcesDirectory)\eng\common\sdl\packages.config
- name: GuardianVersion
diff --git a/eng/common/templates-official/jobs/jobs.yml b/eng/common/templates-official/jobs/jobs.yml
index 669ccd48f7f..857a0f8ba43 100644
--- a/eng/common/templates-official/jobs/jobs.yml
+++ b/eng/common/templates-official/jobs/jobs.yml
@@ -20,13 +20,20 @@ parameters:
enabled: false
# Optional: Include toolset dependencies in the generated graph files
includeToolset: false
-
+
# Required: A collection of jobs to run - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#job
jobs: []
# Optional: Override automatically derived dependsOn value for "publish build assets" job
publishBuildAssetsDependsOn: ''
+ # Optional: Publish the assets as soon as the publish to BAR stage is complete, rather doing so in a separate stage.
+ publishAssetsImmediately: false
+
+ # Optional: If using publishAssetsImmediately and additional parameters are needed, can be used to send along additional parameters (normally sent to post-build.yml)
+ artifactsPublishingAdditionalParameters: ''
+ signingValidationAdditionalParameters: ''
+
# Optional: should run as a public build even in the internal project
# if 'true', the build won't run any of the internal only steps, even if it is running in non-public projects.
runAsPublic: false
@@ -40,7 +47,7 @@ parameters:
jobs:
- ${{ each job in parameters.jobs }}:
- template: ../job/job.yml
- parameters:
+ parameters:
# pass along parameters
${{ each parameter in parameters }}:
${{ if ne(parameter.key, 'jobs') }}:
@@ -68,7 +75,6 @@ jobs:
${{ parameter.key }}: ${{ parameter.value }}
- ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
-
- ${{ if or(eq(parameters.enablePublishBuildAssets, true), eq(parameters.artifacts.publish.manifests, 'true'), ne(parameters.artifacts.publish.manifests, '')) }}:
- template: ../job/publish-build-assets.yml
parameters:
@@ -82,19 +88,10 @@ jobs:
- ${{ job.job }}
- ${{ if eq(parameters.enableSourceBuild, true) }}:
- Source_Build_Complete
- pool:
- # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com)
- ${{ if eq(variables['System.TeamProject'], 'DevDiv') }}:
- name: AzurePipelines-EO
- image: 1ESPT-Windows2022
- demands: Cmd
- os: windows
- # If it's not devdiv, it's dnceng
- ${{ else }}:
- name: NetCore1ESPool-Svc-Internal
- image: 1es-windows-2022-pt
- os: windows
runAsPublic: ${{ parameters.runAsPublic }}
publishUsingPipelines: ${{ parameters.enablePublishUsingPipelines }}
+ publishAssetsImmediately: ${{ parameters.publishAssetsImmediately }}
enablePublishBuildArtifacts: ${{ parameters.enablePublishBuildArtifacts }}
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ signingValidationAdditionalParameters: ${{ parameters.signingValidationAdditionalParameters }}
diff --git a/eng/common/templates-official/jobs/source-build.yml b/eng/common/templates-official/jobs/source-build.yml
index 2159009dc8e..08e5db9bb11 100644
--- a/eng/common/templates-official/jobs/source-build.yml
+++ b/eng/common/templates-official/jobs/source-build.yml
@@ -14,7 +14,7 @@ parameters:
# This is the default platform provided by Arcade, intended for use by a managed-only repo.
defaultManagedPlatform:
name: 'Managed'
- container: 'mcr.microsoft.com/dotnet-buildtools/prereqs:centos-7-3e800f1-20190501005343'
+ container: 'mcr.microsoft.com/dotnet-buildtools/prereqs:centos-stream8'
# Defines the platforms on which to run build jobs. One job is created for each platform, and the
# object in this array is sent to the job template as 'platform'. If no platforms are specified,
diff --git a/eng/common/templates-official/post-build/common-variables.yml b/eng/common/templates-official/post-build/common-variables.yml
index fae340f4d20..c24193acfc9 100644
--- a/eng/common/templates-official/post-build/common-variables.yml
+++ b/eng/common/templates-official/post-build/common-variables.yml
@@ -1,8 +1,4 @@
variables:
- - group: AzureDevOps-Artifact-Feeds-Pats
- - group: DotNet-Blob-Feed
- - group: DotNet-DotNetCli-Storage
- - group: DotNet-MSRC-Storage
- group: Publish-Build-Assets
# Whether the build is internal or not
@@ -11,7 +7,7 @@ variables:
# Default Maestro++ API Endpoint and API Version
- name: MaestroApiEndPoint
- value: "https://maestro.dot.net"
+ value: "https://maestro-prod.westus2.cloudapp.azure.com"
- name: MaestroApiAccessToken
value: $(MaestroAccessToken)
- name: MaestroApiVersion
diff --git a/eng/common/templates-official/post-build/post-build.yml b/eng/common/templates-official/post-build/post-build.yml
index 80bfa4946c6..5c98fe1c0f3 100644
--- a/eng/common/templates-official/post-build/post-build.yml
+++ b/eng/common/templates-official/post-build/post-build.yml
@@ -39,7 +39,7 @@ parameters:
displayName: Enable NuGet validation
type: boolean
default: true
-
+
- name: publishInstallersAndChecksums
displayName: Publish installers and checksums
type: boolean
@@ -49,6 +49,7 @@ parameters:
type: object
default:
enable: false
+ publishGdn: false
continueOnError: false
params: ''
artifactNames: ''
@@ -82,6 +83,11 @@ parameters:
default:
- Validate
+ # Optional: Call asset publishing rather than running in a separate stage
+ - name: publishAssetsImmediately
+ type: boolean
+ default: false
+
stages:
- ${{ if or(eq( parameters.enableNugetValidation, 'true'), eq(parameters.enableSigningValidation, 'true'), eq(parameters.enableSourceLinkValidation, 'true'), eq(parameters.SDLValidationParameters.enable, 'true')) }}:
- stage: Validate
@@ -89,10 +95,11 @@ stages:
displayName: Validate Build Assets
variables:
- template: common-variables.yml
+ - template: /eng/common/templates-official/variables/pool-providers.yml
jobs:
- job:
displayName: NuGet Validation
- condition: eq( ${{ parameters.enableNugetValidation }}, 'true')
+ condition: and(succeededOrFailed(), eq( ${{ parameters.enableNugetValidation }}, 'true'))
pool:
# We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com)
${{ if eq(variables['System.TeamProject'], 'DevDiv') }}:
@@ -101,8 +108,8 @@ stages:
demands: Cmd
os: windows
# If it's not devdiv, it's dnceng
- ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}:
- name: NetCore1ESPool-Svc-Internal
+ ${{ else }}:
+ name: $(DncEngInternalBuildPool)
image: 1es-windows-2022-pt
os: windows
@@ -127,8 +134,8 @@ stages:
displayName: Validate
inputs:
filePath: $(Build.SourcesDirectory)/eng/common/post-build/nuget-validation.ps1
- arguments: -PackagesPath $(Build.ArtifactStagingDirectory)/PackageArtifacts/
- -ToolDestinationPath $(Agent.BuildDirectory)/Extract/
+ arguments: -PackagesPath $(Build.ArtifactStagingDirectory)/PackageArtifacts/
+ -ToolDestinationPath $(Agent.BuildDirectory)/Extract/
- job:
displayName: Signing Validation
@@ -137,11 +144,12 @@ stages:
# We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com)
${{ if eq(variables['System.TeamProject'], 'DevDiv') }}:
name: AzurePipelines-EO
+ image: 1ESPT-Windows2022
demands: Cmd
os: windows
# If it's not devdiv, it's dnceng
- ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}:
- name: NetCore1ESPool-Svc-Internal
+ ${{ else }}:
+ name: $(DncEngInternalBuildPool)
image: 1es-windows-2022-pt
os: windows
steps:
@@ -170,12 +178,6 @@ stages:
- task: NuGetAuthenticate@1
displayName: 'Authenticate to AzDO Feeds'
- - task: PowerShell@2
- displayName: Enable cross-org publishing
- inputs:
- filePath: eng\common\enable-cross-org-publishing.ps1
- arguments: -token $(dn-bot-dnceng-artifact-feeds-rw)
-
# Signing validation will optionally work with the buildmanifest file which is downloaded from
# Azure DevOps above.
- task: PowerShell@2
@@ -191,6 +193,7 @@ stages:
parameters:
StageLabel: 'Validation'
JobLabel: 'Signing'
+ BinlogToolVersion: $(BinlogToolVersion)
- job:
displayName: SourceLink Validation
@@ -203,8 +206,8 @@ stages:
demands: Cmd
os: windows
# If it's not devdiv, it's dnceng
- ${{ if ne(variables['System.TeamProject'], 'DevDiv') }}:
- name: NetCore1ESPool-Svc-Internal
+ ${{ else }}:
+ name: $(DncEngInternalBuildPool)
image: 1es-windows-2022-pt
os: windows
steps:
@@ -228,50 +231,55 @@ stages:
displayName: Validate
inputs:
filePath: $(Build.SourcesDirectory)/eng/common/post-build/sourcelink-validation.ps1
- arguments: -InputPath $(Build.ArtifactStagingDirectory)/BlobArtifacts/
- -ExtractPath $(Agent.BuildDirectory)/Extract/
- -GHRepoName $(Build.Repository.Name)
+ arguments: -InputPath $(Build.ArtifactStagingDirectory)/BlobArtifacts/
+ -ExtractPath $(Agent.BuildDirectory)/Extract/
+ -GHRepoName $(Build.Repository.Name)
-GHCommit $(Build.SourceVersion)
-SourcelinkCliVersion $(SourceLinkCLIVersion)
continueOnError: true
-- stage: publish_using_darc
- ${{ if or(eq(parameters.enableNugetValidation, 'true'), eq(parameters.enableSigningValidation, 'true'), eq(parameters.enableSourceLinkValidation, 'true'), eq(parameters.SDLValidationParameters.enable, 'true')) }}:
- dependsOn: ${{ parameters.publishDependsOn }}
- ${{ if and(ne(parameters.enableNugetValidation, 'true'), ne(parameters.enableSigningValidation, 'true'), ne(parameters.enableSourceLinkValidation, 'true'), ne(parameters.SDLValidationParameters.enable, 'true')) }}:
- dependsOn: ${{ parameters.validateDependsOn }}
- displayName: Publish using Darc
- variables:
- - template: common-variables.yml
- jobs:
- - job:
- displayName: Publish Using Darc
- timeoutInMinutes: 120
- pool:
- # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com)
+- ${{ if ne(parameters.publishAssetsImmediately, 'true') }}:
+ - stage: publish_using_darc
+ ${{ if or(eq(parameters.enableNugetValidation, 'true'), eq(parameters.enableSigningValidation, 'true'), eq(parameters.enableSourceLinkValidation, 'true'), eq(parameters.SDLValidationParameters.enable, 'true')) }}:
+ dependsOn: ${{ parameters.publishDependsOn }}
+ ${{ else }}:
+ dependsOn: ${{ parameters.validateDependsOn }}
+ displayName: Publish using Darc
+ variables:
+ - template: common-variables.yml
+ - template: /eng/common/templates-official/variables/pool-providers.yml
+ jobs:
+ - job:
+ displayName: Publish Using Darc
+ timeoutInMinutes: 120
+ pool:
+ # We don't use the collection uri here because it might vary (.visualstudio.com vs. dev.azure.com)
${{ if eq(variables['System.TeamProject'], 'DevDiv') }}:
name: AzurePipelines-EO
+ image: 1ESPT-Windows2022
demands: Cmd
os: windows
# If it's not devdiv, it's dnceng
${{ else }}:
- name: NetCore1ESPool-Svc-Internal
+ name: $(DncEngInternalBuildPool)
image: 1es-windows-2022-pt
os: windows
- steps:
- - template: setup-maestro-vars.yml
- parameters:
- BARBuildId: ${{ parameters.BARBuildId }}
- PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+ steps:
+ - template: setup-maestro-vars.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
- - task: PowerShell@2
- displayName: Publish Using Darc
- inputs:
- filePath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1
- arguments: -BuildId $(BARBuildId)
- -PublishingInfraVersion ${{ parameters.publishingInfraVersion }}
- -AzdoToken '$(publishing-dnceng-devdiv-code-r-build-re)'
- -MaestroToken '$(MaestroApiAccessToken)'
- -WaitPublishingFinish true
- -ArtifactsPublishingAdditionalParameters '${{ parameters.artifactsPublishingAdditionalParameters }}'
- -SymbolPublishingAdditionalParameters '${{ parameters.symbolPublishingAdditionalParameters }}'
+ - task: NuGetAuthenticate@1
+
+ - task: PowerShell@2
+ displayName: Publish Using Darc
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1
+ arguments: -BuildId $(BARBuildId)
+ -PublishingInfraVersion ${{ parameters.publishingInfraVersion }}
+ -AzdoToken '$(publishing-dnceng-devdiv-code-r-build-re)'
+ -MaestroToken '$(MaestroApiAccessToken)'
+ -WaitPublishingFinish true
+ -ArtifactsPublishingAdditionalParameters '${{ parameters.artifactsPublishingAdditionalParameters }}'
+ -SymbolPublishingAdditionalParameters '${{ parameters.symbolPublishingAdditionalParameters }}'
diff --git a/eng/common/templates-official/steps/build-reason.yml b/eng/common/templates-official/steps/build-reason.yml
new file mode 100644
index 00000000000..eba58109b52
--- /dev/null
+++ b/eng/common/templates-official/steps/build-reason.yml
@@ -0,0 +1,12 @@
+# build-reason.yml
+# Description: runs steps if build.reason condition is valid. conditions is a string of valid build reasons
+# to include steps (',' separated).
+parameters:
+ conditions: ''
+ steps: []
+
+steps:
+ - ${{ if and( not(startsWith(parameters.conditions, 'not')), contains(parameters.conditions, variables['build.reason'])) }}:
+ - ${{ parameters.steps }}
+ - ${{ if and( startsWith(parameters.conditions, 'not'), not(contains(parameters.conditions, variables['build.reason']))) }}:
+ - ${{ parameters.steps }}
diff --git a/eng/common/templates-official/steps/component-governance.yml b/eng/common/templates-official/steps/component-governance.yml
index babc2757d8d..0ecec47b0c9 100644
--- a/eng/common/templates-official/steps/component-governance.yml
+++ b/eng/common/templates-official/steps/component-governance.yml
@@ -1,5 +1,6 @@
parameters:
disableComponentGovernance: false
+ componentGovernanceIgnoreDirectories: ''
steps:
- ${{ if eq(parameters.disableComponentGovernance, 'true') }}:
@@ -7,4 +8,6 @@ steps:
displayName: Set skipComponentGovernanceDetection variable
- ${{ if ne(parameters.disableComponentGovernance, 'true') }}:
- task: ComponentGovernanceComponentDetection@0
- continueOnError: true
\ No newline at end of file
+ continueOnError: true
+ inputs:
+ ignoreDirectories: ${{ parameters.componentGovernanceIgnoreDirectories }}
\ No newline at end of file
diff --git a/eng/common/templates-official/steps/execute-sdl.yml b/eng/common/templates-official/steps/execute-sdl.yml
new file mode 100644
index 00000000000..07426fde05d
--- /dev/null
+++ b/eng/common/templates-official/steps/execute-sdl.yml
@@ -0,0 +1,88 @@
+parameters:
+ overrideGuardianVersion: ''
+ executeAllSdlToolsScript: ''
+ overrideParameters: ''
+ additionalParameters: ''
+ publishGuardianDirectoryToPipeline: false
+ sdlContinueOnError: false
+ condition: ''
+
+steps:
+- task: NuGetAuthenticate@1
+ inputs:
+ nuGetServiceConnections: GuardianConnect
+
+- task: NuGetToolInstaller@1
+ displayName: 'Install NuGet.exe'
+
+- ${{ if ne(parameters.overrideGuardianVersion, '') }}:
+ - pwsh: |
+ Set-Location -Path $(Build.SourcesDirectory)\eng\common\sdl
+ . .\sdl.ps1
+ $guardianCliLocation = Install-Gdn -Path $(Build.SourcesDirectory)\.artifacts -Version ${{ parameters.overrideGuardianVersion }}
+ Write-Host "##vso[task.setvariable variable=GuardianCliLocation]$guardianCliLocation"
+ displayName: Install Guardian (Overridden)
+
+- ${{ if eq(parameters.overrideGuardianVersion, '') }}:
+ - pwsh: |
+ Set-Location -Path $(Build.SourcesDirectory)\eng\common\sdl
+ . .\sdl.ps1
+ $guardianCliLocation = Install-Gdn -Path $(Build.SourcesDirectory)\.artifacts
+ Write-Host "##vso[task.setvariable variable=GuardianCliLocation]$guardianCliLocation"
+ displayName: Install Guardian
+
+- ${{ if ne(parameters.overrideParameters, '') }}:
+ - powershell: ${{ parameters.executeAllSdlToolsScript }} ${{ parameters.overrideParameters }}
+ displayName: Execute SDL (Overridden)
+ continueOnError: ${{ parameters.sdlContinueOnError }}
+ condition: ${{ parameters.condition }}
+
+- ${{ if eq(parameters.overrideParameters, '') }}:
+ - powershell: ${{ parameters.executeAllSdlToolsScript }}
+ -GuardianCliLocation $(GuardianCliLocation)
+ -NugetPackageDirectory $(Build.SourcesDirectory)\.packages
+ -AzureDevOpsAccessToken $(dn-bot-dotnet-build-rw-code-rw)
+ ${{ parameters.additionalParameters }}
+ displayName: Execute SDL
+ continueOnError: ${{ parameters.sdlContinueOnError }}
+ condition: ${{ parameters.condition }}
+
+- ${{ if ne(parameters.publishGuardianDirectoryToPipeline, 'false') }}:
+ # We want to publish the Guardian results and configuration for easy diagnosis. However, the
+ # '.gdn' dir is a mix of configuration, results, extracted dependencies, and Guardian default
+ # tooling files. Some of these files are large and aren't useful during an investigation, so
+ # exclude them by simply deleting them before publishing. (As of writing, there is no documented
+ # way to selectively exclude a dir from the pipeline artifact publish task.)
+ - task: DeleteFiles@1
+ displayName: Delete Guardian dependencies to avoid uploading
+ inputs:
+ SourceFolder: $(Agent.BuildDirectory)/.gdn
+ Contents: |
+ c
+ i
+ condition: succeededOrFailed()
+
+ - publish: $(Agent.BuildDirectory)/.gdn
+ artifact: GuardianConfiguration
+ displayName: Publish GuardianConfiguration
+ condition: succeededOrFailed()
+
+ # Publish the SARIF files in a container named CodeAnalysisLogs to enable integration
+ # with the "SARIF SAST Scans Tab" Azure DevOps extension
+ - task: CopyFiles@2
+ displayName: Copy SARIF files
+ inputs:
+ flattenFolders: true
+ sourceFolder: $(Agent.BuildDirectory)/.gdn/rc/
+ contents: '**/*.sarif'
+ targetFolder: $(Build.SourcesDirectory)/CodeAnalysisLogs
+ condition: succeededOrFailed()
+
+ # Use PublishBuildArtifacts because the SARIF extension only checks this case
+ # see microsoft/sarif-azuredevops-extension#4
+ - task: PublishBuildArtifacts@1
+ displayName: Publish SARIF files to CodeAnalysisLogs container
+ inputs:
+ pathToPublish: $(Build.SourcesDirectory)/CodeAnalysisLogs
+ artifactName: CodeAnalysisLogs
+ condition: succeededOrFailed()
\ No newline at end of file
diff --git a/eng/common/templates-official/steps/generate-sbom.yml b/eng/common/templates-official/steps/generate-sbom.yml
index 7fc4f358023..1bf43bf807a 100644
--- a/eng/common/templates-official/steps/generate-sbom.yml
+++ b/eng/common/templates-official/steps/generate-sbom.yml
@@ -2,12 +2,14 @@
# PackageName - The name of the package this SBOM represents.
# PackageVersion - The version of the package this SBOM represents.
# ManifestDirPath - The path of the directory where the generated manifest files will be placed
+# IgnoreDirectories - Directories to ignore for SBOM generation. This will be passed through to the CG component detector.
parameters:
- PackageVersion: 6.0.0
+ PackageVersion: 8.0.0
BuildDropPath: '$(Build.SourcesDirectory)/artifacts'
PackageName: '.NET'
ManifestDirPath: $(Build.ArtifactStagingDirectory)/sbom
+ IgnoreDirectories: ''
sbomContinueOnError: true
steps:
@@ -34,6 +36,8 @@ steps:
BuildDropPath: ${{ parameters.buildDropPath }}
PackageVersion: ${{ parameters.packageVersion }}
ManifestDirPath: ${{ parameters.manifestDirPath }}
+ ${{ if ne(parameters.IgnoreDirectories, '') }}:
+ AdditionalComponentDetectorArgs: '--IgnoreDirectories ${{ parameters.IgnoreDirectories }}'
- task: 1ES.PublishPipelineArtifact@1
displayName: Publish SBOM manifest
diff --git a/eng/common/templates-official/steps/send-to-helix.yml b/eng/common/templates-official/steps/send-to-helix.yml
index cd02ae1607f..3eb7e2d5f84 100644
--- a/eng/common/templates-official/steps/send-to-helix.yml
+++ b/eng/common/templates-official/steps/send-to-helix.yml
@@ -3,7 +3,7 @@ parameters:
HelixSource: 'pr/default' # required -- sources must start with pr/, official/, prodcon/, or agent/
HelixType: 'tests/default/' # required -- Helix telemetry which identifies what type of data this is; should include "test" for clarity and must end in '/'
HelixBuild: $(Build.BuildNumber) # required -- the build number Helix will use to identify this -- automatically set to the AzDO build number
- HelixTargetQueues: '' # required -- semicolon delimited list of Helix queues to test on; see https://helix.dot.net/ for a list of queues
+ HelixTargetQueues: '' # required -- semicolon-delimited list of Helix queues to test on; see https://helix.dot.net/ for a list of queues
HelixAccessToken: '' # required -- access token to make Helix API requests; should be provided by the appropriate variable group
HelixConfiguration: '' # optional -- additional property attached to a job
HelixPreCommands: '' # optional -- commands to run before Helix work item execution
@@ -12,7 +12,7 @@ parameters:
WorkItemCommand: '' # optional -- a command to execute on the payload; requires WorkItemDirectory; incompatible with XUnitProjects
WorkItemTimeout: '' # optional -- a timeout in TimeSpan.Parse-ready value (e.g. 00:02:00) for the work item command; requires WorkItemDirectory; incompatible with XUnitProjects
CorrelationPayloadDirectory: '' # optional -- a directory to zip up and send to Helix as a correlation payload
- XUnitProjects: '' # optional -- semicolon delimited list of XUnitProjects to parse and send to Helix; requires XUnitRuntimeTargetFramework, XUnitPublishTargetFramework, XUnitRunnerVersion, and IncludeDotNetCli=true
+ XUnitProjects: '' # optional -- semicolon-delimited list of XUnitProjects to parse and send to Helix; requires XUnitRuntimeTargetFramework, XUnitPublishTargetFramework, XUnitRunnerVersion, and IncludeDotNetCli=true
XUnitWorkItemTimeout: '' # optional -- the workitem timeout in seconds for all workitems created from the xUnit projects specified by XUnitProjects
XUnitPublishTargetFramework: '' # optional -- framework to use to publish your xUnit projects
XUnitRuntimeTargetFramework: '' # optional -- framework to use for the xUnit console runner
@@ -20,17 +20,16 @@ parameters:
IncludeDotNetCli: false # optional -- true will download a version of the .NET CLI onto the Helix machine as a correlation payload; requires DotNetCliPackageType and DotNetCliVersion
DotNetCliPackageType: '' # optional -- either 'sdk', 'runtime' or 'aspnetcore-runtime'; determines whether the sdk or runtime will be sent to Helix; see https://raw.githubusercontent.com/dotnet/core/main/release-notes/releases-index.json
DotNetCliVersion: '' # optional -- version of the CLI to send to Helix; based on this: https://raw.githubusercontent.com/dotnet/core/main/release-notes/releases-index.json
- EnableXUnitReporter: false # optional -- true enables XUnit result reporting to Mission Control
WaitForWorkItemCompletion: true # optional -- true will make the task wait until work items have been completed and fail the build if work items fail. False is "fire and forget."
IsExternal: false # [DEPRECATED] -- doesn't do anything, jobs are external if HelixAccessToken is empty and Creator is set
- HelixBaseUri: 'https://helix.dot.net/' # optional -- sets the Helix API base URI (allows targeting int)
+ HelixBaseUri: 'https://helix.dot.net/' # optional -- sets the Helix API base URI (allows targeting https://helix.int-dot.net )
Creator: '' # optional -- if the build is external, use this to specify who is sending the job
DisplayNamePrefix: 'Run Tests' # optional -- rename the beginning of the displayName of the steps in AzDO
condition: succeeded() # optional -- condition for step to execute; defaults to succeeded()
continueOnError: false # optional -- determines whether to continue the build if the step errors; defaults to false
steps:
- - powershell: 'powershell "$env:BUILD_SOURCESDIRECTORY\eng\common\msbuild.ps1 $env:BUILD_SOURCESDIRECTORY\eng\common\helixpublish.proj /restore /t:Test /bl:$env:BUILD_SOURCESDIRECTORY\artifacts\log\$env:BuildConfig\SendToHelix.binlog"'
+ - powershell: 'powershell "$env:BUILD_SOURCESDIRECTORY\eng\common\msbuild.ps1 $env:BUILD_SOURCESDIRECTORY\eng\common\helixpublish.proj /restore /p:TreatWarningsAsErrors=false /t:Test /bl:$env:BUILD_SOURCESDIRECTORY\artifacts\log\$env:BuildConfig\SendToHelix.binlog"'
displayName: ${{ parameters.DisplayNamePrefix }} (Windows)
env:
BuildConfig: $(_BuildConfig)
@@ -54,14 +53,13 @@ steps:
IncludeDotNetCli: ${{ parameters.IncludeDotNetCli }}
DotNetCliPackageType: ${{ parameters.DotNetCliPackageType }}
DotNetCliVersion: ${{ parameters.DotNetCliVersion }}
- EnableXUnitReporter: ${{ parameters.EnableXUnitReporter }}
WaitForWorkItemCompletion: ${{ parameters.WaitForWorkItemCompletion }}
HelixBaseUri: ${{ parameters.HelixBaseUri }}
Creator: ${{ parameters.Creator }}
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
condition: and(${{ parameters.condition }}, eq(variables['Agent.Os'], 'Windows_NT'))
continueOnError: ${{ parameters.continueOnError }}
- - script: $BUILD_SOURCESDIRECTORY/eng/common/msbuild.sh $BUILD_SOURCESDIRECTORY/eng/common/helixpublish.proj /restore /t:Test /bl:$BUILD_SOURCESDIRECTORY/artifacts/log/$BuildConfig/SendToHelix.binlog
+ - script: $BUILD_SOURCESDIRECTORY/eng/common/msbuild.sh $BUILD_SOURCESDIRECTORY/eng/common/helixpublish.proj /restore /p:TreatWarningsAsErrors=false /t:Test /bl:$BUILD_SOURCESDIRECTORY/artifacts/log/$BuildConfig/SendToHelix.binlog
displayName: ${{ parameters.DisplayNamePrefix }} (Unix)
env:
BuildConfig: $(_BuildConfig)
@@ -85,7 +83,6 @@ steps:
IncludeDotNetCli: ${{ parameters.IncludeDotNetCli }}
DotNetCliPackageType: ${{ parameters.DotNetCliPackageType }}
DotNetCliVersion: ${{ parameters.DotNetCliVersion }}
- EnableXUnitReporter: ${{ parameters.EnableXUnitReporter }}
WaitForWorkItemCompletion: ${{ parameters.WaitForWorkItemCompletion }}
HelixBaseUri: ${{ parameters.HelixBaseUri }}
Creator: ${{ parameters.Creator }}
diff --git a/eng/common/templates-official/steps/source-build.yml b/eng/common/templates-official/steps/source-build.yml
index 9eb7e51456a..829f17c34d1 100644
--- a/eng/common/templates-official/steps/source-build.yml
+++ b/eng/common/templates-official/steps/source-build.yml
@@ -23,7 +23,7 @@ steps:
# In addition, add an msbuild argument to copy the WIP from the repo to the target build location.
# This is because SetupNuGetSources.sh will alter the current NuGet.config file, and we need to preserve those
# changes.
- $internalRestoreArgs=
+ internalRestoreArgs=
if [ '$(dn-bot-dnceng-artifact-feeds-rw)' != '$''(dn-bot-dnceng-artifact-feeds-rw)' ]; then
# Temporarily work around https://github.com/dotnet/arcade/issues/7709
chmod +x $(Build.SourcesDirectory)/eng/common/SetupNugetSources.sh
@@ -68,11 +68,21 @@ steps:
runtimeOsArgs='/p:RuntimeOS=${{ parameters.platform.runtimeOS }}'
fi
+ baseOsArgs=
+ if [ '${{ parameters.platform.baseOS }}' != '' ]; then
+ baseOsArgs='/p:BaseOS=${{ parameters.platform.baseOS }}'
+ fi
+
publishArgs=
if [ '${{ parameters.platform.skipPublishValidation }}' != 'true' ]; then
publishArgs='--publish'
fi
+ assetManifestFileName=SourceBuild_RidSpecific.xml
+ if [ '${{ parameters.platform.name }}' != '' ]; then
+ assetManifestFileName=SourceBuild_${{ parameters.platform.name }}.xml
+ fi
+
${{ coalesce(parameters.platform.buildScript, './build.sh') }} --ci \
--configuration $buildConfig \
--restore --build --pack $publishArgs -bl \
@@ -81,8 +91,10 @@ steps:
$internalRestoreArgs \
$targetRidArgs \
$runtimeOsArgs \
+ $baseOsArgs \
/p:SourceBuildNonPortable=${{ parameters.platform.nonPortable }} \
- /p:ArcadeBuildFromSource=true
+ /p:ArcadeBuildFromSource=true \
+ /p:AssetManifestFileName=$assetManifestFileName
displayName: Build
# Upload build logs for diagnosis.
@@ -106,3 +118,12 @@ steps:
artifactName: BuildLogs_SourceBuild_${{ parameters.platform.name }}_Attempt$(System.JobAttempt)
continueOnError: true
condition: succeededOrFailed()
+
+# Manually inject component detection so that we can ignore the source build upstream cache, which contains
+# a nupkg cache of input packages (a local feed).
+# This path must match the upstream cache path in property 'CurrentRepoSourceBuiltNupkgCacheDir'
+# in src\Microsoft.DotNet.Arcade.Sdk\tools\SourceBuild\SourceBuildArcade.targets
+- task: ComponentGovernanceComponentDetection@0
+ displayName: Component Detection (Exclude upstream cache)
+ inputs:
+ ignoreDirectories: '$(Build.SourcesDirectory)/artifacts/source-build/self/src/artifacts/obj/source-built-upstream-cache'
diff --git a/eng/common/templates-official/variables/pool-providers.yml b/eng/common/templates-official/variables/pool-providers.yml
new file mode 100644
index 00000000000..beab7d1bfba
--- /dev/null
+++ b/eng/common/templates-official/variables/pool-providers.yml
@@ -0,0 +1,45 @@
+# Select a pool provider based off branch name. Anything with branch name containing 'release' must go into an -Svc pool,
+# otherwise it should go into the "normal" pools. This separates out the queueing and billing of released branches.
+
+# Motivation:
+# Once a given branch of a repository's output has been officially "shipped" once, it is then considered to be COGS
+# (Cost of goods sold) and should be moved to a servicing pool provider. This allows both separation of queueing
+# (allowing release builds and main PR builds to not intefere with each other) and billing (required for COGS.
+# Additionally, the pool provider name itself may be subject to change when the .NET Core Engineering Services
+# team needs to move resources around and create new and potentially differently-named pools. Using this template
+# file from an Arcade-ified repo helps guard against both having to update one's release/* branches and renaming.
+
+# How to use:
+# This yaml assumes your shipped product branches use the naming convention "release/..." (which many do).
+# If we find alternate naming conventions in broad usage it can be added to the condition below.
+#
+# First, import the template in an arcade-ified repo to pick up the variables, e.g.:
+#
+# variables:
+# - template: /eng/common/templates-official/variables/pool-providers.yml
+#
+# ... then anywhere specifying the pool provider use the runtime variables,
+# $(DncEngInternalBuildPool)
+#
+# pool:
+# name: $(DncEngInternalBuildPool)
+# image: 1es-windows-2022-pt
+
+variables:
+ # Coalesce the target and source branches so we know when a PR targets a release branch
+ # If these variables are somehow missing, fall back to main (tends to have more capacity)
+
+ # Any new -Svc alternative pools should have variables added here to allow for splitting work
+
+ - name: DncEngInternalBuildPool
+ value: $[
+ replace(
+ replace(
+ eq(contains(coalesce(variables['System.PullRequest.TargetBranch'], variables['Build.SourceBranch'], 'refs/heads/main'), 'release'), 'true'),
+ True,
+ 'NetCore1ESPool-Svc-Internal'
+ ),
+ False,
+ 'NetCore1ESPool-Internal'
+ )
+ ]
\ No newline at end of file
diff --git a/eng/common/templates-official/variables/sdl-variables.yml b/eng/common/templates-official/variables/sdl-variables.yml
index 1a860bd0406..dbdd66d4a4b 100644
--- a/eng/common/templates-official/variables/sdl-variables.yml
+++ b/eng/common/templates-official/variables/sdl-variables.yml
@@ -2,6 +2,6 @@ variables:
# The Guardian version specified in 'eng/common/sdl/packages.config'. This value must be kept in
# sync with the packages.config file.
- name: DefaultGuardianVersion
- value: 0.110.1
+ value: 0.109.0
- name: GuardianPackagesConfigFile
value: $(Build.SourcesDirectory)\eng\common\sdl\packages.config
\ No newline at end of file
diff --git a/eng/common/templates/job/job.yml b/eng/common/templates/job/job.yml
index e24ca2f46f9..8ec5c4f2d9f 100644
--- a/eng/common/templates/job/job.yml
+++ b/eng/common/templates/job/job.yml
@@ -15,6 +15,7 @@ parameters:
timeoutInMinutes: ''
variables: []
workspace: ''
+ templateContext: ''
# Job base template specific parameters
# See schema documentation - https://github.com/dotnet/arcade/blob/master/Documentation/AzureDevOps/TemplateSchema.md
@@ -68,6 +69,9 @@ jobs:
${{ if ne(parameters.timeoutInMinutes, '') }}:
timeoutInMinutes: ${{ parameters.timeoutInMinutes }}
+ ${{ if ne(parameters.templateContext, '') }}:
+ templateContext: ${{ parameters.templateContext }}
+
variables:
- ${{ if ne(parameters.enableTelemetry, 'false') }}:
- name: DOTNET_CLI_TELEMETRY_PROFILE
diff --git a/eng/common/templates/job/publish-build-assets.yml b/eng/common/templates/job/publish-build-assets.yml
index abc91c7e8c2..8ec0151def2 100644
--- a/eng/common/templates/job/publish-build-assets.yml
+++ b/eng/common/templates/job/publish-build-assets.yml
@@ -86,7 +86,7 @@ jobs:
/p:OfficialBuildId=$(Build.BuildNumber)
condition: ${{ parameters.condition }}
continueOnError: ${{ parameters.continueOnError }}
-
+
- task: powershell@2
displayName: Create ReleaseConfigs Artifact
inputs:
@@ -95,7 +95,7 @@ jobs:
Add-Content -Path "$(Build.StagingDirectory)/ReleaseConfigs.txt" -Value $(BARBuildId)
Add-Content -Path "$(Build.StagingDirectory)/ReleaseConfigs.txt" -Value "$(DefaultChannels)"
Add-Content -Path "$(Build.StagingDirectory)/ReleaseConfigs.txt" -Value $(IsStableBuild)
-
+
- task: PublishBuildArtifacts@1
displayName: Publish ReleaseConfigs Artifact
inputs:
@@ -121,7 +121,7 @@ jobs:
- task: PublishBuildArtifacts@1
displayName: Publish SymbolPublishingExclusionsFile Artifact
- condition: eq(variables['SymbolExclusionFile'], 'true')
+ condition: eq(variables['SymbolExclusionFile'], 'true')
inputs:
PathtoPublish: '$(Build.SourcesDirectory)/eng/SymbolPublishingExclusionsFile.txt'
PublishLocation: Container
@@ -148,4 +148,4 @@ jobs:
- ${{ if eq(parameters.enablePublishBuildArtifacts, 'true') }}:
- template: /eng/common/templates/steps/publish-logs.yml
parameters:
- JobLabel: 'Publish_Artifacts_Logs'
+ JobLabel: 'Publish_Artifacts_Logs'
diff --git a/eng/common/templates/post-build/post-build.yml b/eng/common/templates/post-build/post-build.yml
index d173341412a..aba44a25a33 100644
--- a/eng/common/templates/post-build/post-build.yml
+++ b/eng/common/templates/post-build/post-build.yml
@@ -39,7 +39,7 @@ parameters:
displayName: Enable NuGet validation
type: boolean
default: true
-
+
- name: publishInstallersAndChecksums
displayName: Publish installers and checksums
type: boolean
@@ -131,8 +131,8 @@ stages:
displayName: Validate
inputs:
filePath: $(Build.SourcesDirectory)/eng/common/post-build/nuget-validation.ps1
- arguments: -PackagesPath $(Build.ArtifactStagingDirectory)/PackageArtifacts/
- -ToolDestinationPath $(Agent.BuildDirectory)/Extract/
+ arguments: -PackagesPath $(Build.ArtifactStagingDirectory)/PackageArtifacts/
+ -ToolDestinationPath $(Agent.BuildDirectory)/Extract/
- job:
displayName: Signing Validation
@@ -221,9 +221,9 @@ stages:
displayName: Validate
inputs:
filePath: $(Build.SourcesDirectory)/eng/common/post-build/sourcelink-validation.ps1
- arguments: -InputPath $(Build.ArtifactStagingDirectory)/BlobArtifacts/
- -ExtractPath $(Agent.BuildDirectory)/Extract/
- -GHRepoName $(Build.Repository.Name)
+ arguments: -InputPath $(Build.ArtifactStagingDirectory)/BlobArtifacts/
+ -ExtractPath $(Agent.BuildDirectory)/Extract/
+ -GHRepoName $(Build.Repository.Name)
-GHCommit $(Build.SourceVersion)
-SourcelinkCliVersion $(SourceLinkCLIVersion)
continueOnError: true
diff --git a/eng/common/templates/steps/generate-sbom.yml b/eng/common/templates/steps/generate-sbom.yml
index a06373f38fa..2b21eae4273 100644
--- a/eng/common/templates/steps/generate-sbom.yml
+++ b/eng/common/templates/steps/generate-sbom.yml
@@ -5,7 +5,7 @@
# IgnoreDirectories - Directories to ignore for SBOM generation. This will be passed through to the CG component detector.
parameters:
- PackageVersion: 7.0.0
+ PackageVersion: 8.0.0
BuildDropPath: '$(Build.SourcesDirectory)/artifacts'
PackageName: '.NET'
ManifestDirPath: $(Build.ArtifactStagingDirectory)/sbom
diff --git a/global.json b/global.json
index 29f1d538878..bd1f68c7529 100644
--- a/global.json
+++ b/global.json
@@ -13,7 +13,7 @@
}
},
"msbuild-sdks": {
- "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.24113.2",
- "Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.24113.2"
+ "Microsoft.DotNet.Arcade.Sdk": "8.0.0-beta.24165.4",
+ "Microsoft.DotNet.Helix.Sdk": "8.0.0-beta.24165.4"
}
}
From fe96e268533a5788f986e0600046846676c0add6 Mon Sep 17 00:00:00 2001
From: DotNet-Bot
Date: Tue, 19 Mar 2024 00:03:09 +0000
Subject: [PATCH 21/22] Update dependencies from
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime build
Microsoft.Extensions.HostFactoryResolver.Sources , Microsoft.NETCore.App.Ref , Microsoft.NETCore.App.Runtime.win-x64 , Microsoft.NETCore.BrowserDebugHost.Transport
From Version 8.0.4-servicing.24163.26 -> To Version 8.0.4-servicing.24168.10
---
NuGet.config | 10 ++--------
eng/Version.Details.xml | 12 ++++++------
eng/Versions.props | 4 ++--
3 files changed, 10 insertions(+), 16 deletions(-)
diff --git a/NuGet.config b/NuGet.config
index 5dc7c38899e..b89b63e213a 100644
--- a/NuGet.config
+++ b/NuGet.config
@@ -4,10 +4,7 @@
-
-
-
-
+
@@ -22,10 +19,7 @@
-
-
-
-
+
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index 7b2bf613fc9..737f0087dd9 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -29,9 +29,9 @@
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
5535e31a712343a63f5d7d796cd874e563e5ac14
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 38f2042434044be9a09065b23b7ef342a313a498
+ a1a9440b48374c6d400287abbb56a4ac54d9b02f
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
@@ -43,16 +43,16 @@
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 38f2042434044be9a09065b23b7ef342a313a498
+ a1a9440b48374c6d400287abbb56a4ac54d9b02f
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 38f2042434044be9a09065b23b7ef342a313a498
+ a1a9440b48374c6d400287abbb56a4ac54d9b02f
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- 38f2042434044be9a09065b23b7ef342a313a498
+ a1a9440b48374c6d400287abbb56a4ac54d9b02f
diff --git a/eng/Versions.props b/eng/Versions.props
index 92244d67cd8..bcdefc4bf31 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -24,12 +24,12 @@
8.0.0
8.0.0
8.0.0
- 8.0.4-servicing.24163.26
+ 8.0.4-servicing.24168.10
8.0.0
8.0.3
8.0.4
8.0.4
- 8.0.4-servicing.24163.26
+ 8.0.4-servicing.24168.10
8.0.0-beta.24165.4
From c49b051728a7af94b11b4e8d644d4efa5465ff62 Mon Sep 17 00:00:00 2001
From: DotNet-Bot
Date: Tue, 19 Mar 2024 23:19:07 +0000
Subject: [PATCH 22/22] Update dependencies from
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime build
Microsoft.Extensions.HostFactoryResolver.Sources , Microsoft.NETCore.App.Ref , Microsoft.NETCore.App.Runtime.win-x64 , Microsoft.NETCore.BrowserDebugHost.Transport
From Version 8.0.4-servicing.24168.10 -> To Version 8.0.4-servicing.24169.9
---
NuGet.config | 4 ++--
eng/Version.Details.xml | 12 ++++++------
eng/Versions.props | 4 ++--
3 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/NuGet.config b/NuGet.config
index b89b63e213a..a86e73bfa95 100644
--- a/NuGet.config
+++ b/NuGet.config
@@ -4,7 +4,7 @@
-
+
@@ -19,7 +19,7 @@
-
+
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index 737f0087dd9..6a9637e4386 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -29,9 +29,9 @@
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
5535e31a712343a63f5d7d796cd874e563e5ac14
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- a1a9440b48374c6d400287abbb56a4ac54d9b02f
+ 2d7eea252964e69be94cb9c847b371b23e4dd470
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
@@ -43,16 +43,16 @@
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- a1a9440b48374c6d400287abbb56a4ac54d9b02f
+ 2d7eea252964e69be94cb9c847b371b23e4dd470
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- a1a9440b48374c6d400287abbb56a4ac54d9b02f
+ 2d7eea252964e69be94cb9c847b371b23e4dd470
-
+
https://dev.azure.com/dnceng/internal/_git/dotnet-runtime
- a1a9440b48374c6d400287abbb56a4ac54d9b02f
+ 2d7eea252964e69be94cb9c847b371b23e4dd470
diff --git a/eng/Versions.props b/eng/Versions.props
index bcdefc4bf31..b924af1b8e3 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -24,12 +24,12 @@
8.0.0
8.0.0
8.0.0
- 8.0.4-servicing.24168.10
+ 8.0.4-servicing.24169.9
8.0.0
8.0.3
8.0.4
8.0.4
- 8.0.4-servicing.24168.10
+ 8.0.4-servicing.24169.9
8.0.0-beta.24165.4