diff --git a/.gitignore b/.gitignore index 615ee80..1fd9da6 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,16 @@ docs/_site coverage.cobertura.xml pkg/ artifacts/ -*.bak \ No newline at end of file +*.bak +tmpclaude-* +tests/**/TestResults/ + +# Auto-generated SQL files in samples +# These are generated during build and should not be tracked +samples/**/DatabaseProject/**/Tables/*.sql +samples/**/DatabaseProject/**/Views/*.sql +samples/**/DatabaseProject/**/StoredProcedures/*.sql +samples/**/DatabaseProject/**/*.sql +!samples/**/DatabaseProject/**/*.sqlproj +!samples/**/DatabaseProject/**/*.csproj +packages/ diff --git a/JD.Efcpt.Build.sln b/JD.Efcpt.Build.sln index 1a2c7f2..7e06a0c 100644 --- a/JD.Efcpt.Build.sln +++ b/JD.Efcpt.Build.sln @@ -1,3 +1,4 @@ + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.0.31903.59 diff --git a/samples/NuGet.config b/samples/NuGet.config new file mode 100644 index 0000000..03e648e --- /dev/null +++ b/samples/NuGet.config @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/samples/Samples.sln b/samples/Samples.sln new file mode 100644 index 0000000..33dcab7 --- /dev/null +++ b/samples/Samples.sln @@ -0,0 +1,406 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "aspnet-core-appsettings", "aspnet-core-appsettings", "{1F87798A-3DA2-1D52-37E6-92287F21560B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspNetCoreAppSettings.AppHost", "aspnet-core-appsettings\AspNetCoreAppSettings.AppHost\AspNetCoreAppSettings.AppHost.csproj", "{50C548F6-BD90-44B2-939B-88E157BC1D77}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyApp.Api", "aspnet-core-appsettings\MyApp.Api\MyApp.Api.csproj", "{B6093DDC-14AF-4A21-989B-3AC63B89ACB0}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "connection-string-mssql", "connection-string-mssql", "{8FE76333-615D-4D0B-08EF-9ACA145B22E5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConnectionStringMssql.AppHost", "connection-string-mssql\ConnectionStringMssql.AppHost\ConnectionStringMssql.AppHost.csproj", "{2809E8F4-B766-4D9D-B514-DEB85D974F5C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EntityFrameworkCoreProject", "connection-string-mssql\EntityFrameworkCoreProject\EntityFrameworkCoreProject.csproj", "{1ADB10A5-ABA0-430F-88EB-10D2F2A379FC}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "connection-string-sqlite", "connection-string-sqlite", "{F300D630-7571-566C-DE3A-0237458CBD19}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EntityFrameworkCoreProject", "connection-string-sqlite\EntityFrameworkCoreProject\EntityFrameworkCoreProject.csproj", "{D0DE0C4D-8901-4FBD-A78C-B11D1B4675B4}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "custom-renaming", "custom-renaming", "{10305151-72DA-BBBB-C817-BD890FA250F2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EntityFrameworkCoreProject", "custom-renaming\EntityFrameworkCoreProject\EntityFrameworkCoreProject.csproj", "{C7F9A6FC-67C8-4E44-B1CF-671A1315156D}" +EndProject +Project("{00D1A9C2-B5F0-4AF3-8072-F6C62B433612}") = "DatabaseProject", "custom-renaming\DatabaseProject\DatabaseProject.sqlproj", "{F00C8951-341A-4738-A289-33504D2906D5}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dacpac-zero-config", "dacpac-zero-config", "{CA0ABCE0-AAC8-D42B-D483-0AD6CB9ED44A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EntityFrameworkCoreProject", "dacpac-zero-config\EntityFrameworkCoreProject\EntityFrameworkCoreProject.csproj", "{D098CDA1-D567-45E4-8C0E-53DFBA25EE22}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "database-first-sql-generation", "database-first-sql-generation", "{46A6B6E4-1F62-AC21-FF7F-BCB260772A08}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataAccessProject", "database-first-sql-generation\DataAccessProject\DataAccessProject.csproj", "{E9BECDF9-5270-4E67-8B53-918DB5414427}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DatabaseProject", "database-first-sql-generation\DatabaseProject\DatabaseProject.csproj", "{FB8CDB1A-1DE0-488F-943A-115DE375344F}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "microsoft-build-sql-zero-config", "microsoft-build-sql-zero-config", "{D19774F8-5390-DECA-0D5D-DB3D3B1934CC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DatabaseProject", "microsoft-build-sql-zero-config\DatabaseProject\DatabaseProject.csproj", "{0756435B-A795-4CC3-BA73-E2AB0F436F39}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EntityFrameworkCoreProject", "microsoft-build-sql-zero-config\EntityFrameworkCoreProject\EntityFrameworkCoreProject.csproj", "{F03B61E0-1EB5-4ECB-8E43-1ED6A31E7665}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "msbuild-sdk-sql-proj-generation", "msbuild-sdk-sql-proj-generation", "{0FBFF59C-0FC2-5776-A3F6-C46E2EF347EC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DatabaseProject", "msbuild-sdk-sql-proj-generation\DatabaseProject\DatabaseProject.csproj", "{DA0491F2-641D-4E6D-9B97-DC465C1CCE33}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EntityFrameworkCoreProject", "msbuild-sdk-sql-proj-generation\EntityFrameworkCoreProject\EntityFrameworkCoreProject.csproj", "{DF6874DC-C650-43B5-AB7E-55CA87F7C515}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "schema-organization", "schema-organization", "{EBF3C506-8F29-9654-7600-23BD3F25C924}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EntityFrameworkCoreProject", "schema-organization\EntityFrameworkCoreProject\EntityFrameworkCoreProject.csproj", "{311609F6-420D-4B05-8E66-B1B084C45D19}" +EndProject +Project("{00D1A9C2-B5F0-4AF3-8072-F6C62B433612}") = "DatabaseProject", "schema-organization\DatabaseProject\DatabaseProject.sqlproj", "{433E6F74-5C51-43A5-A92C-C90D8DEB0D98}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "sdk-zero-config", "sdk-zero-config", "{1B681BF4-A602-D408-2E69-2B57B87575B2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DatabaseProject", "sdk-zero-config\DatabaseProject\DatabaseProject.csproj", "{7973CB94-3824-48AD-816E-CD9EBF217B3A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EntityFrameworkCoreProject", "sdk-zero-config\EntityFrameworkCoreProject\EntityFrameworkCoreProject.csproj", "{E283EB20-A10D-482B-8320-93AFC70C36A8}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "simple-generation", "simple-generation", "{533FC926-FE64-7363-FF68-925D042523EE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EntityFrameworkCoreProject", "simple-generation\EntityFrameworkCoreProject\EntityFrameworkCoreProject.csproj", "{C4A32153-A694-401F-B54A-38F7642D24D9}" +EndProject +Project("{00D1A9C2-B5F0-4AF3-8072-F6C62B433612}") = "DatabaseProject", "simple-generation\DatabaseProject\DatabaseProject.sqlproj", "{9F527768-04B3-4DED-89B7-0D0A8DA59DB9}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "simple-sql-integration", "simple-sql-integration", "{992222C4-ADE0-6BF1-7230-A9C65755AE09}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataAccessProject", "simple-sql-integration\DataAccessProject\DataAccessProject.csproj", "{E8265A69-7C88-4728-ACD2-710A5F7C0E3A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DatabaseProject", "simple-sql-integration\DatabaseProject\DatabaseProject.csproj", "{1B282238-83D7-4FBD-BE3C-180A82253543}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "split-data-and-models-between-multiple-projects", "split-data-and-models-between-multiple-projects", "{DAF4ADBB-250D-0A80-76AC-796D3C9CD4A9}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{986A884E-2D1F-75CC-48B5-B2716C96E4D3}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SampleApp.Data", "split-data-and-models-between-multiple-projects\src\SampleApp.Data\SampleApp.Data.csproj", "{6C744129-0A51-4110-93E4-FCD652680C21}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SampleApp.Models", "split-data-and-models-between-multiple-projects\src\SampleApp.Models\SampleApp.Models.csproj", "{E57FA06A-5CAA-4911-85C5-25A9F0C7E97C}" +EndProject +Project("{00D1A9C2-B5F0-4AF3-8072-F6C62B433612}") = "SampleApp.Sql", "split-data-and-models-between-multiple-projects\src\SampleApp.Sql\SampleApp.Sql.sqlproj", "{8F4BE58C-4C65-4960-9BD4-F785F1AD6EB1}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "_build", "build\_build.csproj", "{A9E02FAB-D5FA-4381-9BC9-F3BA8C9AF559}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A9E02FAB-D5FA-4381-9BC9-F3BA8C9AF559}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A9E02FAB-D5FA-4381-9BC9-F3BA8C9AF559}.Release|Any CPU.ActiveCfg = Release|Any CPU + {50C548F6-BD90-44B2-939B-88E157BC1D77}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {50C548F6-BD90-44B2-939B-88E157BC1D77}.Debug|Any CPU.Build.0 = Debug|Any CPU + {50C548F6-BD90-44B2-939B-88E157BC1D77}.Debug|x64.ActiveCfg = Debug|Any CPU + {50C548F6-BD90-44B2-939B-88E157BC1D77}.Debug|x64.Build.0 = Debug|Any CPU + {50C548F6-BD90-44B2-939B-88E157BC1D77}.Debug|x86.ActiveCfg = Debug|Any CPU + {50C548F6-BD90-44B2-939B-88E157BC1D77}.Debug|x86.Build.0 = Debug|Any CPU + {50C548F6-BD90-44B2-939B-88E157BC1D77}.Release|Any CPU.ActiveCfg = Release|Any CPU + {50C548F6-BD90-44B2-939B-88E157BC1D77}.Release|Any CPU.Build.0 = Release|Any CPU + {50C548F6-BD90-44B2-939B-88E157BC1D77}.Release|x64.ActiveCfg = Release|Any CPU + {50C548F6-BD90-44B2-939B-88E157BC1D77}.Release|x64.Build.0 = Release|Any CPU + {50C548F6-BD90-44B2-939B-88E157BC1D77}.Release|x86.ActiveCfg = Release|Any CPU + {50C548F6-BD90-44B2-939B-88E157BC1D77}.Release|x86.Build.0 = Release|Any CPU + {B6093DDC-14AF-4A21-989B-3AC63B89ACB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B6093DDC-14AF-4A21-989B-3AC63B89ACB0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B6093DDC-14AF-4A21-989B-3AC63B89ACB0}.Debug|x64.ActiveCfg = Debug|Any CPU + {B6093DDC-14AF-4A21-989B-3AC63B89ACB0}.Debug|x64.Build.0 = Debug|Any CPU + {B6093DDC-14AF-4A21-989B-3AC63B89ACB0}.Debug|x86.ActiveCfg = Debug|Any CPU + {B6093DDC-14AF-4A21-989B-3AC63B89ACB0}.Debug|x86.Build.0 = Debug|Any CPU + {B6093DDC-14AF-4A21-989B-3AC63B89ACB0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B6093DDC-14AF-4A21-989B-3AC63B89ACB0}.Release|Any CPU.Build.0 = Release|Any CPU + {B6093DDC-14AF-4A21-989B-3AC63B89ACB0}.Release|x64.ActiveCfg = Release|Any CPU + {B6093DDC-14AF-4A21-989B-3AC63B89ACB0}.Release|x64.Build.0 = Release|Any CPU + {B6093DDC-14AF-4A21-989B-3AC63B89ACB0}.Release|x86.ActiveCfg = Release|Any CPU + {B6093DDC-14AF-4A21-989B-3AC63B89ACB0}.Release|x86.Build.0 = Release|Any CPU + {2809E8F4-B766-4D9D-B514-DEB85D974F5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2809E8F4-B766-4D9D-B514-DEB85D974F5C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2809E8F4-B766-4D9D-B514-DEB85D974F5C}.Debug|x64.ActiveCfg = Debug|Any CPU + {2809E8F4-B766-4D9D-B514-DEB85D974F5C}.Debug|x64.Build.0 = Debug|Any CPU + {2809E8F4-B766-4D9D-B514-DEB85D974F5C}.Debug|x86.ActiveCfg = Debug|Any CPU + {2809E8F4-B766-4D9D-B514-DEB85D974F5C}.Debug|x86.Build.0 = Debug|Any CPU + {2809E8F4-B766-4D9D-B514-DEB85D974F5C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2809E8F4-B766-4D9D-B514-DEB85D974F5C}.Release|Any CPU.Build.0 = Release|Any CPU + {2809E8F4-B766-4D9D-B514-DEB85D974F5C}.Release|x64.ActiveCfg = Release|Any CPU + {2809E8F4-B766-4D9D-B514-DEB85D974F5C}.Release|x64.Build.0 = Release|Any CPU + {2809E8F4-B766-4D9D-B514-DEB85D974F5C}.Release|x86.ActiveCfg = Release|Any CPU + {2809E8F4-B766-4D9D-B514-DEB85D974F5C}.Release|x86.Build.0 = Release|Any CPU + {1ADB10A5-ABA0-430F-88EB-10D2F2A379FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1ADB10A5-ABA0-430F-88EB-10D2F2A379FC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1ADB10A5-ABA0-430F-88EB-10D2F2A379FC}.Debug|x64.ActiveCfg = Debug|Any CPU + {1ADB10A5-ABA0-430F-88EB-10D2F2A379FC}.Debug|x64.Build.0 = Debug|Any CPU + {1ADB10A5-ABA0-430F-88EB-10D2F2A379FC}.Debug|x86.ActiveCfg = Debug|Any CPU + {1ADB10A5-ABA0-430F-88EB-10D2F2A379FC}.Debug|x86.Build.0 = Debug|Any CPU + {1ADB10A5-ABA0-430F-88EB-10D2F2A379FC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1ADB10A5-ABA0-430F-88EB-10D2F2A379FC}.Release|Any CPU.Build.0 = Release|Any CPU + {1ADB10A5-ABA0-430F-88EB-10D2F2A379FC}.Release|x64.ActiveCfg = Release|Any CPU + {1ADB10A5-ABA0-430F-88EB-10D2F2A379FC}.Release|x64.Build.0 = Release|Any CPU + {1ADB10A5-ABA0-430F-88EB-10D2F2A379FC}.Release|x86.ActiveCfg = Release|Any CPU + {1ADB10A5-ABA0-430F-88EB-10D2F2A379FC}.Release|x86.Build.0 = Release|Any CPU + {D0DE0C4D-8901-4FBD-A78C-B11D1B4675B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D0DE0C4D-8901-4FBD-A78C-B11D1B4675B4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D0DE0C4D-8901-4FBD-A78C-B11D1B4675B4}.Debug|x64.ActiveCfg = Debug|Any CPU + {D0DE0C4D-8901-4FBD-A78C-B11D1B4675B4}.Debug|x64.Build.0 = Debug|Any CPU + {D0DE0C4D-8901-4FBD-A78C-B11D1B4675B4}.Debug|x86.ActiveCfg = Debug|Any CPU + {D0DE0C4D-8901-4FBD-A78C-B11D1B4675B4}.Debug|x86.Build.0 = Debug|Any CPU + {D0DE0C4D-8901-4FBD-A78C-B11D1B4675B4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D0DE0C4D-8901-4FBD-A78C-B11D1B4675B4}.Release|Any CPU.Build.0 = Release|Any CPU + {D0DE0C4D-8901-4FBD-A78C-B11D1B4675B4}.Release|x64.ActiveCfg = Release|Any CPU + {D0DE0C4D-8901-4FBD-A78C-B11D1B4675B4}.Release|x64.Build.0 = Release|Any CPU + {D0DE0C4D-8901-4FBD-A78C-B11D1B4675B4}.Release|x86.ActiveCfg = Release|Any CPU + {D0DE0C4D-8901-4FBD-A78C-B11D1B4675B4}.Release|x86.Build.0 = Release|Any CPU + {C7F9A6FC-67C8-4E44-B1CF-671A1315156D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C7F9A6FC-67C8-4E44-B1CF-671A1315156D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C7F9A6FC-67C8-4E44-B1CF-671A1315156D}.Debug|x64.ActiveCfg = Debug|Any CPU + {C7F9A6FC-67C8-4E44-B1CF-671A1315156D}.Debug|x64.Build.0 = Debug|Any CPU + {C7F9A6FC-67C8-4E44-B1CF-671A1315156D}.Debug|x86.ActiveCfg = Debug|Any CPU + {C7F9A6FC-67C8-4E44-B1CF-671A1315156D}.Debug|x86.Build.0 = Debug|Any CPU + {C7F9A6FC-67C8-4E44-B1CF-671A1315156D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C7F9A6FC-67C8-4E44-B1CF-671A1315156D}.Release|Any CPU.Build.0 = Release|Any CPU + {C7F9A6FC-67C8-4E44-B1CF-671A1315156D}.Release|x64.ActiveCfg = Release|Any CPU + {C7F9A6FC-67C8-4E44-B1CF-671A1315156D}.Release|x64.Build.0 = Release|Any CPU + {C7F9A6FC-67C8-4E44-B1CF-671A1315156D}.Release|x86.ActiveCfg = Release|Any CPU + {C7F9A6FC-67C8-4E44-B1CF-671A1315156D}.Release|x86.Build.0 = Release|Any CPU + {F00C8951-341A-4738-A289-33504D2906D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F00C8951-341A-4738-A289-33504D2906D5}.Debug|x64.ActiveCfg = Debug|Any CPU + {F00C8951-341A-4738-A289-33504D2906D5}.Debug|x86.ActiveCfg = Debug|Any CPU + {F00C8951-341A-4738-A289-33504D2906D5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F00C8951-341A-4738-A289-33504D2906D5}.Release|x64.ActiveCfg = Release|Any CPU + {F00C8951-341A-4738-A289-33504D2906D5}.Release|x86.ActiveCfg = Release|Any CPU + {D098CDA1-D567-45E4-8C0E-53DFBA25EE22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D098CDA1-D567-45E4-8C0E-53DFBA25EE22}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D098CDA1-D567-45E4-8C0E-53DFBA25EE22}.Debug|x64.ActiveCfg = Debug|Any CPU + {D098CDA1-D567-45E4-8C0E-53DFBA25EE22}.Debug|x64.Build.0 = Debug|Any CPU + {D098CDA1-D567-45E4-8C0E-53DFBA25EE22}.Debug|x86.ActiveCfg = Debug|Any CPU + {D098CDA1-D567-45E4-8C0E-53DFBA25EE22}.Debug|x86.Build.0 = Debug|Any CPU + {D098CDA1-D567-45E4-8C0E-53DFBA25EE22}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D098CDA1-D567-45E4-8C0E-53DFBA25EE22}.Release|Any CPU.Build.0 = Release|Any CPU + {D098CDA1-D567-45E4-8C0E-53DFBA25EE22}.Release|x64.ActiveCfg = Release|Any CPU + {D098CDA1-D567-45E4-8C0E-53DFBA25EE22}.Release|x64.Build.0 = Release|Any CPU + {D098CDA1-D567-45E4-8C0E-53DFBA25EE22}.Release|x86.ActiveCfg = Release|Any CPU + {D098CDA1-D567-45E4-8C0E-53DFBA25EE22}.Release|x86.Build.0 = Release|Any CPU + {E9BECDF9-5270-4E67-8B53-918DB5414427}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E9BECDF9-5270-4E67-8B53-918DB5414427}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E9BECDF9-5270-4E67-8B53-918DB5414427}.Debug|x64.ActiveCfg = Debug|Any CPU + {E9BECDF9-5270-4E67-8B53-918DB5414427}.Debug|x64.Build.0 = Debug|Any CPU + {E9BECDF9-5270-4E67-8B53-918DB5414427}.Debug|x86.ActiveCfg = Debug|Any CPU + {E9BECDF9-5270-4E67-8B53-918DB5414427}.Debug|x86.Build.0 = Debug|Any CPU + {E9BECDF9-5270-4E67-8B53-918DB5414427}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E9BECDF9-5270-4E67-8B53-918DB5414427}.Release|Any CPU.Build.0 = Release|Any CPU + {E9BECDF9-5270-4E67-8B53-918DB5414427}.Release|x64.ActiveCfg = Release|Any CPU + {E9BECDF9-5270-4E67-8B53-918DB5414427}.Release|x64.Build.0 = Release|Any CPU + {E9BECDF9-5270-4E67-8B53-918DB5414427}.Release|x86.ActiveCfg = Release|Any CPU + {E9BECDF9-5270-4E67-8B53-918DB5414427}.Release|x86.Build.0 = Release|Any CPU + {FB8CDB1A-1DE0-488F-943A-115DE375344F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FB8CDB1A-1DE0-488F-943A-115DE375344F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FB8CDB1A-1DE0-488F-943A-115DE375344F}.Debug|x64.ActiveCfg = Debug|Any CPU + {FB8CDB1A-1DE0-488F-943A-115DE375344F}.Debug|x64.Build.0 = Debug|Any CPU + {FB8CDB1A-1DE0-488F-943A-115DE375344F}.Debug|x86.ActiveCfg = Debug|Any CPU + {FB8CDB1A-1DE0-488F-943A-115DE375344F}.Debug|x86.Build.0 = Debug|Any CPU + {FB8CDB1A-1DE0-488F-943A-115DE375344F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FB8CDB1A-1DE0-488F-943A-115DE375344F}.Release|Any CPU.Build.0 = Release|Any CPU + {FB8CDB1A-1DE0-488F-943A-115DE375344F}.Release|x64.ActiveCfg = Release|Any CPU + {FB8CDB1A-1DE0-488F-943A-115DE375344F}.Release|x64.Build.0 = Release|Any CPU + {FB8CDB1A-1DE0-488F-943A-115DE375344F}.Release|x86.ActiveCfg = Release|Any CPU + {FB8CDB1A-1DE0-488F-943A-115DE375344F}.Release|x86.Build.0 = Release|Any CPU + {0756435B-A795-4CC3-BA73-E2AB0F436F39}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0756435B-A795-4CC3-BA73-E2AB0F436F39}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0756435B-A795-4CC3-BA73-E2AB0F436F39}.Debug|x64.ActiveCfg = Debug|Any CPU + {0756435B-A795-4CC3-BA73-E2AB0F436F39}.Debug|x64.Build.0 = Debug|Any CPU + {0756435B-A795-4CC3-BA73-E2AB0F436F39}.Debug|x86.ActiveCfg = Debug|Any CPU + {0756435B-A795-4CC3-BA73-E2AB0F436F39}.Debug|x86.Build.0 = Debug|Any CPU + {0756435B-A795-4CC3-BA73-E2AB0F436F39}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0756435B-A795-4CC3-BA73-E2AB0F436F39}.Release|Any CPU.Build.0 = Release|Any CPU + {0756435B-A795-4CC3-BA73-E2AB0F436F39}.Release|x64.ActiveCfg = Release|Any CPU + {0756435B-A795-4CC3-BA73-E2AB0F436F39}.Release|x64.Build.0 = Release|Any CPU + {0756435B-A795-4CC3-BA73-E2AB0F436F39}.Release|x86.ActiveCfg = Release|Any CPU + {0756435B-A795-4CC3-BA73-E2AB0F436F39}.Release|x86.Build.0 = Release|Any CPU + {F03B61E0-1EB5-4ECB-8E43-1ED6A31E7665}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F03B61E0-1EB5-4ECB-8E43-1ED6A31E7665}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F03B61E0-1EB5-4ECB-8E43-1ED6A31E7665}.Debug|x64.ActiveCfg = Debug|Any CPU + {F03B61E0-1EB5-4ECB-8E43-1ED6A31E7665}.Debug|x64.Build.0 = Debug|Any CPU + {F03B61E0-1EB5-4ECB-8E43-1ED6A31E7665}.Debug|x86.ActiveCfg = Debug|Any CPU + {F03B61E0-1EB5-4ECB-8E43-1ED6A31E7665}.Debug|x86.Build.0 = Debug|Any CPU + {F03B61E0-1EB5-4ECB-8E43-1ED6A31E7665}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F03B61E0-1EB5-4ECB-8E43-1ED6A31E7665}.Release|Any CPU.Build.0 = Release|Any CPU + {F03B61E0-1EB5-4ECB-8E43-1ED6A31E7665}.Release|x64.ActiveCfg = Release|Any CPU + {F03B61E0-1EB5-4ECB-8E43-1ED6A31E7665}.Release|x64.Build.0 = Release|Any CPU + {F03B61E0-1EB5-4ECB-8E43-1ED6A31E7665}.Release|x86.ActiveCfg = Release|Any CPU + {F03B61E0-1EB5-4ECB-8E43-1ED6A31E7665}.Release|x86.Build.0 = Release|Any CPU + {DA0491F2-641D-4E6D-9B97-DC465C1CCE33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DA0491F2-641D-4E6D-9B97-DC465C1CCE33}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DA0491F2-641D-4E6D-9B97-DC465C1CCE33}.Debug|x64.ActiveCfg = Debug|Any CPU + {DA0491F2-641D-4E6D-9B97-DC465C1CCE33}.Debug|x64.Build.0 = Debug|Any CPU + {DA0491F2-641D-4E6D-9B97-DC465C1CCE33}.Debug|x86.ActiveCfg = Debug|Any CPU + {DA0491F2-641D-4E6D-9B97-DC465C1CCE33}.Debug|x86.Build.0 = Debug|Any CPU + {DA0491F2-641D-4E6D-9B97-DC465C1CCE33}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DA0491F2-641D-4E6D-9B97-DC465C1CCE33}.Release|Any CPU.Build.0 = Release|Any CPU + {DA0491F2-641D-4E6D-9B97-DC465C1CCE33}.Release|x64.ActiveCfg = Release|Any CPU + {DA0491F2-641D-4E6D-9B97-DC465C1CCE33}.Release|x64.Build.0 = Release|Any CPU + {DA0491F2-641D-4E6D-9B97-DC465C1CCE33}.Release|x86.ActiveCfg = Release|Any CPU + {DA0491F2-641D-4E6D-9B97-DC465C1CCE33}.Release|x86.Build.0 = Release|Any CPU + {DF6874DC-C650-43B5-AB7E-55CA87F7C515}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DF6874DC-C650-43B5-AB7E-55CA87F7C515}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DF6874DC-C650-43B5-AB7E-55CA87F7C515}.Debug|x64.ActiveCfg = Debug|Any CPU + {DF6874DC-C650-43B5-AB7E-55CA87F7C515}.Debug|x64.Build.0 = Debug|Any CPU + {DF6874DC-C650-43B5-AB7E-55CA87F7C515}.Debug|x86.ActiveCfg = Debug|Any CPU + {DF6874DC-C650-43B5-AB7E-55CA87F7C515}.Debug|x86.Build.0 = Debug|Any CPU + {DF6874DC-C650-43B5-AB7E-55CA87F7C515}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DF6874DC-C650-43B5-AB7E-55CA87F7C515}.Release|Any CPU.Build.0 = Release|Any CPU + {DF6874DC-C650-43B5-AB7E-55CA87F7C515}.Release|x64.ActiveCfg = Release|Any CPU + {DF6874DC-C650-43B5-AB7E-55CA87F7C515}.Release|x64.Build.0 = Release|Any CPU + {DF6874DC-C650-43B5-AB7E-55CA87F7C515}.Release|x86.ActiveCfg = Release|Any CPU + {DF6874DC-C650-43B5-AB7E-55CA87F7C515}.Release|x86.Build.0 = Release|Any CPU + {311609F6-420D-4B05-8E66-B1B084C45D19}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {311609F6-420D-4B05-8E66-B1B084C45D19}.Debug|Any CPU.Build.0 = Debug|Any CPU + {311609F6-420D-4B05-8E66-B1B084C45D19}.Debug|x64.ActiveCfg = Debug|Any CPU + {311609F6-420D-4B05-8E66-B1B084C45D19}.Debug|x64.Build.0 = Debug|Any CPU + {311609F6-420D-4B05-8E66-B1B084C45D19}.Debug|x86.ActiveCfg = Debug|Any CPU + {311609F6-420D-4B05-8E66-B1B084C45D19}.Debug|x86.Build.0 = Debug|Any CPU + {311609F6-420D-4B05-8E66-B1B084C45D19}.Release|Any CPU.ActiveCfg = Release|Any CPU + {311609F6-420D-4B05-8E66-B1B084C45D19}.Release|Any CPU.Build.0 = Release|Any CPU + {311609F6-420D-4B05-8E66-B1B084C45D19}.Release|x64.ActiveCfg = Release|Any CPU + {311609F6-420D-4B05-8E66-B1B084C45D19}.Release|x64.Build.0 = Release|Any CPU + {311609F6-420D-4B05-8E66-B1B084C45D19}.Release|x86.ActiveCfg = Release|Any CPU + {311609F6-420D-4B05-8E66-B1B084C45D19}.Release|x86.Build.0 = Release|Any CPU + {433E6F74-5C51-43A5-A92C-C90D8DEB0D98}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {433E6F74-5C51-43A5-A92C-C90D8DEB0D98}.Debug|x64.ActiveCfg = Debug|Any CPU + {433E6F74-5C51-43A5-A92C-C90D8DEB0D98}.Debug|x86.ActiveCfg = Debug|Any CPU + {433E6F74-5C51-43A5-A92C-C90D8DEB0D98}.Release|Any CPU.ActiveCfg = Release|Any CPU + {433E6F74-5C51-43A5-A92C-C90D8DEB0D98}.Release|x64.ActiveCfg = Release|Any CPU + {433E6F74-5C51-43A5-A92C-C90D8DEB0D98}.Release|x86.ActiveCfg = Release|Any CPU + {7973CB94-3824-48AD-816E-CD9EBF217B3A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7973CB94-3824-48AD-816E-CD9EBF217B3A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7973CB94-3824-48AD-816E-CD9EBF217B3A}.Debug|x64.ActiveCfg = Debug|Any CPU + {7973CB94-3824-48AD-816E-CD9EBF217B3A}.Debug|x64.Build.0 = Debug|Any CPU + {7973CB94-3824-48AD-816E-CD9EBF217B3A}.Debug|x86.ActiveCfg = Debug|Any CPU + {7973CB94-3824-48AD-816E-CD9EBF217B3A}.Debug|x86.Build.0 = Debug|Any CPU + {7973CB94-3824-48AD-816E-CD9EBF217B3A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7973CB94-3824-48AD-816E-CD9EBF217B3A}.Release|Any CPU.Build.0 = Release|Any CPU + {7973CB94-3824-48AD-816E-CD9EBF217B3A}.Release|x64.ActiveCfg = Release|Any CPU + {7973CB94-3824-48AD-816E-CD9EBF217B3A}.Release|x64.Build.0 = Release|Any CPU + {7973CB94-3824-48AD-816E-CD9EBF217B3A}.Release|x86.ActiveCfg = Release|Any CPU + {7973CB94-3824-48AD-816E-CD9EBF217B3A}.Release|x86.Build.0 = Release|Any CPU + {E283EB20-A10D-482B-8320-93AFC70C36A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E283EB20-A10D-482B-8320-93AFC70C36A8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E283EB20-A10D-482B-8320-93AFC70C36A8}.Debug|x64.ActiveCfg = Debug|Any CPU + {E283EB20-A10D-482B-8320-93AFC70C36A8}.Debug|x64.Build.0 = Debug|Any CPU + {E283EB20-A10D-482B-8320-93AFC70C36A8}.Debug|x86.ActiveCfg = Debug|Any CPU + {E283EB20-A10D-482B-8320-93AFC70C36A8}.Debug|x86.Build.0 = Debug|Any CPU + {E283EB20-A10D-482B-8320-93AFC70C36A8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E283EB20-A10D-482B-8320-93AFC70C36A8}.Release|Any CPU.Build.0 = Release|Any CPU + {E283EB20-A10D-482B-8320-93AFC70C36A8}.Release|x64.ActiveCfg = Release|Any CPU + {E283EB20-A10D-482B-8320-93AFC70C36A8}.Release|x64.Build.0 = Release|Any CPU + {E283EB20-A10D-482B-8320-93AFC70C36A8}.Release|x86.ActiveCfg = Release|Any CPU + {E283EB20-A10D-482B-8320-93AFC70C36A8}.Release|x86.Build.0 = Release|Any CPU + {C4A32153-A694-401F-B54A-38F7642D24D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C4A32153-A694-401F-B54A-38F7642D24D9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C4A32153-A694-401F-B54A-38F7642D24D9}.Debug|x64.ActiveCfg = Debug|Any CPU + {C4A32153-A694-401F-B54A-38F7642D24D9}.Debug|x64.Build.0 = Debug|Any CPU + {C4A32153-A694-401F-B54A-38F7642D24D9}.Debug|x86.ActiveCfg = Debug|Any CPU + {C4A32153-A694-401F-B54A-38F7642D24D9}.Debug|x86.Build.0 = Debug|Any CPU + {C4A32153-A694-401F-B54A-38F7642D24D9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C4A32153-A694-401F-B54A-38F7642D24D9}.Release|Any CPU.Build.0 = Release|Any CPU + {C4A32153-A694-401F-B54A-38F7642D24D9}.Release|x64.ActiveCfg = Release|Any CPU + {C4A32153-A694-401F-B54A-38F7642D24D9}.Release|x64.Build.0 = Release|Any CPU + {C4A32153-A694-401F-B54A-38F7642D24D9}.Release|x86.ActiveCfg = Release|Any CPU + {C4A32153-A694-401F-B54A-38F7642D24D9}.Release|x86.Build.0 = Release|Any CPU + {9F527768-04B3-4DED-89B7-0D0A8DA59DB9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9F527768-04B3-4DED-89B7-0D0A8DA59DB9}.Debug|x64.ActiveCfg = Debug|Any CPU + {9F527768-04B3-4DED-89B7-0D0A8DA59DB9}.Debug|x86.ActiveCfg = Debug|Any CPU + {9F527768-04B3-4DED-89B7-0D0A8DA59DB9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9F527768-04B3-4DED-89B7-0D0A8DA59DB9}.Release|x64.ActiveCfg = Release|Any CPU + {9F527768-04B3-4DED-89B7-0D0A8DA59DB9}.Release|x86.ActiveCfg = Release|Any CPU + {E8265A69-7C88-4728-ACD2-710A5F7C0E3A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E8265A69-7C88-4728-ACD2-710A5F7C0E3A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E8265A69-7C88-4728-ACD2-710A5F7C0E3A}.Debug|x64.ActiveCfg = Debug|Any CPU + {E8265A69-7C88-4728-ACD2-710A5F7C0E3A}.Debug|x64.Build.0 = Debug|Any CPU + {E8265A69-7C88-4728-ACD2-710A5F7C0E3A}.Debug|x86.ActiveCfg = Debug|Any CPU + {E8265A69-7C88-4728-ACD2-710A5F7C0E3A}.Debug|x86.Build.0 = Debug|Any CPU + {E8265A69-7C88-4728-ACD2-710A5F7C0E3A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E8265A69-7C88-4728-ACD2-710A5F7C0E3A}.Release|Any CPU.Build.0 = Release|Any CPU + {E8265A69-7C88-4728-ACD2-710A5F7C0E3A}.Release|x64.ActiveCfg = Release|Any CPU + {E8265A69-7C88-4728-ACD2-710A5F7C0E3A}.Release|x64.Build.0 = Release|Any CPU + {E8265A69-7C88-4728-ACD2-710A5F7C0E3A}.Release|x86.ActiveCfg = Release|Any CPU + {E8265A69-7C88-4728-ACD2-710A5F7C0E3A}.Release|x86.Build.0 = Release|Any CPU + {1B282238-83D7-4FBD-BE3C-180A82253543}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1B282238-83D7-4FBD-BE3C-180A82253543}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1B282238-83D7-4FBD-BE3C-180A82253543}.Debug|x64.ActiveCfg = Debug|Any CPU + {1B282238-83D7-4FBD-BE3C-180A82253543}.Debug|x64.Build.0 = Debug|Any CPU + {1B282238-83D7-4FBD-BE3C-180A82253543}.Debug|x86.ActiveCfg = Debug|Any CPU + {1B282238-83D7-4FBD-BE3C-180A82253543}.Debug|x86.Build.0 = Debug|Any CPU + {1B282238-83D7-4FBD-BE3C-180A82253543}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1B282238-83D7-4FBD-BE3C-180A82253543}.Release|Any CPU.Build.0 = Release|Any CPU + {1B282238-83D7-4FBD-BE3C-180A82253543}.Release|x64.ActiveCfg = Release|Any CPU + {1B282238-83D7-4FBD-BE3C-180A82253543}.Release|x64.Build.0 = Release|Any CPU + {1B282238-83D7-4FBD-BE3C-180A82253543}.Release|x86.ActiveCfg = Release|Any CPU + {1B282238-83D7-4FBD-BE3C-180A82253543}.Release|x86.Build.0 = Release|Any CPU + {6C744129-0A51-4110-93E4-FCD652680C21}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6C744129-0A51-4110-93E4-FCD652680C21}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6C744129-0A51-4110-93E4-FCD652680C21}.Debug|x64.ActiveCfg = Debug|Any CPU + {6C744129-0A51-4110-93E4-FCD652680C21}.Debug|x64.Build.0 = Debug|Any CPU + {6C744129-0A51-4110-93E4-FCD652680C21}.Debug|x86.ActiveCfg = Debug|Any CPU + {6C744129-0A51-4110-93E4-FCD652680C21}.Debug|x86.Build.0 = Debug|Any CPU + {6C744129-0A51-4110-93E4-FCD652680C21}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6C744129-0A51-4110-93E4-FCD652680C21}.Release|Any CPU.Build.0 = Release|Any CPU + {6C744129-0A51-4110-93E4-FCD652680C21}.Release|x64.ActiveCfg = Release|Any CPU + {6C744129-0A51-4110-93E4-FCD652680C21}.Release|x64.Build.0 = Release|Any CPU + {6C744129-0A51-4110-93E4-FCD652680C21}.Release|x86.ActiveCfg = Release|Any CPU + {6C744129-0A51-4110-93E4-FCD652680C21}.Release|x86.Build.0 = Release|Any CPU + {E57FA06A-5CAA-4911-85C5-25A9F0C7E97C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E57FA06A-5CAA-4911-85C5-25A9F0C7E97C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E57FA06A-5CAA-4911-85C5-25A9F0C7E97C}.Debug|x64.ActiveCfg = Debug|Any CPU + {E57FA06A-5CAA-4911-85C5-25A9F0C7E97C}.Debug|x64.Build.0 = Debug|Any CPU + {E57FA06A-5CAA-4911-85C5-25A9F0C7E97C}.Debug|x86.ActiveCfg = Debug|Any CPU + {E57FA06A-5CAA-4911-85C5-25A9F0C7E97C}.Debug|x86.Build.0 = Debug|Any CPU + {E57FA06A-5CAA-4911-85C5-25A9F0C7E97C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E57FA06A-5CAA-4911-85C5-25A9F0C7E97C}.Release|Any CPU.Build.0 = Release|Any CPU + {E57FA06A-5CAA-4911-85C5-25A9F0C7E97C}.Release|x64.ActiveCfg = Release|Any CPU + {E57FA06A-5CAA-4911-85C5-25A9F0C7E97C}.Release|x64.Build.0 = Release|Any CPU + {E57FA06A-5CAA-4911-85C5-25A9F0C7E97C}.Release|x86.ActiveCfg = Release|Any CPU + {E57FA06A-5CAA-4911-85C5-25A9F0C7E97C}.Release|x86.Build.0 = Release|Any CPU + {8F4BE58C-4C65-4960-9BD4-F785F1AD6EB1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8F4BE58C-4C65-4960-9BD4-F785F1AD6EB1}.Debug|x64.ActiveCfg = Debug|Any CPU + {8F4BE58C-4C65-4960-9BD4-F785F1AD6EB1}.Debug|x86.ActiveCfg = Debug|Any CPU + {8F4BE58C-4C65-4960-9BD4-F785F1AD6EB1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8F4BE58C-4C65-4960-9BD4-F785F1AD6EB1}.Release|x64.ActiveCfg = Release|Any CPU + {8F4BE58C-4C65-4960-9BD4-F785F1AD6EB1}.Release|x86.ActiveCfg = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {50C548F6-BD90-44B2-939B-88E157BC1D77} = {1F87798A-3DA2-1D52-37E6-92287F21560B} + {B6093DDC-14AF-4A21-989B-3AC63B89ACB0} = {1F87798A-3DA2-1D52-37E6-92287F21560B} + {2809E8F4-B766-4D9D-B514-DEB85D974F5C} = {8FE76333-615D-4D0B-08EF-9ACA145B22E5} + {1ADB10A5-ABA0-430F-88EB-10D2F2A379FC} = {8FE76333-615D-4D0B-08EF-9ACA145B22E5} + {D0DE0C4D-8901-4FBD-A78C-B11D1B4675B4} = {F300D630-7571-566C-DE3A-0237458CBD19} + {C7F9A6FC-67C8-4E44-B1CF-671A1315156D} = {10305151-72DA-BBBB-C817-BD890FA250F2} + {F00C8951-341A-4738-A289-33504D2906D5} = {10305151-72DA-BBBB-C817-BD890FA250F2} + {D098CDA1-D567-45E4-8C0E-53DFBA25EE22} = {CA0ABCE0-AAC8-D42B-D483-0AD6CB9ED44A} + {E9BECDF9-5270-4E67-8B53-918DB5414427} = {46A6B6E4-1F62-AC21-FF7F-BCB260772A08} + {FB8CDB1A-1DE0-488F-943A-115DE375344F} = {46A6B6E4-1F62-AC21-FF7F-BCB260772A08} + {0756435B-A795-4CC3-BA73-E2AB0F436F39} = {D19774F8-5390-DECA-0D5D-DB3D3B1934CC} + {F03B61E0-1EB5-4ECB-8E43-1ED6A31E7665} = {D19774F8-5390-DECA-0D5D-DB3D3B1934CC} + {DA0491F2-641D-4E6D-9B97-DC465C1CCE33} = {0FBFF59C-0FC2-5776-A3F6-C46E2EF347EC} + {DF6874DC-C650-43B5-AB7E-55CA87F7C515} = {0FBFF59C-0FC2-5776-A3F6-C46E2EF347EC} + {311609F6-420D-4B05-8E66-B1B084C45D19} = {EBF3C506-8F29-9654-7600-23BD3F25C924} + {433E6F74-5C51-43A5-A92C-C90D8DEB0D98} = {EBF3C506-8F29-9654-7600-23BD3F25C924} + {7973CB94-3824-48AD-816E-CD9EBF217B3A} = {1B681BF4-A602-D408-2E69-2B57B87575B2} + {E283EB20-A10D-482B-8320-93AFC70C36A8} = {1B681BF4-A602-D408-2E69-2B57B87575B2} + {C4A32153-A694-401F-B54A-38F7642D24D9} = {533FC926-FE64-7363-FF68-925D042523EE} + {9F527768-04B3-4DED-89B7-0D0A8DA59DB9} = {533FC926-FE64-7363-FF68-925D042523EE} + {E8265A69-7C88-4728-ACD2-710A5F7C0E3A} = {992222C4-ADE0-6BF1-7230-A9C65755AE09} + {1B282238-83D7-4FBD-BE3C-180A82253543} = {992222C4-ADE0-6BF1-7230-A9C65755AE09} + {986A884E-2D1F-75CC-48B5-B2716C96E4D3} = {DAF4ADBB-250D-0A80-76AC-796D3C9CD4A9} + {6C744129-0A51-4110-93E4-FCD652680C21} = {986A884E-2D1F-75CC-48B5-B2716C96E4D3} + {E57FA06A-5CAA-4911-85C5-25A9F0C7E97C} = {986A884E-2D1F-75CC-48B5-B2716C96E4D3} + {8F4BE58C-4C65-4960-9BD4-F785F1AD6EB1} = {986A884E-2D1F-75CC-48B5-B2716C96E4D3} + EndGlobalSection +EndGlobal diff --git a/samples/build.cmd b/samples/build.cmd new file mode 100644 index 0000000..b08cc59 --- /dev/null +++ b/samples/build.cmd @@ -0,0 +1,7 @@ +:; set -eo pipefail +:; SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd) +:; ${SCRIPT_DIR}/build.sh "$@" +:; exit $? + +@ECHO OFF +powershell -ExecutionPolicy ByPass -NoProfile -File "%~dp0build.ps1" %* diff --git a/samples/build.ps1 b/samples/build.ps1 new file mode 100644 index 0000000..e76a5b2 --- /dev/null +++ b/samples/build.ps1 @@ -0,0 +1,106 @@ +#!/usr/bin/env pwsh +<# +.SYNOPSIS + Build script for samples solution with proper dependency management +.DESCRIPTION + This script ensures the main JD.Efcpt.Build packages are built first, + then builds the samples solution. +.PARAMETER Configuration + Build configuration (Debug or Release). Default is Debug. +.PARAMETER SkipMainBuild + Skip building the main solution packages +#> + +param( + [ValidateSet('Debug', 'Release')] + [string]$Configuration = 'Debug', + [switch]$SkipMainBuild +) + +$ErrorActionPreference = 'Stop' +Set-StrictMode -Version Latest + +$samplesRoot = $PSScriptRoot +$repoRoot = Split-Path $samplesRoot -Parent +$mainSolution = Join-Path $repoRoot "JD.Efcpt.Build.sln" +$packagesDir = Join-Path $repoRoot "packages" +$samplesSolution = Join-Path $samplesRoot "Samples.sln" + +Write-Host "========================================" -ForegroundColor Cyan +Write-Host "JD.Efcpt.Build Samples Build Script" -ForegroundColor Cyan +Write-Host "========================================" -ForegroundColor Cyan +Write-Host "" + +# Step 1: Build main solution packages +if (-not $SkipMainBuild) { + Write-Host "Step 1: Building main solution..." -ForegroundColor Yellow + Push-Location $repoRoot + try { + dotnet build $mainSolution --configuration $Configuration + if ($LASTEXITCODE -ne 0) { + throw "Failed to build main solution" + } + Write-Host "✓ Main solution built successfully" -ForegroundColor Green + Write-Host "" + + Write-Host "Step 2: Packing main solution..." -ForegroundColor Yellow + dotnet pack $mainSolution --configuration $Configuration --output $packagesDir --no-build + if ($LASTEXITCODE -ne 0) { + throw "Failed to pack main solution" + } + Write-Host "✓ Main solution packed successfully" -ForegroundColor Green + Write-Host "" + + Write-Host "Step 3: Fixing sample project issues..." -ForegroundColor Yellow + & "$samplesRoot\fix-samples.ps1" -Quiet + Write-Host " ✓ Sample fixes applied" -ForegroundColor Green + Write-Host "" + } + finally { + Pop-Location + } +} +else { + Write-Host "Skipping main solution build" -ForegroundColor Gray + Write-Host "" +} + +# Step 2: Restore and build samples solution +Write-Host "Step 4: Restoring sample solution..." -ForegroundColor Yellow +Write-Host "Note: Using NuGet.config for package sources (local packages + nuget.org)" -ForegroundColor Gray +dotnet restore $samplesSolution +$restoreExitCode = $LASTEXITCODE + +if ($restoreExitCode -ne 0) { + Write-Host "⚠ Restore completed with errors" -ForegroundColor Yellow + Write-Host "" + Write-Host "Known issues:" -ForegroundColor Yellow + Write-Host " - sdk-zero-config: Requires SDK version in global.json" -ForegroundColor Gray + Write-Host " - Some samples: Target framework may not match EF Core package version" -ForegroundColor Gray + Write-Host "" +} +else { + Write-Host "✓ Sample solution restored" -ForegroundColor Green + Write-Host "" +} + +Write-Host "Step 5: Building sample solution..." -ForegroundColor Yellow +dotnet build $samplesSolution --configuration $Configuration --no-restore +$buildExitCode = $LASTEXITCODE + +if ($buildExitCode -ne 0) { + Write-Host "⚠ Build completed with errors" -ForegroundColor Yellow + Write-Host "" + Write-Host "Some samples may have pre-existing issues." -ForegroundColor Gray + Write-Host "Check individual sample README files for requirements." -ForegroundColor Gray + Write-Host "" + exit 1 +} +else { + Write-Host "✓ Sample solution built successfully" -ForegroundColor Green + Write-Host "" +} + +Write-Host "========================================" -ForegroundColor Cyan +Write-Host "Build completed! 🎉" -ForegroundColor Green +Write-Host "========================================" -ForegroundColor Cyan diff --git a/samples/build.sh b/samples/build.sh new file mode 100644 index 0000000..fdff0c6 --- /dev/null +++ b/samples/build.sh @@ -0,0 +1,67 @@ +#!/usr/bin/env bash + +bash --version 2>&1 | head -n 1 + +set -eo pipefail +SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd) + +########################################################################### +# CONFIGURATION +########################################################################### + +BUILD_PROJECT_FILE="$SCRIPT_DIR/build/_build.csproj" +TEMP_DIRECTORY="$SCRIPT_DIR//.nuke/temp" + +DOTNET_GLOBAL_FILE="$SCRIPT_DIR//global.json" +DOTNET_INSTALL_URL="https://dot.net/v1/dotnet-install.sh" +DOTNET_CHANNEL="STS" + +export DOTNET_CLI_TELEMETRY_OPTOUT=1 +export DOTNET_NOLOGO=1 + +########################################################################### +# EXECUTION +########################################################################### + +function FirstJsonValue { + perl -nle 'print $1 if m{"'"$1"'": "([^"]+)",?}' <<< "${@:2}" +} + +# If dotnet CLI is installed globally and it matches requested version, use for execution +if [ -x "$(command -v dotnet)" ] && dotnet --version &>/dev/null; then + export DOTNET_EXE="$(command -v dotnet)" +else + # Download install script + DOTNET_INSTALL_FILE="$TEMP_DIRECTORY/dotnet-install.sh" + mkdir -p "$TEMP_DIRECTORY" + curl -Lsfo "$DOTNET_INSTALL_FILE" "$DOTNET_INSTALL_URL" + chmod +x "$DOTNET_INSTALL_FILE" + + # If global.json exists, load expected version + if [[ -f "$DOTNET_GLOBAL_FILE" ]]; then + DOTNET_VERSION=$(FirstJsonValue "version" "$(cat "$DOTNET_GLOBAL_FILE")") + if [[ "$DOTNET_VERSION" == "" ]]; then + unset DOTNET_VERSION + fi + fi + + # Install by channel or version + DOTNET_DIRECTORY="$TEMP_DIRECTORY/dotnet-unix" + if [[ -z ${DOTNET_VERSION+x} ]]; then + "$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --channel "$DOTNET_CHANNEL" --no-path + else + "$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --version "$DOTNET_VERSION" --no-path + fi + export DOTNET_EXE="$DOTNET_DIRECTORY/dotnet" + export PATH="$DOTNET_DIRECTORY:$PATH" +fi + +echo "Microsoft (R) .NET SDK version $("$DOTNET_EXE" --version)" + +if [[ ! -z ${NUKE_ENTERPRISE_TOKEN+x} && "$NUKE_ENTERPRISE_TOKEN" != "" ]]; then + "$DOTNET_EXE" nuget remove source "nuke-enterprise" &>/dev/null || true + "$DOTNET_EXE" nuget add source "https://f.feedz.io/nuke/enterprise/nuget" --name "nuke-enterprise" --username "PAT" --password "$NUKE_ENTERPRISE_TOKEN" --store-password-in-clear-text &>/dev/null || true +fi + +"$DOTNET_EXE" build "$BUILD_PROJECT_FILE" /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet +"$DOTNET_EXE" run --project "$BUILD_PROJECT_FILE" --no-build -- "$@" diff --git a/src/JD.Efcpt.Build.Definitions/BuildPropsFactory.cs b/src/JD.Efcpt.Build.Definitions/BuildPropsFactory.cs new file mode 100644 index 0000000..862ec84 --- /dev/null +++ b/src/JD.Efcpt.Build.Definitions/BuildPropsFactory.cs @@ -0,0 +1,30 @@ +using JD.MSBuild.Fluent; +using JD.MSBuild.Fluent.Fluent; +using JD.MSBuild.Fluent.Typed; + +namespace JD.Efcpt.Build.Definitions; + +/// +/// MSBuild package definition scaffolded from JD.Efcpt.Build.xml +/// +public static class BuildPropsFactory +{ + public static PackageDefinition Create() + { + return Package.Define("JD.Efcpt.Build") + .Props(p => + { + p.Property("true"); + p.Import("..\\buildTransitive\\JD.Efcpt.Build.props"); + }) + .Build(); + } + + // Strongly-typed property names + public readonly struct EfcptIsDirectReference : IMsBuildPropertyName + { + public string Name => "_EfcptIsDirectReference"; + } +} + + diff --git a/src/JD.Efcpt.Build.Definitions/BuildTargetsFactory.cs b/src/JD.Efcpt.Build.Definitions/BuildTargetsFactory.cs new file mode 100644 index 0000000..cf96247 --- /dev/null +++ b/src/JD.Efcpt.Build.Definitions/BuildTargetsFactory.cs @@ -0,0 +1,20 @@ +using JD.MSBuild.Fluent; +using JD.MSBuild.Fluent.Fluent; + +namespace JD.Efcpt.Build.Definitions; + +/// +/// MSBuild package definition scaffolded from JD.Efcpt.Build.xml +/// +public static class BuildTargetsFactory +{ + public static PackageDefinition Create() + { + return Package.Define("JD.Efcpt.Build") + .Targets(t => + { + t.Import("..\\buildTransitive\\JD.Efcpt.Build.targets"); + }) + .Build(); + } +} diff --git a/src/JD.Efcpt.Build.Definitions/BuildTransitivePropsFactory.cs b/src/JD.Efcpt.Build.Definitions/BuildTransitivePropsFactory.cs new file mode 100644 index 0000000..6674c39 --- /dev/null +++ b/src/JD.Efcpt.Build.Definitions/BuildTransitivePropsFactory.cs @@ -0,0 +1,556 @@ +using JD.MSBuild.Fluent; +using JD.MSBuild.Fluent.Fluent; +using JD.MSBuild.Fluent.Typed; + +namespace JD.Efcpt.Build.Definitions; + +/// +/// MSBuild package definition scaffolded from JD.Efcpt.Build.xml +/// +public static class BuildTransitivePropsFactory +{ + public static PackageDefinition Create() + { + return Package.Define("JD.Efcpt.Build") + .Props(p => + { + p.PropertyGroup(null, group => + { + group.Property( "true", "'$(EfcptEnabled)'==''"); + group.Property( "$(BaseIntermediateOutputPath)efcpt\\", "'$(EfcptOutput)'==''"); + group.Property( "$(EfcptOutput)Generated\\", "'$(EfcptGeneratedDir)'==''"); + group.Property( "", "'$(EfcptSqlProj)'==''"); + group.Property( "", "'$(EfcptDacpac)'==''"); + group.Property( "efcpt-config.json", "'$(EfcptConfig)'==''"); + group.Property( "efcpt.renaming.json", "'$(EfcptRenaming)'==''"); + group.Property( "Template", "'$(EfcptTemplateDir)'==''"); + group.Property( "", "'$(EfcptConnectionString)'==''"); + group.Property( "", "'$(EfcptAppSettings)'==''"); + group.Property( "", "'$(EfcptAppConfig)'==''"); + group.Property( "DefaultConnection", "'$(EfcptConnectionStringName)'==''"); + group.Property( "mssql", "'$(EfcptProvider)'==''"); + group.Property( "$(SolutionDir)", "'$(EfcptSolutionDir)'==''"); + group.Property( "$(SolutionPath)", "'$(EfcptSolutionPath)'==''"); + group.Property( "true", "'$(EfcptProbeSolutionDir)'==''"); + group.Property( "auto", "'$(EfcptToolMode)'==''"); + group.Property( "ErikEJ.EFCorePowerTools.Cli", "'$(EfcptToolPackageId)'==''"); + group.Property( "10.*", "'$(EfcptToolVersion)'==''"); + group.Property( "true", "'$(EfcptToolRestore)'==''"); + group.Property( "efcpt", "'$(EfcptToolCommand)'==''"); + group.Property( "", "'$(EfcptToolPath)'==''"); + group.Property( "dotnet", "'$(EfcptDotNetExe)'==''"); + group.Property( "$(EfcptOutput)fingerprint.txt", "'$(EfcptFingerprintFile)'==''"); + group.Property( "$(EfcptOutput).efcpt.stamp", "'$(EfcptStampFile)'==''"); + group.Property( "false", "'$(EfcptDetectGeneratedFileChanges)'==''"); + group.Property( "minimal", "'$(EfcptLogVerbosity)'==''"); + group.Property( "false", "'$(EfcptDumpResolvedInputs)'==''"); + group.Property( "Info", "'$(EfcptAutoDetectWarningLevel)'==''"); + group.Property( "Warn", "'$(EfcptSdkVersionWarningLevel)'==''"); + group.Property( "false", "'$(EfcptCheckForUpdates)'==''"); + group.Property( "24", "'$(EfcptUpdateCheckCacheHours)'==''"); + group.Property( "false", "'$(EfcptForceUpdateCheck)'==''"); + group.Property( "false", "'$(EfcptSplitOutputs)'==''"); + group.Property( "", "'$(EfcptDataProject)'==''"); + group.Property( "obj\\efcpt\\Generated\\", "'$(EfcptDataProjectOutputSubdir)'==''"); + group.Property( "", "'$(EfcptExternalDataDir)'==''"); + group.Property( "true", "'$(EfcptApplyMsBuildOverrides)'==''"); + group.Property( "$(RootNamespace)", "'$(EfcptConfigRootNamespace)'=='' and '$(RootNamespace)'!=''"); + group.Property( "$(MSBuildProjectName)", "'$(EfcptConfigRootNamespace)'==''"); + group.Property( "", "'$(EfcptConfigDbContextName)'==''"); + group.Property( "", "'$(EfcptConfigDbContextNamespace)'==''"); + group.Property( "", "'$(EfcptConfigModelNamespace)'==''"); + group.Property( "", "'$(EfcptConfigOutputPath)'==''"); + group.Property( "", "'$(EfcptConfigDbContextOutputPath)'==''"); + group.Property( "", "'$(EfcptConfigSplitDbContext)'==''"); + group.Property( "", "'$(EfcptConfigUseSchemaFolders)'==''"); + group.Property( "", "'$(EfcptConfigUseSchemaNamespaces)'==''"); + group.Property( "", "'$(EfcptConfigEnableOnConfiguring)'==''"); + group.Property( "", "'$(EfcptConfigGenerationType)'==''"); + group.Property( "", "'$(EfcptConfigUseDatabaseNames)'==''"); + group.Property( "", "'$(EfcptConfigUseDataAnnotations)'==''"); + group.Property( "", "'$(EfcptConfigUseInflector)'==''"); + group.Property( "", "'$(EfcptConfigUseLegacyInflector)'==''"); + group.Property( "", "'$(EfcptConfigUseManyToManyEntity)'==''"); + group.Property( "", "'$(EfcptConfigUseT4)'==''"); + group.Property( "", "'$(EfcptConfigUseT4Split)'==''"); + group.Property( "", "'$(EfcptConfigRemoveDefaultSqlFromBool)'==''"); + group.Property( "", "'$(EfcptConfigSoftDeleteObsoleteFiles)'==''"); + group.Property( "", "'$(EfcptConfigDiscoverMultipleResultSets)'==''"); + group.Property( "", "'$(EfcptConfigUseAlternateResultSetDiscovery)'==''"); + group.Property( "", "'$(EfcptConfigT4TemplatePath)'==''"); + group.Property( "", "'$(EfcptConfigUseNoNavigations)'==''"); + group.Property( "", "'$(EfcptConfigMergeDacpacs)'==''"); + group.Property( "", "'$(EfcptConfigRefreshObjectLists)'==''"); + group.Property( "", "'$(EfcptConfigGenerateMermaidDiagram)'==''"); + group.Property( "", "'$(EfcptConfigUseDecimalAnnotationForSprocs)'==''"); + group.Property( "", "'$(EfcptConfigUsePrefixNavigationNaming)'==''"); + group.Property( "", "'$(EfcptConfigUseDatabaseNamesForRoutines)'==''"); + group.Property( "", "'$(EfcptConfigUseInternalAccessForRoutines)'==''"); + group.Property( "", "'$(EfcptConfigUseDateOnlyTimeOnly)'==''"); + group.Property( "", "'$(EfcptConfigUseHierarchyId)'==''"); + group.Property( "", "'$(EfcptConfigUseSpatial)'==''"); + group.Property( "", "'$(EfcptConfigUseNodaTime)'==''"); + group.Property( "", "'$(EfcptConfigPreserveCasingWithRegex)'==''"); + group.Property( "false", "'$(EfcptEnableProfiling)'==''"); + group.Property( "$(EfcptOutput)build-profile.json", "'$(EfcptProfilingOutput)'==''"); + group.Property( "minimal", "'$(EfcptProfilingVerbosity)'==''"); + }); + p.PropertyGroup(null, group => + { + group.Property( "microsoft-build-sql", "'$(EfcptSqlProjType)'==''"); + group.Property( "csharp", "'$(EfcptSqlProjLanguage)'==''"); + group.Property( "$(MSBuildProjectDirectory)\\", "'$(EfcptSqlProjOutputDir)'==''"); + group.Property( "$(MSBuildProjectDirectory)\\", "'$(EfcptSqlScriptsDir)'==''"); + group.Property( "Sql160", "'$(EfcptSqlServerVersion)'==''"); + group.Property( "", "'$(EfcptSqlPackageToolVersion)'==''"); + group.Property( "true", "'$(EfcptSqlPackageToolRestore)'==''"); + group.Property( "", "'$(EfcptSqlPackageToolPath)'==''"); + }); + }) + .Targets(t => + { + t.PropertyGroup(null, group => + { + group.Property( "true", "'$(EfcptEnabled)'==''"); + group.Property( "$(BaseIntermediateOutputPath)efcpt\\", "'$(EfcptOutput)'==''"); + group.Property( "$(EfcptOutput)Generated\\", "'$(EfcptGeneratedDir)'==''"); + group.Property( "", "'$(EfcptSqlProj)'==''"); + group.Property( "", "'$(EfcptDacpac)'==''"); + group.Property( "efcpt-config.json", "'$(EfcptConfig)'==''"); + group.Property( "efcpt.renaming.json", "'$(EfcptRenaming)'==''"); + group.Property( "Template", "'$(EfcptTemplateDir)'==''"); + group.Property( "", "'$(EfcptConnectionString)'==''"); + group.Property( "", "'$(EfcptAppSettings)'==''"); + group.Property( "", "'$(EfcptAppConfig)'==''"); + group.Property( "DefaultConnection", "'$(EfcptConnectionStringName)'==''"); + group.Property( "mssql", "'$(EfcptProvider)'==''"); + group.Property( "$(SolutionDir)", "'$(EfcptSolutionDir)'==''"); + group.Property( "$(SolutionPath)", "'$(EfcptSolutionPath)'==''"); + group.Property( "true", "'$(EfcptProbeSolutionDir)'==''"); + group.Property( "auto", "'$(EfcptToolMode)'==''"); + group.Property( "ErikEJ.EFCorePowerTools.Cli", "'$(EfcptToolPackageId)'==''"); + group.Property( "10.*", "'$(EfcptToolVersion)'==''"); + group.Property( "true", "'$(EfcptToolRestore)'==''"); + group.Property( "efcpt", "'$(EfcptToolCommand)'==''"); + group.Property( "", "'$(EfcptToolPath)'==''"); + group.Property( "dotnet", "'$(EfcptDotNetExe)'==''"); + group.Property( "$(EfcptOutput)fingerprint.txt", "'$(EfcptFingerprintFile)'==''"); + group.Property( "$(EfcptOutput).efcpt.stamp", "'$(EfcptStampFile)'==''"); + group.Property( "false", "'$(EfcptDetectGeneratedFileChanges)'==''"); + group.Property( "minimal", "'$(EfcptLogVerbosity)'==''"); + group.Property( "false", "'$(EfcptDumpResolvedInputs)'==''"); + group.Property( "Info", "'$(EfcptAutoDetectWarningLevel)'==''"); + group.Property( "Warn", "'$(EfcptSdkVersionWarningLevel)'==''"); + group.Property( "false", "'$(EfcptCheckForUpdates)'==''"); + group.Property( "24", "'$(EfcptUpdateCheckCacheHours)'==''"); + group.Property( "false", "'$(EfcptForceUpdateCheck)'==''"); + group.Property( "false", "'$(EfcptSplitOutputs)'==''"); + group.Property( "", "'$(EfcptDataProject)'==''"); + group.Property( "obj\\efcpt\\Generated\\", "'$(EfcptDataProjectOutputSubdir)'==''"); + group.Property( "", "'$(EfcptExternalDataDir)'==''"); + group.Property( "true", "'$(EfcptApplyMsBuildOverrides)'==''"); + group.Property( "$(RootNamespace)", "'$(EfcptConfigRootNamespace)'=='' and '$(RootNamespace)'!=''"); + group.Property( "$(MSBuildProjectName)", "'$(EfcptConfigRootNamespace)'==''"); + group.Property( "", "'$(EfcptConfigDbContextName)'==''"); + group.Property( "", "'$(EfcptConfigDbContextNamespace)'==''"); + group.Property( "", "'$(EfcptConfigModelNamespace)'==''"); + group.Property( "", "'$(EfcptConfigOutputPath)'==''"); + group.Property( "", "'$(EfcptConfigDbContextOutputPath)'==''"); + group.Property( "", "'$(EfcptConfigSplitDbContext)'==''"); + group.Property( "", "'$(EfcptConfigUseSchemaFolders)'==''"); + group.Property( "", "'$(EfcptConfigUseSchemaNamespaces)'==''"); + group.Property( "", "'$(EfcptConfigEnableOnConfiguring)'==''"); + group.Property( "", "'$(EfcptConfigGenerationType)'==''"); + group.Property( "", "'$(EfcptConfigUseDatabaseNames)'==''"); + group.Property( "", "'$(EfcptConfigUseDataAnnotations)'==''"); + group.Property( "", "'$(EfcptConfigUseInflector)'==''"); + group.Property( "", "'$(EfcptConfigUseLegacyInflector)'==''"); + group.Property( "", "'$(EfcptConfigUseManyToManyEntity)'==''"); + group.Property( "", "'$(EfcptConfigUseT4)'==''"); + group.Property( "", "'$(EfcptConfigUseT4Split)'==''"); + group.Property( "", "'$(EfcptConfigRemoveDefaultSqlFromBool)'==''"); + group.Property( "", "'$(EfcptConfigSoftDeleteObsoleteFiles)'==''"); + group.Property( "", "'$(EfcptConfigDiscoverMultipleResultSets)'==''"); + group.Property( "", "'$(EfcptConfigUseAlternateResultSetDiscovery)'==''"); + group.Property( "", "'$(EfcptConfigT4TemplatePath)'==''"); + group.Property( "", "'$(EfcptConfigUseNoNavigations)'==''"); + group.Property( "", "'$(EfcptConfigMergeDacpacs)'==''"); + group.Property( "", "'$(EfcptConfigRefreshObjectLists)'==''"); + group.Property( "", "'$(EfcptConfigGenerateMermaidDiagram)'==''"); + group.Property( "", "'$(EfcptConfigUseDecimalAnnotationForSprocs)'==''"); + group.Property( "", "'$(EfcptConfigUsePrefixNavigationNaming)'==''"); + group.Property( "", "'$(EfcptConfigUseDatabaseNamesForRoutines)'==''"); + group.Property( "", "'$(EfcptConfigUseInternalAccessForRoutines)'==''"); + group.Property( "", "'$(EfcptConfigUseDateOnlyTimeOnly)'==''"); + group.Property( "", "'$(EfcptConfigUseHierarchyId)'==''"); + group.Property( "", "'$(EfcptConfigUseSpatial)'==''"); + group.Property( "", "'$(EfcptConfigUseNodaTime)'==''"); + group.Property( "", "'$(EfcptConfigPreserveCasingWithRegex)'==''"); + group.Property( "false", "'$(EfcptEnableProfiling)'==''"); + group.Property( "$(EfcptOutput)build-profile.json", "'$(EfcptProfilingOutput)'==''"); + group.Property( "minimal", "'$(EfcptProfilingVerbosity)'==''"); + }); + t.PropertyGroup(null, group => + { + group.Property( "microsoft-build-sql", "'$(EfcptSqlProjType)'==''"); + group.Property( "csharp", "'$(EfcptSqlProjLanguage)'==''"); + group.Property( "$(MSBuildProjectDirectory)\\", "'$(EfcptSqlProjOutputDir)'==''"); + group.Property( "$(MSBuildProjectDirectory)\\", "'$(EfcptSqlScriptsDir)'==''"); + group.Property( "Sql160", "'$(EfcptSqlServerVersion)'==''"); + group.Property( "", "'$(EfcptSqlPackageToolVersion)'==''"); + group.Property( "true", "'$(EfcptSqlPackageToolRestore)'==''"); + group.Property( "", "'$(EfcptSqlPackageToolPath)'==''"); + }); + }) + .Build(); + } + + // Strongly-typed property names + + + public readonly struct EfcptAppConfig : IMsBuildPropertyName + { + public string Name => "EfcptAppConfig"; + } + public readonly struct EfcptApplyMsBuildOverrides : IMsBuildPropertyName + { + public string Name => "EfcptApplyMsBuildOverrides"; + } + public readonly struct EfcptAppSettings : IMsBuildPropertyName + { + public string Name => "EfcptAppSettings"; + } + public readonly struct EfcptAutoDetectWarningLevel : IMsBuildPropertyName + { + public string Name => "EfcptAutoDetectWarningLevel"; + } + public readonly struct EfcptCheckForUpdates : IMsBuildPropertyName + { + public string Name => "EfcptCheckForUpdates"; + } + public readonly struct EfcptConfig : IMsBuildPropertyName + { + public string Name => "EfcptConfig"; + } + public readonly struct EfcptConfigDbContextName : IMsBuildPropertyName + { + public string Name => "EfcptConfigDbContextName"; + } + public readonly struct EfcptConfigDbContextNamespace : IMsBuildPropertyName + { + public string Name => "EfcptConfigDbContextNamespace"; + } + public readonly struct EfcptConfigDbContextOutputPath : IMsBuildPropertyName + { + public string Name => "EfcptConfigDbContextOutputPath"; + } + public readonly struct EfcptConfigDiscoverMultipleResultSets : IMsBuildPropertyName + { + public string Name => "EfcptConfigDiscoverMultipleResultSets"; + } + public readonly struct EfcptConfigEnableOnConfiguring : IMsBuildPropertyName + { + public string Name => "EfcptConfigEnableOnConfiguring"; + } + public readonly struct EfcptConfigGenerateMermaidDiagram : IMsBuildPropertyName + { + public string Name => "EfcptConfigGenerateMermaidDiagram"; + } + public readonly struct EfcptConfigGenerationType : IMsBuildPropertyName + { + public string Name => "EfcptConfigGenerationType"; + } + public readonly struct EfcptConfigMergeDacpacs : IMsBuildPropertyName + { + public string Name => "EfcptConfigMergeDacpacs"; + } + public readonly struct EfcptConfigModelNamespace : IMsBuildPropertyName + { + public string Name => "EfcptConfigModelNamespace"; + } + public readonly struct EfcptConfigOutputPath : IMsBuildPropertyName + { + public string Name => "EfcptConfigOutputPath"; + } + public readonly struct EfcptConfigPreserveCasingWithRegex : IMsBuildPropertyName + { + public string Name => "EfcptConfigPreserveCasingWithRegex"; + } + public readonly struct EfcptConfigRefreshObjectLists : IMsBuildPropertyName + { + public string Name => "EfcptConfigRefreshObjectLists"; + } + public readonly struct EfcptConfigRemoveDefaultSqlFromBool : IMsBuildPropertyName + { + public string Name => "EfcptConfigRemoveDefaultSqlFromBool"; + } + public readonly struct EfcptConfigRootNamespace : IMsBuildPropertyName + { + public string Name => "EfcptConfigRootNamespace"; + } + public readonly struct EfcptConfigSoftDeleteObsoleteFiles : IMsBuildPropertyName + { + public string Name => "EfcptConfigSoftDeleteObsoleteFiles"; + } + public readonly struct EfcptConfigSplitDbContext : IMsBuildPropertyName + { + public string Name => "EfcptConfigSplitDbContext"; + } + public readonly struct EfcptConfigT4TemplatePath : IMsBuildPropertyName + { + public string Name => "EfcptConfigT4TemplatePath"; + } + public readonly struct EfcptConfigUseAlternateResultSetDiscovery : IMsBuildPropertyName + { + public string Name => "EfcptConfigUseAlternateResultSetDiscovery"; + } + public readonly struct EfcptConfigUseDataAnnotations : IMsBuildPropertyName + { + public string Name => "EfcptConfigUseDataAnnotations"; + } + public readonly struct EfcptConfigUseDatabaseNames : IMsBuildPropertyName + { + public string Name => "EfcptConfigUseDatabaseNames"; + } + public readonly struct EfcptConfigUseDatabaseNamesForRoutines : IMsBuildPropertyName + { + public string Name => "EfcptConfigUseDatabaseNamesForRoutines"; + } + public readonly struct EfcptConfigUseDateOnlyTimeOnly : IMsBuildPropertyName + { + public string Name => "EfcptConfigUseDateOnlyTimeOnly"; + } + public readonly struct EfcptConfigUseDecimalAnnotationForSprocs : IMsBuildPropertyName + { + public string Name => "EfcptConfigUseDecimalAnnotationForSprocs"; + } + public readonly struct EfcptConfigUseHierarchyId : IMsBuildPropertyName + { + public string Name => "EfcptConfigUseHierarchyId"; + } + public readonly struct EfcptConfigUseInflector : IMsBuildPropertyName + { + public string Name => "EfcptConfigUseInflector"; + } + public readonly struct EfcptConfigUseInternalAccessForRoutines : IMsBuildPropertyName + { + public string Name => "EfcptConfigUseInternalAccessForRoutines"; + } + public readonly struct EfcptConfigUseLegacyInflector : IMsBuildPropertyName + { + public string Name => "EfcptConfigUseLegacyInflector"; + } + public readonly struct EfcptConfigUseManyToManyEntity : IMsBuildPropertyName + { + public string Name => "EfcptConfigUseManyToManyEntity"; + } + public readonly struct EfcptConfigUseNodaTime : IMsBuildPropertyName + { + public string Name => "EfcptConfigUseNodaTime"; + } + public readonly struct EfcptConfigUseNoNavigations : IMsBuildPropertyName + { + public string Name => "EfcptConfigUseNoNavigations"; + } + public readonly struct EfcptConfigUsePrefixNavigationNaming : IMsBuildPropertyName + { + public string Name => "EfcptConfigUsePrefixNavigationNaming"; + } + public readonly struct EfcptConfigUseSchemaFolders : IMsBuildPropertyName + { + public string Name => "EfcptConfigUseSchemaFolders"; + } + public readonly struct EfcptConfigUseSchemaNamespaces : IMsBuildPropertyName + { + public string Name => "EfcptConfigUseSchemaNamespaces"; + } + public readonly struct EfcptConfigUseSpatial : IMsBuildPropertyName + { + public string Name => "EfcptConfigUseSpatial"; + } + public readonly struct EfcptConfigUseT4 : IMsBuildPropertyName + { + public string Name => "EfcptConfigUseT4"; + } + public readonly struct EfcptConfigUseT4Split : IMsBuildPropertyName + { + public string Name => "EfcptConfigUseT4Split"; + } + public readonly struct EfcptConnectionString : IMsBuildPropertyName + { + public string Name => "EfcptConnectionString"; + } + public readonly struct EfcptConnectionStringName : IMsBuildPropertyName + { + public string Name => "EfcptConnectionStringName"; + } + public readonly struct EfcptDacpac : IMsBuildPropertyName + { + public string Name => "EfcptDacpac"; + } + public readonly struct EfcptDataProject : IMsBuildPropertyName + { + public string Name => "EfcptDataProject"; + } + public readonly struct EfcptDataProjectOutputSubdir : IMsBuildPropertyName + { + public string Name => "EfcptDataProjectOutputSubdir"; + } + public readonly struct EfcptDetectGeneratedFileChanges : IMsBuildPropertyName + { + public string Name => "EfcptDetectGeneratedFileChanges"; + } + public readonly struct EfcptDotNetExe : IMsBuildPropertyName + { + public string Name => "EfcptDotNetExe"; + } + public readonly struct EfcptDumpResolvedInputs : IMsBuildPropertyName + { + public string Name => "EfcptDumpResolvedInputs"; + } + public readonly struct EfcptEnabled : IMsBuildPropertyName + { + public string Name => "EfcptEnabled"; + } + public readonly struct EfcptEnableProfiling : IMsBuildPropertyName + { + public string Name => "EfcptEnableProfiling"; + } + public readonly struct EfcptExternalDataDir : IMsBuildPropertyName + { + public string Name => "EfcptExternalDataDir"; + } + public readonly struct EfcptFingerprintFile : IMsBuildPropertyName + { + public string Name => "EfcptFingerprintFile"; + } + public readonly struct EfcptForceUpdateCheck : IMsBuildPropertyName + { + public string Name => "EfcptForceUpdateCheck"; + } + public readonly struct EfcptGeneratedDir : IMsBuildPropertyName + { + public string Name => "EfcptGeneratedDir"; + } + public readonly struct EfcptLogVerbosity : IMsBuildPropertyName + { + public string Name => "EfcptLogVerbosity"; + } + public readonly struct EfcptOutput : IMsBuildPropertyName + { + public string Name => "EfcptOutput"; + } + public readonly struct EfcptProbeSolutionDir : IMsBuildPropertyName + { + public string Name => "EfcptProbeSolutionDir"; + } + public readonly struct EfcptProfilingOutput : IMsBuildPropertyName + { + public string Name => "EfcptProfilingOutput"; + } + public readonly struct EfcptProfilingVerbosity : IMsBuildPropertyName + { + public string Name => "EfcptProfilingVerbosity"; + } + public readonly struct EfcptProvider : IMsBuildPropertyName + { + public string Name => "EfcptProvider"; + } + public readonly struct EfcptRenaming : IMsBuildPropertyName + { + public string Name => "EfcptRenaming"; + } + public readonly struct EfcptSdkVersionWarningLevel : IMsBuildPropertyName + { + public string Name => "EfcptSdkVersionWarningLevel"; + } + public readonly struct EfcptSolutionDir : IMsBuildPropertyName + { + public string Name => "EfcptSolutionDir"; + } + public readonly struct EfcptSolutionPath : IMsBuildPropertyName + { + public string Name => "EfcptSolutionPath"; + } + public readonly struct EfcptSplitOutputs : IMsBuildPropertyName + { + public string Name => "EfcptSplitOutputs"; + } + public readonly struct EfcptSqlPackageToolPath : IMsBuildPropertyName + { + public string Name => "EfcptSqlPackageToolPath"; + } + public readonly struct EfcptSqlPackageToolRestore : IMsBuildPropertyName + { + public string Name => "EfcptSqlPackageToolRestore"; + } + public readonly struct EfcptSqlPackageToolVersion : IMsBuildPropertyName + { + public string Name => "EfcptSqlPackageToolVersion"; + } + public readonly struct EfcptSqlProj : IMsBuildPropertyName + { + public string Name => "EfcptSqlProj"; + } + public readonly struct EfcptSqlProjLanguage : IMsBuildPropertyName + { + public string Name => "EfcptSqlProjLanguage"; + } + public readonly struct EfcptSqlProjOutputDir : IMsBuildPropertyName + { + public string Name => "EfcptSqlProjOutputDir"; + } + public readonly struct EfcptSqlProjType : IMsBuildPropertyName + { + public string Name => "EfcptSqlProjType"; + } + public readonly struct EfcptSqlScriptsDir : IMsBuildPropertyName + { + public string Name => "EfcptSqlScriptsDir"; + } + public readonly struct EfcptSqlServerVersion : IMsBuildPropertyName + { + public string Name => "EfcptSqlServerVersion"; + } + public readonly struct EfcptStampFile : IMsBuildPropertyName + { + public string Name => "EfcptStampFile"; + } + public readonly struct EfcptTemplateDir : IMsBuildPropertyName + { + public string Name => "EfcptTemplateDir"; + } + public readonly struct EfcptToolCommand : IMsBuildPropertyName + { + public string Name => "EfcptToolCommand"; + } + public readonly struct EfcptToolMode : IMsBuildPropertyName + { + public string Name => "EfcptToolMode"; + } + public readonly struct EfcptToolPackageId : IMsBuildPropertyName + { + public string Name => "EfcptToolPackageId"; + } + public readonly struct EfcptToolPath : IMsBuildPropertyName + { + public string Name => "EfcptToolPath"; + } + public readonly struct EfcptToolRestore : IMsBuildPropertyName + { + public string Name => "EfcptToolRestore"; + } + public readonly struct EfcptToolVersion : IMsBuildPropertyName + { + public string Name => "EfcptToolVersion"; + } + public readonly struct EfcptUpdateCheckCacheHours : IMsBuildPropertyName + { + public string Name => "EfcptUpdateCheckCacheHours"; + } +} + + + + + diff --git a/src/JD.Efcpt.Build.Definitions/BuildTransitiveTargetsFactory.cs b/src/JD.Efcpt.Build.Definitions/BuildTransitiveTargetsFactory.cs new file mode 100644 index 0000000..1e7b13b --- /dev/null +++ b/src/JD.Efcpt.Build.Definitions/BuildTransitiveTargetsFactory.cs @@ -0,0 +1,817 @@ +using JD.Efcpt.Build.Definitions.Constants; +using JD.Efcpt.Build.Definitions.Registry; +using JD.Efcpt.Build.Definitions.Shared; +using JD.MSBuild.Fluent; +using JD.MSBuild.Fluent.Common; +using JD.MSBuild.Fluent.Fluent; +using JD.MSBuild.Fluent.Typed; + +namespace JD.Efcpt.Build.Definitions; + +/// +/// MSBuild package definition scaffolded from JD.Efcpt.Build.xml +/// +public static class BuildTransitiveTargetsFactory +{ + public static PackageDefinition Create() + { + return Package.Define("JD.Efcpt.Build") + .Props(p => + { + p.PropertyGroup(null, SharedPropertyGroups.ConfigureNullableReferenceTypes); + p.PropertyGroup(null, SharedPropertyGroups.ConfigureTaskAssemblyResolution); + }) + .Targets(t => + { + t.PropertyGroup(null, SharedPropertyGroups.ConfigureNullableReferenceTypes); + t.PropertyGroup(null, SharedPropertyGroups.ConfigureTaskAssemblyResolution); + + t.Target("_EfcptDetectSqlProject", target => + { + target.BeforeTargets("BeforeBuild", "BeforeRebuild"); + target.Task("DetectSqlProject", task => + { + task.Param("ProjectPath", "$(MSBuildProjectFullPath)"); + task.Param("SqlServerVersion", "$(SqlServerVersion)"); + task.Param("DSP", "$(DSP)"); + task.OutputProperty(); + }); + target.PropertyGroup("'$(_EfcptIsSqlProject)' == ''", group => + { + group.Property("_EfcptIsSqlProject", "false"); + }); + }); + t.Target("_EfcptLogTaskAssemblyInfo", target => + { + target.BeforeTargets(new EfcptResolveInputsTarget(), new EfcptResolveInputsForDirectDacpacTarget()); + target.Condition("'$(EfcptEnabled)' == 'true' and '$(EfcptLogVerbosity)' == 'detailed'"); + target.Message("EFCPT Task Assembly Selection:", "high"); + target.Message(" MSBuildRuntimeType: $(MSBuildRuntimeType)", "high"); + target.Message(" MSBuildVersion: $(MSBuildVersion)", "high"); + target.Message(" Selected TasksFolder: $(_EfcptTasksFolder)", "high"); + target.Message(" TaskAssembly Path: $(_EfcptTaskAssembly)", "high"); + target.Message(" TaskAssembly Exists: $([System.IO.File]::Exists('$(_EfcptTaskAssembly)'))", "high"); + }); + + UsingTasksRegistry.RegisterAll(t); + + t.Target("_EfcptInitializeProfiling", target => + { + target.BeforeTargets("_EfcptDetectSqlProject"); + target.Condition("'$(EfcptEnabled)' == 'true'"); + target.Task("InitializeBuildProfiling", task => + { + task.Param("EnableProfiling", "$(EfcptEnableProfiling)"); + task.Param("ProjectPath", "$(MSBuildProjectFullPath)"); + task.Param("ProjectName", "$(MSBuildProjectName)"); + task.Param("TargetFramework", "$(TargetFramework)"); + task.Param("Configuration", "$(Configuration)"); + task.Param("ConfigPath", "$(_EfcptResolvedConfig)"); + task.Param("RenamingPath", "$(_EfcptResolvedRenaming)"); + task.Param("TemplateDir", "$(_EfcptResolvedTemplateDir)"); + task.Param("SqlProjectPath", "$(_EfcptSqlProj)"); + task.Param("DacpacPath", "$(_EfcptDacpacPath)"); + task.Param("Provider", "$(EfcptProvider)"); + }); + }); + t.Target("_EfcptCheckForUpdates", target => + { + target.BeforeTargets("Build"); + target.Condition("'$(EfcptCheckForUpdates)' == 'true' and '$(EfcptSdkVersion)' != ''"); + target.Task("CheckSdkVersion", task => + { + task.Param("CurrentVersion", "$(EfcptSdkVersion)"); + task.Param("PackageId", "JD.Efcpt.Sdk"); + task.Param("CacheHours", "$(EfcptUpdateCheckCacheHours)"); + task.Param("ForceCheck", "$(EfcptForceUpdateCheck)"); + task.Param("WarningLevel", "$(EfcptSdkVersionWarningLevel)"); + task.OutputProperty(); + task.OutputProperty(); + }); + }); + t.Target( target => + { + target.Condition("'$(EfcptEnabled)' == 'true' and '$(_EfcptIsSqlProject)' == 'true'"); + }); + t.Target( target => + { + target.DependsOnTargets("BeforeSqlProjGeneration"); + target.Condition("'$(EfcptEnabled)' == 'true' and '$(_EfcptIsSqlProject)' == 'true'"); + target.Error("SqlProj generation requires a connection string. Set EfcptConnectionString, EfcptAppSettings, or EfcptAppConfig.", "'$(EfcptConnectionString)' == '' and '$(EfcptAppSettings)' == '' and '$(EfcptAppConfig)' == ''"); + target.Message("Querying database schema for fingerprinting...", "high"); + target.Task("QuerySchemaMetadata", task => + { + task.Param("ConnectionString", "$(EfcptConnectionString)"); + task.Param("OutputDir", "$(EfcptOutput)"); + task.Param("Provider", "$(EfcptProvider)"); + task.Param("LogVerbosity", "$(EfcptLogVerbosity)"); + task.OutputProperty(); + }); + target.Message("Database schema fingerprint: $(_EfcptSchemaFingerprint)", "normal"); + }); + t.Target( target => + { + target.DependsOnTargets("EfcptQueryDatabaseSchemaForSqlProj"); + target.Condition("'$(EfcptEnabled)' == 'true' and '$(_EfcptIsSqlProject)' == 'true'"); + target.PropertyGroup(null, group => + { + group.Property("_EfcptScriptsDir", "$(EfcptSqlScriptsDir)"); + }); + target.Message("Extracting database schema to SQL scripts in SQL project: $(_EfcptScriptsDir)", "high"); + target.ItemGroup(null, group => + { + group.Include("_EfcptGeneratedScripts", "$(_EfcptScriptsDir)**\\*.sql"); + }); + target.Task("Delete", task => + { + task.Param("Files", "@(_EfcptGeneratedScripts)"); + }, "'@(_EfcptGeneratedScripts)' != ''"); + target.Task("RunSqlPackage", task => + { + task.Param("ToolVersion", "$(EfcptSqlPackageToolVersion)"); + task.Param("ToolRestore", "$(EfcptSqlPackageToolRestore)"); + task.Param("ToolPath", "$(EfcptSqlPackageToolPath)"); + task.Param("DotNetExe", "$(EfcptDotNetExe)"); + task.Param("WorkingDirectory", "$(EfcptOutput)"); + task.Param("ConnectionString", "$(EfcptConnectionString)"); + task.Param("TargetDirectory", "$(_EfcptScriptsDir)"); + task.Param("ExtractTarget", "SchemaObjectType"); + task.Param("TargetFramework", "$(TargetFramework)"); + task.Param("LogVerbosity", "$(EfcptLogVerbosity)"); + task.OutputProperty(); + }); + target.Message("Extracted SQL scripts to: $(_EfcptExtractedScriptsPath)", "high"); + }); + t.Target( target => + { + target.DependsOnTargets("EfcptExtractDatabaseSchemaToScripts"); + target.Condition("'$(EfcptEnabled)' == 'true' and '$(_EfcptIsSqlProject)' == 'true'"); + target.Message("Adding auto-generation warnings to SQL files...", "high"); + target.PropertyGroup(null, group => + { + group.Property("_EfcptDatabaseName", "$([System.Text.RegularExpressions.Regex]::Match($(EfcptConnectionString), 'Database\\s*=\\s*\\\"?([^;\"]+)\\\"?').Groups[1].Value)"); + group.Property("_EfcptDatabaseName", "$([System.Text.RegularExpressions.Regex]::Match($(EfcptConnectionString), 'Initial Catalog\\s*=\\s*\\\"?([^;\"]+)\\\"?').Groups[1].Value)"); + }); + target.Task("AddSqlFileWarnings", task => + { + task.Param("ScriptsDirectory", "$(_EfcptScriptsDir)"); + task.Param("DatabaseName", "$(_EfcptDatabaseName)"); + task.Param("LogVerbosity", "$(EfcptLogVerbosity)"); + }); + }); + t.Target( target => + { + target.BeforeTargets("Build"); + target.DependsOnTargets("EfcptAddSqlFileWarnings"); + target.Condition("'$(EfcptEnabled)' == 'true' and '$(_EfcptIsSqlProject)' == 'true'"); + target.Message("_EfcptIsSqlProject: $(_EfcptIsSqlProject)", "high"); + target.Message("SQL script generation complete. SQL project will build to DACPAC.", "high"); + }); + t.Target( target => + { + target.Condition("'$(EfcptEnabled)' == 'true' and '$(_EfcptIsSqlProject)' != 'true' and '$(EfcptDacpac)' == ''"); + target.Task("ResolveSqlProjAndInputs", task => + { + task.Param("ProjectFullPath", "$(MSBuildProjectFullPath)"); + task.Param("ProjectDirectory", "$(MSBuildProjectDirectory)"); + task.Param("Configuration", "$(Configuration)"); + task.Param("ProjectReferences", "@(ProjectReference)"); + task.Param("SqlProjOverride", "$(EfcptSqlProj)"); + task.Param("ConfigOverride", "$(EfcptConfig)"); + task.Param("RenamingOverride", "$(EfcptRenaming)"); + task.Param("TemplateDirOverride", "$(EfcptTemplateDir)"); + task.Param("SolutionDir", "$(EfcptSolutionDir)"); + task.Param("SolutionPath", "$(EfcptSolutionPath)"); + task.Param("ProbeSolutionDir", "$(EfcptProbeSolutionDir)"); + task.Param("OutputDir", "$(EfcptOutput)"); + task.Param("DefaultsRoot", "$(MSBuildThisFileDirectory)Defaults"); + task.Param("DumpResolvedInputs", "$(EfcptDumpResolvedInputs)"); + task.Param("EfcptConnectionString", "$(EfcptConnectionString)"); + task.Param("EfcptAppSettings", "$(EfcptAppSettings)"); + task.Param("EfcptAppConfig", "$(EfcptAppConfig)"); + task.Param("EfcptConnectionStringName", "$(EfcptConnectionStringName)"); + task.Param("AutoDetectWarningLevel", "$(EfcptAutoDetectWarningLevel)"); + task.OutputProperty(); + task.OutputProperty(); + task.OutputProperty(); + task.OutputProperty(); + task.OutputProperty(); + task.OutputProperty(); + task.OutputProperty(); + }); + }); + t.Target( target => + { + target.Condition("'$(EfcptEnabled)' == 'true' and '$(EfcptDacpac)' != ''"); + target.PropertyGroup(null, group => + { + group.Property("_EfcptResolvedConfig", "$(MSBuildProjectDirectory)\\$(EfcptConfig)"); + group.Property("_EfcptResolvedConfig", "$(MSBuildThisFileDirectory)Defaults\\efcpt-config.json"); + group.Property("_EfcptResolvedRenaming", "$(MSBuildProjectDirectory)\\$(EfcptRenaming)"); + group.Property("_EfcptResolvedRenaming", "$(MSBuildThisFileDirectory)Defaults\\efcpt.renaming.json"); + group.Property("_EfcptResolvedTemplateDir", "$(MSBuildProjectDirectory)\\$(EfcptTemplateDir)"); + group.Property("_EfcptResolvedTemplateDir", "$(MSBuildThisFileDirectory)Defaults\\Template"); + group.Property("_EfcptIsUsingDefaultConfig", "true"); + group.Property("_EfcptUseConnectionString", "false"); + }); + target.Task("MakeDir", task => + { + task.Param("Directories", "$(EfcptOutput)"); + }); + }); + t.Target( target => + { + target.BeforeTargets(new EfcptStageInputsTarget()); + target.AfterTargets(new EfcptResolveInputsTarget()); + target.Condition("'$(EfcptEnabled)' == 'true' and '$(_EfcptUseConnectionString)' == 'true'"); + target.Task("QuerySchemaMetadata", task => + { + task.Param("ConnectionString", "$(_EfcptResolvedConnectionString)"); + task.Param("OutputDir", "$(EfcptOutput)"); + task.Param("Provider", "$(EfcptProvider)"); + task.Param("LogVerbosity", "$(EfcptLogVerbosity)"); + task.OutputProperty(); + }); + }); + t.Target( target => + { + target.DependsOnTargets("EfcptResolveInputs;EfcptResolveInputsForDirectDacpac"); + target.Condition("'$(EfcptEnabled)' == 'true' and '$(_EfcptUseConnectionString)' != 'true' and '$(EfcptDacpac)' != ''"); + target.PropertyGroup(null, group => + { + group.Property("_EfcptDacpacPath", "$(EfcptDacpac)"); + group.Property("_EfcptDacpacPath", "$([System.IO.Path]::GetFullPath($([System.IO.Path]::Combine('$(MSBuildProjectDirectory)', '$(EfcptDacpac)'))))"); + group.Property("_EfcptUseDirectDacpac", "true"); + }); + target.Error("EfcptDacpac was specified but the file does not exist: $(_EfcptDacpacPath)", "!Exists('$(_EfcptDacpacPath)')"); + target.Message("Using pre-built DACPAC: $(_EfcptDacpacPath)", "high"); + }); + t.Target( target => + { + target.DependsOnTargets("EfcptResolveInputs;EfcptUseDirectDacpac"); + target.Condition("'$(EfcptEnabled)' == 'true'"); + target.Message("Building SQL project: $(_EfcptSqlProj)", "normal", "'$(_EfcptUseConnectionString)' != 'true' and '$(_EfcptUseDirectDacpac)' != 'true' and '$(_EfcptSqlProj)' != ''"); + target.Task("MSBuild", task => + { + task.Param("Projects", "$(_EfcptSqlProj)"); + task.Param("Targets", "Build"); + task.Param("Properties", "Configuration=$(Configuration)"); + task.Param("BuildInParallel", "false"); + }, "'$(_EfcptUseConnectionString)' != 'true' and '$(_EfcptUseDirectDacpac)' != 'true' and '$(_EfcptSqlProj)' != ''"); + }); + t.Target( target => + { + target.DependsOnTargets("EfcptResolveInputs;EfcptUseDirectDacpac;EfcptBuildSqlProj"); + target.Condition("'$(EfcptEnabled)' == 'true'"); + target.Task("EnsureDacpacBuilt", task => + { + task.Param("SqlProjPath", "$(_EfcptSqlProj)"); + task.Param("Configuration", "$(Configuration)"); + task.Param("MsBuildExe", "$(MSBuildBinPath)msbuild.exe"); + task.Param("DotNetExe", "$(EfcptDotNetExe)"); + task.Param("LogVerbosity", "$(EfcptLogVerbosity)"); + task.OutputProperty(); + }, "'$(_EfcptUseConnectionString)' != 'true' and '$(_EfcptUseDirectDacpac)' != 'true' and '$(_EfcptIsSqlProject)' != 'true'"); + }); + t.Target( target => + { + target.DependsOnTargets("EfcptResolveInputs;EfcptEnsureDacpac;EfcptUseDirectDacpac"); + target.Condition("'$(EfcptEnabled)' == 'true' and '$(_EfcptIsSqlProject)' != 'true'"); + target.Task("ResolveDbContextName", task => + { + task.Param("ExplicitDbContextName", "$(EfcptConfigDbContextName)"); + task.Param("SqlProjPath", "$(_EfcptSqlProj)"); + task.Param("DacpacPath", "$(_EfcptDacpacPath)"); + task.Param("ConnectionString", "$(_EfcptResolvedConnectionString)"); + task.Param("UseConnectionStringMode", "$(_EfcptUseConnectionString)"); + task.Param("LogVerbosity", "$(EfcptLogVerbosity)"); + task.OutputProperty(); + }); + target.PropertyGroup(null, group => + { + group.Property( "$(_EfcptResolvedDbContextName)"); + }); + }); + t.Target( target => + { + target.DependsOnTargets("EfcptResolveInputs;EfcptEnsureDacpac;EfcptUseDirectDacpac;EfcptResolveDbContextName"); + target.Condition("'$(EfcptEnabled)' == 'true' and '$(_EfcptIsSqlProject)' != 'true'"); + target.Task("StageEfcptInputs", task => + { + task.Param("OutputDir", "$(EfcptOutput)"); + task.Param("ProjectDirectory", "$(MSBuildProjectDirectory)"); + task.Param("ConfigPath", "$(_EfcptResolvedConfig)"); + task.Param("RenamingPath", "$(_EfcptResolvedRenaming)"); + task.Param("TemplateDir", "$(_EfcptResolvedTemplateDir)"); + task.Param("TemplateOutputDir", "$(EfcptGeneratedDir)"); + task.Param("TargetFramework", "$(TargetFramework)"); + task.Param("LogVerbosity", "$(EfcptLogVerbosity)"); + task.OutputProperty(); + task.OutputProperty(); + task.OutputProperty(); + }); + }); + t.Target( target => + { + target.DependsOnTargets("EfcptStageInputs"); + target.Condition("'$(EfcptEnabled)' == 'true' and '$(_EfcptIsSqlProject)' != 'true'"); + target.Task("ApplyConfigOverrides", task => + { + task.Param("StagedConfigPath", "$(_EfcptStagedConfig)"); + task.Param("ApplyOverrides", "$(EfcptApplyMsBuildOverrides)"); + task.Param("IsUsingDefaultConfig", "$(_EfcptIsUsingDefaultConfig)"); + task.Param("LogVerbosity", "$(EfcptLogVerbosity)"); + task.Param("RootNamespace", "$(EfcptConfigRootNamespace)"); + task.Param("DbContextName", "$(EfcptConfigDbContextName)"); + task.Param("DbContextNamespace", "$(EfcptConfigDbContextNamespace)"); + task.Param("ModelNamespace", "$(EfcptConfigModelNamespace)"); + task.Param("OutputPath", "$(EfcptConfigOutputPath)"); + task.Param("DbContextOutputPath", "$(EfcptConfigDbContextOutputPath)"); + task.Param("SplitDbContext", "$(EfcptConfigSplitDbContext)"); + task.Param("UseSchemaFolders", "$(EfcptConfigUseSchemaFolders)"); + task.Param("UseSchemaNamespaces", "$(EfcptConfigUseSchemaNamespaces)"); + task.Param("EnableOnConfiguring", "$(EfcptConfigEnableOnConfiguring)"); + task.Param("GenerationType", "$(EfcptConfigGenerationType)"); + task.Param("UseDatabaseNames", "$(EfcptConfigUseDatabaseNames)"); + task.Param("UseDataAnnotations", "$(EfcptConfigUseDataAnnotations)"); + task.Param("UseNullableReferenceTypes", "$(EfcptConfigUseNullableReferenceTypes)"); + task.Param("UseInflector", "$(EfcptConfigUseInflector)"); + task.Param("UseLegacyInflector", "$(EfcptConfigUseLegacyInflector)"); + task.Param("UseManyToManyEntity", "$(EfcptConfigUseManyToManyEntity)"); + task.Param("UseT4", "$(EfcptConfigUseT4)"); + task.Param("UseT4Split", "$(EfcptConfigUseT4Split)"); + task.Param("RemoveDefaultSqlFromBool", "$(EfcptConfigRemoveDefaultSqlFromBool)"); + task.Param("SoftDeleteObsoleteFiles", "$(EfcptConfigSoftDeleteObsoleteFiles)"); + task.Param("DiscoverMultipleResultSets", "$(EfcptConfigDiscoverMultipleResultSets)"); + task.Param("UseAlternateResultSetDiscovery", "$(EfcptConfigUseAlternateResultSetDiscovery)"); + task.Param("T4TemplatePath", "$(EfcptConfigT4TemplatePath)"); + task.Param("UseNoNavigations", "$(EfcptConfigUseNoNavigations)"); + task.Param("MergeDacpacs", "$(EfcptConfigMergeDacpacs)"); + task.Param("RefreshObjectLists", "$(EfcptConfigRefreshObjectLists)"); + task.Param("GenerateMermaidDiagram", "$(EfcptConfigGenerateMermaidDiagram)"); + task.Param("UseDecimalAnnotationForSprocs", "$(EfcptConfigUseDecimalAnnotationForSprocs)"); + task.Param("UsePrefixNavigationNaming", "$(EfcptConfigUsePrefixNavigationNaming)"); + task.Param("UseDatabaseNamesForRoutines", "$(EfcptConfigUseDatabaseNamesForRoutines)"); + task.Param("UseInternalAccessForRoutines", "$(EfcptConfigUseInternalAccessForRoutines)"); + task.Param("UseDateOnlyTimeOnly", "$(EfcptConfigUseDateOnlyTimeOnly)"); + task.Param("UseHierarchyId", "$(EfcptConfigUseHierarchyId)"); + task.Param("UseSpatial", "$(EfcptConfigUseSpatial)"); + task.Param("UseNodaTime", "$(EfcptConfigUseNodaTime)"); + task.Param("PreserveCasingWithRegex", "$(EfcptConfigPreserveCasingWithRegex)"); + }); + }); + t.Target( target => + { + target.DependsOnTargets("EfcptApplyConfigOverrides"); + target.Condition("'$(EfcptEnabled)' == 'true' and '$(_EfcptIsSqlProject)' != 'true'"); + target.Task("SerializeConfigProperties", task => + { + task.Param("RootNamespace", "$(EfcptConfigRootNamespace)"); + task.Param("DbContextName", "$(EfcptConfigDbContextName)"); + task.Param("DbContextNamespace", "$(EfcptConfigDbContextNamespace)"); + task.Param("ModelNamespace", "$(EfcptConfigModelNamespace)"); + task.Param("OutputPath", "$(EfcptConfigOutputPath)"); + task.Param("DbContextOutputPath", "$(EfcptConfigDbContextOutputPath)"); + task.Param("SplitDbContext", "$(EfcptConfigSplitDbContext)"); + task.Param("UseSchemaFolders", "$(EfcptConfigUseSchemaFolders)"); + task.Param("UseSchemaNamespaces", "$(EfcptConfigUseSchemaNamespaces)"); + task.Param("EnableOnConfiguring", "$(EfcptConfigEnableOnConfiguring)"); + task.Param("GenerationType", "$(EfcptConfigGenerationType)"); + task.Param("UseDatabaseNames", "$(EfcptConfigUseDatabaseNames)"); + task.Param("UseDataAnnotations", "$(EfcptConfigUseDataAnnotations)"); + task.Param("UseNullableReferenceTypes", "$(EfcptConfigUseNullableReferenceTypes)"); + task.Param("UseInflector", "$(EfcptConfigUseInflector)"); + task.Param("UseLegacyInflector", "$(EfcptConfigUseLegacyInflector)"); + task.Param("UseManyToManyEntity", "$(EfcptConfigUseManyToManyEntity)"); + task.Param("UseT4", "$(EfcptConfigUseT4)"); + task.Param("UseT4Split", "$(EfcptConfigUseT4Split)"); + task.Param("RemoveDefaultSqlFromBool", "$(EfcptConfigRemoveDefaultSqlFromBool)"); + task.Param("SoftDeleteObsoleteFiles", "$(EfcptConfigSoftDeleteObsoleteFiles)"); + task.Param("DiscoverMultipleResultSets", "$(EfcptConfigDiscoverMultipleResultSets)"); + task.Param("UseAlternateResultSetDiscovery", "$(EfcptConfigUseAlternateResultSetDiscovery)"); + task.Param("T4TemplatePath", "$(EfcptConfigT4TemplatePath)"); + task.Param("UseNoNavigations", "$(EfcptConfigUseNoNavigations)"); + task.Param("MergeDacpacs", "$(EfcptConfigMergeDacpacs)"); + task.Param("RefreshObjectLists", "$(EfcptConfigRefreshObjectLists)"); + task.Param("GenerateMermaidDiagram", "$(EfcptConfigGenerateMermaidDiagram)"); + task.Param("UseDecimalAnnotationForSprocs", "$(EfcptConfigUseDecimalAnnotationForSprocs)"); + task.Param("UsePrefixNavigationNaming", "$(EfcptConfigUsePrefixNavigationNaming)"); + task.Param("UseDatabaseNamesForRoutines", "$(EfcptConfigUseDatabaseNamesForRoutines)"); + task.Param("UseInternalAccessForRoutines", "$(EfcptConfigUseInternalAccessForRoutines)"); + task.Param("UseDateOnlyTimeOnly", "$(EfcptConfigUseDateOnlyTimeOnly)"); + task.Param("UseHierarchyId", "$(EfcptConfigUseHierarchyId)"); + task.Param("UseSpatial", "$(EfcptConfigUseSpatial)"); + task.Param("UseNodaTime", "$(EfcptConfigUseNodaTime)"); + task.Param("PreserveCasingWithRegex", "$(EfcptConfigPreserveCasingWithRegex)"); + task.OutputProperty(); + }); + }); + t.Target( target => + { + target.DependsOnTargets("EfcptSerializeConfigProperties"); + target.Condition("'$(EfcptEnabled)' == 'true' and '$(_EfcptIsSqlProject)' != 'true'"); + target.Task("ComputeFingerprint", task => + { + task.Param("DacpacPath", "$(_EfcptDacpacPath)"); + task.Param("SchemaFingerprint", "$(_EfcptSchemaFingerprint)"); + task.Param("UseConnectionStringMode", "$(_EfcptUseConnectionString)"); + task.Param("ConfigPath", "$(_EfcptStagedConfig)"); + task.Param("RenamingPath", "$(_EfcptStagedRenaming)"); + task.Param("TemplateDir", "$(_EfcptStagedTemplateDir)"); + task.Param("FingerprintFile", "$(EfcptFingerprintFile)"); + task.Param("ToolVersion", "$(EfcptToolVersion)"); + task.Param("GeneratedDir", "$(EfcptGeneratedDir)"); + task.Param("DetectGeneratedFileChanges", "$(EfcptDetectGeneratedFileChanges)"); + task.Param("ConfigPropertyOverrides", "$(_EfcptSerializedConfigProperties)"); + task.Param("LogVerbosity", "$(EfcptLogVerbosity)"); + task.OutputProperty(); + task.OutputProperty(); + }); + }); + t.Target( target => + { + target.DependsOnTargets("EfcptComputeFingerprint"); + target.Condition("'$(EfcptEnabled)' == 'true' and '$(_EfcptIsSqlProject)' != 'true'"); + }); + t.Target( target => + { + target.BeforeTargets("CoreCompile"); + target.DependsOnTargets("BeforeEfcptGeneration"); + target.Inputs("$(_EfcptDacpacPath);$(_EfcptStagedConfig);$(_EfcptStagedRenaming)"); + target.Outputs("$(EfcptStampFile)"); + target.Condition("'$(EfcptEnabled)' == 'true' and '$(_EfcptIsSqlProject)' != 'true' and ('$(_EfcptFingerprintChanged)' == 'true' or !Exists('$(EfcptStampFile)'))"); + target.Task("MakeDir", task => + { + task.Param("Directories", "$(EfcptGeneratedDir)"); + }); + target.Task("RunEfcpt", task => + { + task.Param("ToolMode", "$(EfcptToolMode)"); + task.Param("ToolPackageId", "$(EfcptToolPackageId)"); + task.Param("ToolVersion", "$(EfcptToolVersion)"); + task.Param("ToolRestore", "$(EfcptToolRestore)"); + task.Param("ToolCommand", "$(EfcptToolCommand)"); + task.Param("ToolPath", "$(EfcptToolPath)"); + task.Param("DotNetExe", "$(EfcptDotNetExe)"); + task.Param("WorkingDirectory", "$(EfcptOutput)"); + task.Param("DacpacPath", "$(_EfcptDacpacPath)"); + task.Param("ConnectionString", "$(_EfcptResolvedConnectionString)"); + task.Param("UseConnectionStringMode", "$(_EfcptUseConnectionString)"); + task.Param("Provider", "$(EfcptProvider)"); + task.Param("ConfigPath", "$(_EfcptStagedConfig)"); + task.Param("RenamingPath", "$(_EfcptStagedRenaming)"); + task.Param("TemplateDir", "$(_EfcptStagedTemplateDir)"); + task.Param("OutputDir", "$(EfcptGeneratedDir)"); + task.Param("TargetFramework", "$(TargetFramework)"); + task.Param("ProjectPath", "$(MSBuildProjectFullPath)"); + task.Param("LogVerbosity", "$(EfcptLogVerbosity)"); + }); + target.Task("RenameGeneratedFiles", task => + { + task.Param("GeneratedDir", "$(EfcptGeneratedDir)"); + task.Param("LogVerbosity", "$(EfcptLogVerbosity)"); + }); + target.Task("WriteLinesToFile", task => + { + task.Param("File", "$(EfcptStampFile)"); + task.Param("Lines", "$(_EfcptFingerprint)"); + task.Param("Overwrite", "true"); + }); + }); + t.Target( target => + { + target.AfterTargets(new EfcptGenerateModelsTarget()); + target.Condition("'$(EfcptEnabled)' == 'true' and '$(_EfcptIsSqlProject)' != 'true'"); + }); + t.Target( target => + { + target.DependsOnTargets("EfcptGenerateModels"); + target.Condition("'$(EfcptEnabled)' == 'true' and '$(_EfcptIsSqlProject)' != 'true' and '$(EfcptSplitOutputs)' == 'true'"); + target.PropertyGroup(null, group => + { + group.Property("_EfcptDataProjectPath", "$(EfcptDataProject)"); + group.Property("_EfcptDataProjectPath", "$([System.IO.Path]::GetFullPath($([System.IO.Path]::Combine('$(MSBuildProjectDirectory)', '$(EfcptDataProject)'))))"); + }); + target.Error("EfcptSplitOutputs is enabled but EfcptDataProject is not set. Please specify the path to your Data project: ..\\MyProject.Data\\MyProject.Data.csproj", "'$(_EfcptDataProjectPath)' == ''"); + target.Error("EfcptDataProject was specified but the file does not exist: $(_EfcptDataProjectPath)", "!Exists('$(_EfcptDataProjectPath)')"); + target.PropertyGroup(null, group => + { + group.Property("_EfcptDataProjectDir", "$([System.IO.Path]::GetDirectoryName('$(_EfcptDataProjectPath)'))\\"); + group.Property("_EfcptDataDestDir", "$(_EfcptDataProjectDir)$(EfcptDataProjectOutputSubdir)"); + }); + target.Message("Split outputs enabled. DbContext and configurations will be copied to: $(_EfcptDataDestDir)", "high"); + }); + t.Target( target => + { + target.DependsOnTargets("EfcptValidateSplitOutputs"); + target.Condition("'$(EfcptEnabled)' == 'true' and '$(_EfcptIsSqlProject)' != 'true' and '$(EfcptSplitOutputs)' == 'true'"); + target.ItemGroup(null, group => + { + group.Include("_EfcptDbContextFiles", "$(EfcptGeneratedDir)*.g.cs"); + }); + target.ItemGroup(null, group => + { + group.Include("_EfcptConfigurationFiles", "$(EfcptGeneratedDir)*Configuration.g.cs"); + group.Include("_EfcptConfigurationFiles", "$(EfcptGeneratedDir)Configurations\\**\\*.g.cs"); + }); + target.PropertyGroup(null, group => + { + group.Property("_EfcptHasFilesToCopy", "true"); + }); + target.Task("RemoveDir", task => + { + task.Param("Directories", "$(_EfcptDataDestDir)"); + }, "'$(_EfcptHasFilesToCopy)' == 'true' and Exists('$(_EfcptDataDestDir)')"); + target.Task("MakeDir", task => + { + task.Param("Directories", "$(_EfcptDataDestDir)"); + }, "'$(_EfcptHasFilesToCopy)' == 'true'"); + target.Task("MakeDir", task => + { + task.Param("Directories", "$(_EfcptDataDestDir)Configurations"); + }, "'@(_EfcptConfigurationFiles)' != ''"); + target.Task("Copy", task => + { + task.Param("SourceFiles", "@(_EfcptDbContextFiles)"); + task.Param("DestinationFolder", "$(_EfcptDataDestDir)"); + task.Param("SkipUnchangedFiles", "true"); + task.OutputItem("CopiedFiles", "_EfcptCopiedDataFiles"); + }, "'@(_EfcptDbContextFiles)' != ''"); + target.Task("Copy", task => + { + task.Param("SourceFiles", "@(_EfcptConfigurationFiles)"); + task.Param("DestinationFolder", "$(_EfcptDataDestDir)Configurations"); + task.Param("SkipUnchangedFiles", "true"); + task.OutputItem("CopiedFiles", "_EfcptCopiedDataFiles"); + }, "'@(_EfcptConfigurationFiles)' != ''"); + target.Message("Copied @(_EfcptCopiedDataFiles->Count()) data files to Data project: $(_EfcptDataDestDir)", "high", "'@(_EfcptCopiedDataFiles)' != ''"); + target.Message("Split outputs: No new files to copy (generation was skipped)", "normal", "'$(_EfcptHasFilesToCopy)' != 'true'"); + target.Task("Delete", task => + { + task.Param("Files", "@(_EfcptDbContextFiles)"); + }, "'@(_EfcptDbContextFiles)' != ''"); + target.Task("Delete", task => + { + task.Param("Files", "@(_EfcptConfigurationFiles)"); + }, "'@(_EfcptConfigurationFiles)' != ''"); + target.Message("Removed DbContext and configuration files from Models project", "normal", "'$(_EfcptHasFilesToCopy)' == 'true'"); + }); + t.Target( target => + { + target.BeforeTargets("CoreCompile"); + target.DependsOnTargets("EfcptResolveInputs;EfcptUseDirectDacpac;EfcptEnsureDacpac;EfcptStageInputs;EfcptComputeFingerprint;EfcptGenerateModels;EfcptCopyDataToDataProject"); + target.Condition("'$(EfcptEnabled)' == 'true' and '$(_EfcptIsSqlProject)' != 'true'"); + target.ItemGroup(null, group => + { + group.Include("Compile", "$(EfcptGeneratedDir)Models\\**\\*.g.cs", null, "'$(EfcptSplitOutputs)' == 'true'"); + group.Include("Compile", "$(EfcptGeneratedDir)**\\*.g.cs", null, "'$(EfcptSplitOutputs)' != 'true'"); + }); + }); + t.Target( target => + { + target.BeforeTargets("CoreCompile"); + target.Condition("'$(EfcptExternalDataDir)' != '' and Exists('$(EfcptExternalDataDir)')"); + target.ItemGroup(null, group => + { + group.Include("Compile", "$(EfcptExternalDataDir)**\\*.g.cs"); + }); + target.Message("Including external data files from: $(EfcptExternalDataDir)", "normal"); + }); + t.Target( target => + { + target.AfterTargets("Clean"); + target.Condition("'$(EfcptEnabled)' == 'true'"); + target.Message("Cleaning efcpt output: $(EfcptOutput)", "normal"); + target.Task("RemoveDir", task => + { + task.Param("Directories", "$(EfcptOutput)"); + }, "Exists('$(EfcptOutput)')"); + }); + t.Target("_EfcptFinalizeProfiling", target => + { + target.AfterTargets("Build"); + target.Condition("'$(EfcptEnabled)' == 'true' and '$(EfcptEnableProfiling)' == 'true'"); + target.Task("FinalizeBuildProfiling", task => + { + task.Param("ProjectPath", "$(MSBuildProjectFullPath)"); + task.Param("OutputPath", "$(EfcptProfilingOutput)"); + task.Param("BuildSucceeded", "true"); + }); + }); + }) + .Build(); + } + + // Strongly-typed names + public readonly struct EfcptDacpacPath : IMsBuildPropertyName + { + public string Name => "_EfcptDacpacPath"; + } + public readonly struct EfcptDatabaseName : IMsBuildPropertyName + { + public string Name => "_EfcptDatabaseName"; + } + public readonly struct EfcptDataDestDir : IMsBuildPropertyName + { + public string Name => "_EfcptDataDestDir"; + } + public readonly struct EfcptDataProjectDir : IMsBuildPropertyName + { + public string Name => "_EfcptDataProjectDir"; + } + public readonly struct EfcptDataProjectPath : IMsBuildPropertyName + { + public string Name => "_EfcptDataProjectPath"; + } + public readonly struct EfcptHasFilesToCopy : IMsBuildPropertyName + { + public string Name => "_EfcptHasFilesToCopy"; + } + public readonly struct EfcptIsSqlProject : IMsBuildPropertyName + { + public string Name => "_EfcptIsSqlProject"; + } + public readonly struct EfcptIsUsingDefaultConfig : IMsBuildPropertyName + { + public string Name => "_EfcptIsUsingDefaultConfig"; + } + public readonly struct EfcptResolvedConfig : IMsBuildPropertyName + { + public string Name => "_EfcptResolvedConfig"; + } + public readonly struct EfcptResolvedRenaming : IMsBuildPropertyName + { + public string Name => "_EfcptResolvedRenaming"; + } + public readonly struct EfcptResolvedTemplateDir : IMsBuildPropertyName + { + public string Name => "_EfcptResolvedTemplateDir"; + } + public readonly struct EfcptScriptsDir : IMsBuildPropertyName + { + public string Name => "_EfcptScriptsDir"; + } + public readonly struct EfcptTaskAssembly : IMsBuildPropertyName + { + public string Name => "_EfcptTaskAssembly"; + } + public readonly struct EfcptTasksFolder : IMsBuildPropertyName + { + public string Name => "_EfcptTasksFolder"; + } + public readonly struct EfcptUseConnectionString : IMsBuildPropertyName + { + public string Name => "_EfcptUseConnectionString"; + } + public readonly struct EfcptUseDirectDacpac : IMsBuildPropertyName + { + public string Name => "_EfcptUseDirectDacpac"; + } + public readonly struct EfcptConfigDbContextName : IMsBuildPropertyName + { + public string Name => "EfcptConfigDbContextName"; + } + public readonly struct EfcptConfigUseNullableReferenceTypes : IMsBuildPropertyName + { + public string Name => "EfcptConfigUseNullableReferenceTypes"; + } + // Item types: + public readonly struct EfcptConfigurationFilesItem : IMsBuildItemTypeName + { + public string Name => "_EfcptConfigurationFiles"; + } + public readonly struct EfcptDbContextFilesItem : IMsBuildItemTypeName + { + public string Name => "_EfcptDbContextFiles"; + } + public readonly struct EfcptGeneratedScriptsItem : IMsBuildItemTypeName + { + public string Name => "_EfcptGeneratedScripts"; + } + public readonly struct CompileItem : IMsBuildItemTypeName + { + public string Name => "Compile"; + } + public readonly struct EfcptCheckForUpdatesTarget : IMsBuildTargetName + { + public string Name => "_EfcptCheckForUpdates"; + } + public readonly struct EfcptDetectSqlProjectTarget : IMsBuildTargetName + { + public string Name => "_EfcptDetectSqlProject"; + } + public readonly struct EfcptFinalizeProfilingTarget : IMsBuildTargetName + { + public string Name => "_EfcptFinalizeProfiling"; + } + public readonly struct EfcptInitializeProfilingTarget : IMsBuildTargetName + { + public string Name => "_EfcptInitializeProfiling"; + } + public readonly struct EfcptLogTaskAssemblyInfoTarget : IMsBuildTargetName + { + public string Name => "_EfcptLogTaskAssemblyInfo"; + } + public readonly struct AfterEfcptGenerationTarget : IMsBuildTargetName + { + public string Name => "AfterEfcptGeneration"; + } + public readonly struct AfterSqlProjGenerationTarget : IMsBuildTargetName + { + public string Name => "AfterSqlProjGeneration"; + } + public readonly struct BeforeEfcptGenerationTarget : IMsBuildTargetName + { + public string Name => "BeforeEfcptGeneration"; + } + public readonly struct BeforeSqlProjGenerationTarget : IMsBuildTargetName + { + public string Name => "BeforeSqlProjGeneration"; + } + public readonly struct EfcptAddSqlFileWarningsTarget : IMsBuildTargetName + { + public string Name => "EfcptAddSqlFileWarnings"; + } + public readonly struct EfcptAddToCompileTarget : IMsBuildTargetName + { + public string Name => "EfcptAddToCompile"; + } + public readonly struct EfcptApplyConfigOverridesTarget : IMsBuildTargetName + { + public string Name => "EfcptApplyConfigOverrides"; + } + public readonly struct EfcptBuildSqlProjTarget : IMsBuildTargetName + { + public string Name => "EfcptBuildSqlProj"; + } + public readonly struct EfcptCleanTarget : IMsBuildTargetName + { + public string Name => "EfcptClean"; + } + public readonly struct EfcptComputeFingerprintTarget : IMsBuildTargetName + { + public string Name => "EfcptComputeFingerprint"; + } + public readonly struct EfcptCopyDataToDataProjectTarget : IMsBuildTargetName + { + public string Name => "EfcptCopyDataToDataProject"; + } + public readonly struct EfcptEnsureDacpacTarget : IMsBuildTargetName + { + public string Name => "EfcptEnsureDacpac"; + } + public readonly struct EfcptExtractDatabaseSchemaToScriptsTarget : IMsBuildTargetName + { + public string Name => "EfcptExtractDatabaseSchemaToScripts"; + } + public readonly struct EfcptGenerateModelsTarget : IMsBuildTargetName + { + public string Name => "EfcptGenerateModels"; + } + public readonly struct EfcptIncludeExternalDataTarget : IMsBuildTargetName + { + public string Name => "EfcptIncludeExternalData"; + } + public readonly struct EfcptQueryDatabaseSchemaForSqlProjTarget : IMsBuildTargetName + { + public string Name => "EfcptQueryDatabaseSchemaForSqlProj"; + } + public readonly struct EfcptQuerySchemaMetadataTarget : IMsBuildTargetName + { + public string Name => "EfcptQuerySchemaMetadata"; + } + public readonly struct EfcptResolveDbContextNameTarget : IMsBuildTargetName + { + public string Name => "EfcptResolveDbContextName"; + } + public readonly struct EfcptResolveInputsTarget : IMsBuildTargetName + { + public string Name => "EfcptResolveInputs"; + } + public readonly struct EfcptResolveInputsForDirectDacpacTarget : IMsBuildTargetName + { + public string Name => "EfcptResolveInputsForDirectDacpac"; + } + public readonly struct EfcptSerializeConfigPropertiesTarget : IMsBuildTargetName + { + public string Name => "EfcptSerializeConfigProperties"; + } + public readonly struct EfcptStageInputsTarget : IMsBuildTargetName + { + public string Name => "EfcptStageInputs"; + } + public readonly struct EfcptUseDirectDacpacTarget : IMsBuildTargetName + { + public string Name => "EfcptUseDirectDacpac"; + } + public readonly struct EfcptValidateSplitOutputsTarget : IMsBuildTargetName + { + public string Name => "EfcptValidateSplitOutputs"; + } +} + + + + + + diff --git a/src/JD.Efcpt.Build.Definitions/Constants/Conditions.cs b/src/JD.Efcpt.Build.Definitions/Constants/Conditions.cs new file mode 100644 index 0000000..e7d4649 --- /dev/null +++ b/src/JD.Efcpt.Build.Definitions/Constants/Conditions.cs @@ -0,0 +1,84 @@ +namespace JD.Efcpt.Build.Definitions.Constants; + +/// +/// Common MSBuild condition expressions used throughout the build definitions. +/// Provides type-safe, reusable condition strings to eliminate duplication. +/// +public static class Conditions +{ + /// + /// Checks if EFCPT is enabled for the project. + /// + public const string EfcptEnabled = "'$(EfcptEnabled)' == 'true'"; + + /// + /// Checks if the current project is a SQL database project. + /// + public const string IsSqlProject = "'$(_EfcptIsSqlProject)' == 'true'"; + + /// + /// Checks if the current project is NOT a SQL database project. + /// + public const string IsNotSqlProject = "'$(_EfcptIsSqlProject)' != 'true'"; + + /// + /// Checks if connection string mode is being used. + /// + public const string UseConnectionString = "'$(_EfcptUseConnectionString)' == 'true'"; + + /// + /// Checks if direct DACPAC mode is being used. + /// + public const string UseDirectDacpac = "'$(_EfcptUseDirectDacpac)' == 'true'"; + + /// + /// Checks if no DACPAC path is specified. + /// + public const string NoDacpac = "'$(EfcptDacpac)' == ''"; + + /// + /// Checks if split outputs mode is enabled. + /// + public const string SplitOutputs = "'$(EfcptSplitOutputs)' == 'true'"; + + /// + /// Checks if the EFCPT fingerprint has changed. + /// + public const string FingerprintChanged = "'$(_EfcptFingerprintChanged)' == 'true'"; + + /// + /// Combines multiple conditions with AND logic. + /// + /// The conditions to combine. + /// A combined condition string. + public static string And(params string[] conditions) => + string.Join(" and ", conditions); + + /// + /// Combines multiple conditions with OR logic. + /// + /// The conditions to combine. + /// A combined condition string. + public static string Or(params string[] conditions) => + string.Join(" or ", conditions); + + /// + /// Creates a condition that checks if EFCPT is enabled AND another condition is true. + /// + /// The additional condition. + /// A combined condition string. + public static string EfcptEnabledAnd(string condition) => + And(EfcptEnabled, condition); + + /// + /// Creates a condition for EFCPT-enabled SQL projects. + /// + public static string EfcptEnabledSqlProject => + And(EfcptEnabled, IsSqlProject); + + /// + /// Creates a condition for EFCPT-enabled data access projects (not SQL projects). + /// + public static string EfcptEnabledDataAccess => + And(EfcptEnabled, IsNotSqlProject); +} diff --git a/src/JD.Efcpt.Build.Definitions/Constants/MSBuildVersions.cs b/src/JD.Efcpt.Build.Definitions/Constants/MSBuildVersions.cs new file mode 100644 index 0000000..ddcfef7 --- /dev/null +++ b/src/JD.Efcpt.Build.Definitions/Constants/MSBuildVersions.cs @@ -0,0 +1,23 @@ +namespace JD.Efcpt.Build.Definitions.Constants; + +/// +/// MSBuild version constants for task assembly resolution. +/// Maps MSBuild versions to Visual Studio releases. +/// +public static class MSBuildVersions +{ + /// + /// MSBuild 18.0 - Visual Studio 2026 and later + /// + public const string VS2026 = "18.0"; + + /// + /// MSBuild 17.14 - Visual Studio 2024 Update 14 and later + /// + public const string VS2024Update14 = "17.14"; + + /// + /// MSBuild 17.12 - Visual Studio 2024 Update 12 and later + /// + public const string VS2024Update12 = "17.12"; +} diff --git a/src/JD.Efcpt.Build.Definitions/DefinitionFactory.cs b/src/JD.Efcpt.Build.Definitions/DefinitionFactory.cs new file mode 100644 index 0000000..8b321f4 --- /dev/null +++ b/src/JD.Efcpt.Build.Definitions/DefinitionFactory.cs @@ -0,0 +1,32 @@ +using JD.MSBuild.Fluent; + +namespace JD.Efcpt.Build.Definitions; + +/// +/// Main definition factory for JD.Efcpt.Build package. +/// This factory coordinates all the build, buildTransitive, and SDK assets. +/// +public static class DefinitionFactory +{ + public static PackageDefinition Create() + { + var buildProps = BuildPropsFactory.Create(); + var buildTargets = BuildTargetsFactory.Create(); + var buildTransitiveProps = BuildTransitivePropsFactory.Create(); + var buildTransitiveTargets = BuildTransitiveTargetsFactory.Create(); + + return new PackageDefinition + { + Id = "JD.Efcpt.Build", + Description = "MSBuild tasks and targets for Entity Framework Core power tools", + BuildProps = buildProps.Props, + BuildTargets = buildTargets.Targets, + BuildTransitiveProps = buildTransitiveProps.Props, + BuildTransitiveTargets = buildTransitiveTargets.Targets, + Packaging = + { + BuildTransitive = true + } + }; + } +} diff --git a/src/JD.Efcpt.Build.Definitions/JD.Efcpt.Build.Definitions.csproj b/src/JD.Efcpt.Build.Definitions/JD.Efcpt.Build.Definitions.csproj new file mode 100644 index 0000000..e3b38da --- /dev/null +++ b/src/JD.Efcpt.Build.Definitions/JD.Efcpt.Build.Definitions.csproj @@ -0,0 +1,35 @@ + + + + netstandard2.0 + latest + enable + disable + + + JD.Efcpt.Build + JD.Efcpt.Build + MSBuild tasks and targets for Entity Framework Core power tools. + Jerrett Davis + Jerrett Davis + Copyright © Jerrett Davis + https://github.com/JerrettDavis/JD.Efcpt.Build + https://github.com/JerrettDavis/JD.Efcpt.Build + git + MIT + README.md + msbuild;efcore;ef-core;entity-framework;build-tools + + + false + + + + + + + + + + + diff --git a/src/JD.Efcpt.Build.Definitions/MsBuildNames.cs b/src/JD.Efcpt.Build.Definitions/MsBuildNames.cs new file mode 100644 index 0000000..f3543dc --- /dev/null +++ b/src/JD.Efcpt.Build.Definitions/MsBuildNames.cs @@ -0,0 +1,94 @@ +using JD.MSBuild.Fluent.Typed; + +namespace JD.Efcpt.Build.Definitions; + +/// +/// Strongly-typed MSBuild task names specific to JD.Efcpt.Build. +/// For well-known MSBuild names, see . +/// +public static class EfcptTaskNames +{ + // ==================================================================================== + // JD.Efcpt.Build Tasks + // ==================================================================================== + + public readonly struct DetectSqlProjectTask : IMsBuildTaskName + { + public string Name => "DetectSqlProject"; + } + + public readonly struct ResolveSqlProjAndInputsTask : IMsBuildTaskName + { + public string Name => "ResolveSqlProjAndInputs"; + } + + public readonly struct EnsureDacpacBuiltTask : IMsBuildTaskName + { + public string Name => "EnsureDacpacBuilt"; + } + + public readonly struct StageEfcptInputsTask : IMsBuildTaskName + { + public string Name => "StageEfcptInputs"; + } + + public readonly struct ComputeFingerprintTask : IMsBuildTaskName + { + public string Name => "ComputeFingerprint"; + } + + public readonly struct RunEfcptTask : IMsBuildTaskName + { + public string Name => "RunEfcpt"; + } + + public readonly struct RenameGeneratedFilesTask : IMsBuildTaskName + { + public string Name => "RenameGeneratedFiles"; + } + + public readonly struct QuerySchemaMetadataTask : IMsBuildTaskName + { + public string Name => "QuerySchemaMetadata"; + } + + public readonly struct ApplyConfigOverridesTask : IMsBuildTaskName + { + public string Name => "ApplyConfigOverrides"; + } + + public readonly struct ResolveDbContextNameTask : IMsBuildTaskName + { + public string Name => "ResolveDbContextName"; + } + + public readonly struct SerializeConfigPropertiesTask : IMsBuildTaskName + { + public string Name => "SerializeConfigProperties"; + } + + public readonly struct CheckSdkVersionTask : IMsBuildTaskName + { + public string Name => "CheckSdkVersion"; + } + + public readonly struct RunSqlPackageTask : IMsBuildTaskName + { + public string Name => "RunSqlPackage"; + } + + public readonly struct AddSqlFileWarningsTask : IMsBuildTaskName + { + public string Name => "AddSqlFileWarnings"; + } + + public readonly struct InitializeBuildProfilingTask : IMsBuildTaskName + { + public string Name => "InitializeBuildProfiling"; + } + + public readonly struct FinalizeBuildProfilingTask : IMsBuildTaskName + { + public string Name => "FinalizeBuildProfiling"; + } +} diff --git a/src/JD.Efcpt.Build.Definitions/Registry/UsingTasksRegistry.cs b/src/JD.Efcpt.Build.Definitions/Registry/UsingTasksRegistry.cs new file mode 100644 index 0000000..aad498e --- /dev/null +++ b/src/JD.Efcpt.Build.Definitions/Registry/UsingTasksRegistry.cs @@ -0,0 +1,48 @@ +using JD.MSBuild.Fluent.Common; +using JD.MSBuild.Fluent.Fluent; + +namespace JD.Efcpt.Build.Definitions.Registry; + +/// +/// Centralized registry for all JD.Efcpt.Build custom MSBuild tasks. +/// Automatically registers all task assemblies with MSBuild using a data-driven approach. +/// +public static class UsingTasksRegistry +{ + /// + /// All custom task names in the JD.Efcpt.Build.Tasks assembly. + /// Adding a new task only requires adding its name to this array. + /// + private static readonly string[] TaskNames = + [ + "AddSqlFileWarnings", + "ApplyConfigOverrides", + "CheckSdkVersion", + "ComputeFingerprint", + "DetectSqlProject", + "EnsureDacpacBuilt", + "FinalizeBuildProfiling", + "InitializeBuildProfiling", + "QuerySchemaMetadata", + "RenameGeneratedFiles", + "ResolveDbContextName", + "ResolveSqlProjAndInputs", + "RunEfcpt", + "RunSqlPackage", + "SerializeConfigProperties", + "StageEfcptInputs" + ]; + + /// + /// Registers all EFCPT custom tasks with MSBuild. + /// Uses the resolved task assembly path from SharedPropertyGroups. + /// + /// The targets builder to register tasks with. + public static void RegisterAll(TargetsBuilder t) + { + t.RegisterTasks( + assemblyPath: "$(_EfcptTaskAssembly)", + taskNamespace: "JD.Efcpt.Build.Tasks", + taskNames: TaskNames); + } +} diff --git a/src/JD.Efcpt.Build.Definitions/Shared/SharedPropertyGroups.cs b/src/JD.Efcpt.Build.Definitions/Shared/SharedPropertyGroups.cs new file mode 100644 index 0000000..5a09715 --- /dev/null +++ b/src/JD.Efcpt.Build.Definitions/Shared/SharedPropertyGroups.cs @@ -0,0 +1,46 @@ +using JD.MSBuild.Fluent.Common; +using JD.MSBuild.Fluent.Fluent; + +namespace JD.Efcpt.Build.Definitions.Shared; + +/// +/// Shared property group configurations used across both Props and Targets. +/// Eliminates duplication and provides single source of truth. +/// +public static class SharedPropertyGroups +{ + /// + /// Configures MSBuild property resolution for selecting the correct task assembly + /// based on MSBuild runtime version and type. + /// + public static void ConfigureTaskAssemblyResolution(PropsGroupBuilder group) + { + group.ResolveMultiTargetedTaskAssembly( + folderProperty: "_EfcptTasksFolder", + assemblyProperty: "_EfcptTaskAssembly", + assemblyFileName: "JD.Efcpt.Build.Tasks.dll", + nugetTasksPath: "$(MSBuildThisFileDirectory)..\\tasks", + localProjectPath: "$(MSBuildThisFileDirectory)..\\..\\JD.Efcpt.Build.Tasks"); + } + + /// + /// Configures EfcptConfigUseNullableReferenceTypes property based on project's Nullable setting. + /// Provides zero-config experience by deriving EFCPT settings from standard project settings. + /// + /// + /// Logic: + /// + /// If Nullable is "enable" or "Enable" → set to true + /// If Nullable has any other value → set to false + /// If Nullable is not set → leave EfcptConfigUseNullableReferenceTypes as-is (user override) + /// + /// + public static void ConfigureNullableReferenceTypes(PropsGroupBuilder group) + { + group.Property("true", + "'$(EfcptConfigUseNullableReferenceTypes)'=='' and ('$(Nullable)'=='enable' or '$(Nullable)'=='Enable')"); + + group.Property("false", + "'$(EfcptConfigUseNullableReferenceTypes)'=='' and '$(Nullable)'!=''"); + } +} diff --git a/src/JD.Efcpt.Build.Tasks/Chains/ConnectionStringResolutionChain.cs b/src/JD.Efcpt.Build.Tasks/Chains/ConnectionStringResolutionChain.cs index ba97f1f..74dcf62 100644 --- a/src/JD.Efcpt.Build.Tasks/Chains/ConnectionStringResolutionChain.cs +++ b/src/JD.Efcpt.Build.Tasks/Chains/ConnectionStringResolutionChain.cs @@ -131,7 +131,7 @@ private static bool HasAppConfigFiles(string projectDirectory) var fullPath = PathUtils.FullPath(explicitPath, projectDirectory); var validator = new ConfigurationFileTypeValidator(); - validator.ValidateAndWarn(fullPath, propertyName, log); + ConfigurationFileTypeValidator.ValidateAndWarn(fullPath, propertyName, log); var result = ParseConnectionStringFromFile(fullPath, connectionStringName, log); return result.Success ? result.ConnectionString : null; @@ -158,7 +158,7 @@ private static bool HasAppConfigFiles(string projectDirectory) foreach (var file in appSettingsFiles.OrderBy(f => f == Path.Combine(projectDirectory, "appsettings.json") ? 0 : 1)) { var parser = new AppSettingsConnectionStringParser(); - var result = parser.Parse(file, connectionStringName, log); + var result = AppSettingsConnectionStringParser.Parse(file, connectionStringName, log); if (!result.Success || string.IsNullOrWhiteSpace(result.ConnectionString)) continue; @@ -186,7 +186,7 @@ private static bool HasAppConfigFiles(string projectDirectory) continue; var parser = new AppConfigConnectionStringParser(); - var result = parser.Parse(path, connectionStringName, log); + var result = AppConfigConnectionStringParser.Parse(path, connectionStringName, log); if (result.Success && !string.IsNullOrWhiteSpace(result.ConnectionString)) { log.Detail($"Resolved connection string from auto-discovered file: {configFile}"); @@ -205,8 +205,8 @@ private static ConnectionStringResult ParseConnectionStringFromFile( var ext = Path.GetExtension(filePath).ToLowerInvariant(); return ext switch { - ".json" => new AppSettingsConnectionStringParser().Parse(filePath, connectionStringName, log), - ".config" => new AppConfigConnectionStringParser().Parse(filePath, connectionStringName, log), + ".json" => AppSettingsConnectionStringParser.Parse(filePath, connectionStringName, log), + ".config" => AppConfigConnectionStringParser.Parse(filePath, connectionStringName, log), _ => ConnectionStringResult.Failed() }; } diff --git a/src/JD.Efcpt.Build.Tasks/Config/EfcptConfigGenerator.cs b/src/JD.Efcpt.Build.Tasks/Config/EfcptConfigGenerator.cs index 061b2ce..b098a7e 100644 --- a/src/JD.Efcpt.Build.Tasks/Config/EfcptConfigGenerator.cs +++ b/src/JD.Efcpt.Build.Tasks/Config/EfcptConfigGenerator.cs @@ -17,6 +17,12 @@ public static class EfcptConfigGenerator private const string PrimarySchemaUrl = "https://raw.githubusercontent.com/ErikEJ/EFCorePowerTools/master/samples/efcpt-config.schema.json"; private const string FallbackSchemaUrl = "https://raw.githubusercontent.com/JerrettDavis/JD.Efcpt.Build/refs/heads/main/lib/efcpt-config.schema.json"; + private static readonly JsonSerializerOptions JsonOptions = new() + { + WriteIndented = true, + Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping + }; + /// /// Generates a default efcpt-config.json from a schema URL. /// @@ -109,13 +115,7 @@ public static string GenerateFromSchema( // Don't process TypeMappings as it's not required // Serialize with indentation - var options = new JsonSerializerOptions - { - WriteIndented = true, - Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping - }; - - return JsonSerializer.Serialize(config, options); + return JsonSerializer.Serialize(config, JsonOptions); } private static void ProcessCodeGeneration(JsonObject config, JsonObject definitions) diff --git a/src/JD.Efcpt.Build.Tasks/ConnectionStrings/AppConfigConnectionStringParser.cs b/src/JD.Efcpt.Build.Tasks/ConnectionStrings/AppConfigConnectionStringParser.cs index d9623c1..b8636d2 100644 --- a/src/JD.Efcpt.Build.Tasks/ConnectionStrings/AppConfigConnectionStringParser.cs +++ b/src/JD.Efcpt.Build.Tasks/ConnectionStrings/AppConfigConnectionStringParser.cs @@ -16,7 +16,7 @@ internal sealed class AppConfigConnectionStringParser /// The name of the connection string to retrieve. /// The build log for warnings and errors. /// A result indicating success or failure, along with the connection string if found. - public ConnectionStringResult Parse(string filePath, string connectionStringName, BuildLog log) + public static ConnectionStringResult Parse(string filePath, string connectionStringName, BuildLog log) { try { @@ -40,7 +40,7 @@ public ConnectionStringResult Parse(string filePath, string connectionStringName return ConnectionStringResult.WithSuccess(match.ConnectionString!, filePath, match.Name!); // Fallback to first available - if (connectionStrings.Any()) + if (connectionStrings.Count > 0) { var first = connectionStrings.First(); log.Warn("JD0002", diff --git a/src/JD.Efcpt.Build.Tasks/ConnectionStrings/AppSettingsConnectionStringParser.cs b/src/JD.Efcpt.Build.Tasks/ConnectionStrings/AppSettingsConnectionStringParser.cs index 3f25168..75a7921 100644 --- a/src/JD.Efcpt.Build.Tasks/ConnectionStrings/AppSettingsConnectionStringParser.cs +++ b/src/JD.Efcpt.Build.Tasks/ConnectionStrings/AppSettingsConnectionStringParser.cs @@ -14,7 +14,7 @@ internal sealed class AppSettingsConnectionStringParser /// The name of the connection string to retrieve. /// The build log for warnings and errors. /// A result indicating success or failure, along with the connection string if found. - public ConnectionStringResult Parse(string filePath, string connectionStringName, BuildLog log) + public static ConnectionStringResult Parse(string filePath, string connectionStringName, BuildLog log) { try { diff --git a/src/JD.Efcpt.Build.Tasks/ConnectionStrings/ConfigurationFileTypeValidator.cs b/src/JD.Efcpt.Build.Tasks/ConnectionStrings/ConfigurationFileTypeValidator.cs index 8f43c98..527780d 100644 --- a/src/JD.Efcpt.Build.Tasks/ConnectionStrings/ConfigurationFileTypeValidator.cs +++ b/src/JD.Efcpt.Build.Tasks/ConnectionStrings/ConfigurationFileTypeValidator.cs @@ -11,7 +11,7 @@ internal sealed class ConfigurationFileTypeValidator /// The path to the configuration file. /// The name of the parameter (e.g., "EfcptAppSettings" or "EfcptAppConfig"). /// The build log for warnings. - public void ValidateAndWarn(string filePath, string parameterName, BuildLog log) + public static void ValidateAndWarn(string filePath, string parameterName, BuildLog log) { var extension = Path.GetExtension(filePath).ToLowerInvariant(); var isJson = extension == ".json"; diff --git a/src/JD.Efcpt.Build.Tasks/DbContextNameGenerator.cs b/src/JD.Efcpt.Build.Tasks/DbContextNameGenerator.cs index daf70e1..60899dd 100644 --- a/src/JD.Efcpt.Build.Tasks/DbContextNameGenerator.cs +++ b/src/JD.Efcpt.Build.Tasks/DbContextNameGenerator.cs @@ -33,6 +33,8 @@ public static class DbContextNameGenerator { private const string DefaultContextName = "MyDbContext"; private const string ContextSuffix = "Context"; + + private static readonly char[] DotSeparator = ['.']; /// /// Generates a DbContext name from the provided SQL project path. @@ -209,7 +211,7 @@ private static string HumanizeName(string rawName) return DefaultContextName; // Handle dotted namespaces (e.g., "Org.Unit.SystemData" → "SystemData") - var dotParts = rawName.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries); + var dotParts = rawName.Split(DotSeparator, StringSplitOptions.RemoveEmptyEntries); var baseName = dotParts.Length > 0 ? dotParts[^1] : rawName; // Remove digits at the end (common in DACPAC names like "MyDb20251225.dacpac") diff --git a/src/JD.Efcpt.Build.Tasks/DetectSqlProject.cs b/src/JD.Efcpt.Build.Tasks/DetectSqlProject.cs index f86668b..46c20db 100644 --- a/src/JD.Efcpt.Build.Tasks/DetectSqlProject.cs +++ b/src/JD.Efcpt.Build.Tasks/DetectSqlProject.cs @@ -61,7 +61,7 @@ private bool ExecuteCore(TaskExecutionContext ctx) } // Fall back to property-based detection for legacy SSDT projects - var hasLegacyProperties = !string.IsNullOrEmpty(SqlServerVersion) || !string.IsNullOrEmpty(DSP); + var hasLegacyProperties = !string.IsNullOrWhiteSpace(SqlServerVersion) || !string.IsNullOrWhiteSpace(DSP); if (hasLegacyProperties) { diff --git a/src/JD.Efcpt.Build.Tasks/Profiling/BuildProfiler.cs b/src/JD.Efcpt.Build.Tasks/Profiling/BuildProfiler.cs index b6034df..7821986 100644 --- a/src/JD.Efcpt.Build.Tasks/Profiling/BuildProfiler.cs +++ b/src/JD.Efcpt.Build.Tasks/Profiling/BuildProfiler.cs @@ -27,6 +27,11 @@ public interface ITaskTracker : IDisposable public sealed class BuildProfiler { private static readonly BuildRunOutput EmptyRunOutput = new(); + private static readonly JsonSerializerOptions JsonOptions = new() + { + WriteIndented = true, + DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull + }; private readonly BuildRunOutput _runOutput; private readonly Stack _nodeStack = new(); @@ -238,13 +243,7 @@ public void Complete(string outputPath) } // Write profile to file with indented JSON for human readability - var options = new JsonSerializerOptions - { - WriteIndented = true, - DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull - }; - - var json = JsonSerializer.Serialize(_runOutput, options); + var json = JsonSerializer.Serialize(_runOutput, JsonOptions); File.WriteAllText(outputPath, json); } } diff --git a/src/JD.Efcpt.Build.Tasks/RunEfcpt.cs b/src/JD.Efcpt.Build.Tasks/RunEfcpt.cs index 37ad3fe..d362302 100644 --- a/src/JD.Efcpt.Build.Tasks/RunEfcpt.cs +++ b/src/JD.Efcpt.Build.Tasks/RunEfcpt.cs @@ -82,6 +82,8 @@ public sealed class RunEfcpt : Task /// private const int ProcessTimeoutMs = 5000; + private static readonly string[] NewLineSeparators = ["\r\n", "\n"]; + /// /// Controls how the efcpt dotnet tool is resolved. /// @@ -546,7 +548,7 @@ private static bool IsDotNet10SdkInstalled(string dotnetExe) // Parse output like "10.0.100 [C:\Program Files\dotnet\sdk]" // Check if any line starts with "10." or higher - foreach (var line in output.Split(new[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries)) + foreach (var line in output.Split(NewLineSeparators, StringSplitOptions.RemoveEmptyEntries)) { var trimmed = line.Trim(); if (string.IsNullOrEmpty(trimmed)) diff --git a/src/JD.Efcpt.Build.Tasks/RunSqlPackage.cs b/src/JD.Efcpt.Build.Tasks/RunSqlPackage.cs index 277280a..0e7ddc3 100644 --- a/src/JD.Efcpt.Build.Tasks/RunSqlPackage.cs +++ b/src/JD.Efcpt.Build.Tasks/RunSqlPackage.cs @@ -182,7 +182,7 @@ private bool ExecuteCore(TaskExecutionContext ctx) if (Directory.Exists(dacpacTempDir)) { log.Detail($"Moving extracted files from {dacpacTempDir} to {TargetDirectory}"); - MoveDirectoryContents(dacpacTempDir, TargetDirectory, log); + RunSqlPackage.MoveDirectoryContents(dacpacTempDir, TargetDirectory, log); // Clean up temp directory try @@ -428,7 +428,7 @@ private bool ExecuteSqlPackage((string Executable, string Arguments) toolInfo, s /// /// Recursively moves all contents from source directory to destination directory. /// - private void MoveDirectoryContents(string sourceDir, string destDir, IBuildLog log) + private static void MoveDirectoryContents(string sourceDir, string destDir, IBuildLog log) { // Ensure source directory path ends with separator for proper substring var sourceDirNormalized = sourceDir.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar) + Path.DirectorySeparatorChar; diff --git a/src/JD.Efcpt.Build.Tasks/SqlProjectDetector.cs b/src/JD.Efcpt.Build.Tasks/SqlProjectDetector.cs index 0bbb2f1..1bc8302 100644 --- a/src/JD.Efcpt.Build.Tasks/SqlProjectDetector.cs +++ b/src/JD.Efcpt.Build.Tasks/SqlProjectDetector.cs @@ -9,6 +9,8 @@ internal static class SqlProjectDetector ["Microsoft.Build.Sql", "MSBuild.Sdk.SqlProj"], StringComparer.OrdinalIgnoreCase); + private static readonly char[] SemicolonSeparator = [';']; + public static bool IsSqlProjectReference(string projectPath) { if (string.IsNullOrWhiteSpace(projectPath)) @@ -79,7 +81,7 @@ private static bool HasSupportedSdkAttribute(XElement project) private static IEnumerable ParseSdkNames(string raw) => raw - .Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries) + .Split(SemicolonSeparator, StringSplitOptions.RemoveEmptyEntries) .Select(entry => entry.Trim()) .Where(entry => entry.Length > 0) .Select(entry => diff --git a/src/JD.Efcpt.Build.Tasks/Utilities/DotNetToolUtilities.cs b/src/JD.Efcpt.Build.Tasks/Utilities/DotNetToolUtilities.cs index 4546e03..2d60521 100644 --- a/src/JD.Efcpt.Build.Tasks/Utilities/DotNetToolUtilities.cs +++ b/src/JD.Efcpt.Build.Tasks/Utilities/DotNetToolUtilities.cs @@ -13,6 +13,9 @@ internal static class DotNetToolUtilities /// private const int ProcessTimeoutMs = 5000; + private static readonly char[] NewLineSeparator = ['\n']; + private static readonly char[] SpaceSeparator = [' ', '\t']; + /// /// Checks if the .NET 10.0 (or later) SDK is installed by running `dotnet --list-sdks`. /// @@ -61,7 +64,7 @@ public static bool IsDotNet10SdkInstalled(string dotnetExe) var output = outputBuilder.ToString(); // Parse SDK versions from output like "10.0.100 [C:\Program Files\dotnet\sdk]" - foreach (var line in output.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries)) + foreach (var line in output.Split(NewLineSeparator, StringSplitOptions.RemoveEmptyEntries)) { var trimmed = line.Trim(); var firstSpace = trimmed.IndexOf(' '); @@ -131,14 +134,14 @@ public static bool IsDnxAvailable(string dotnetExe) var output = outputBuilder.ToString(); // If we can list runtimes and at least one .NET 10 runtime is present, dnx is available - foreach (var line in output.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries)) + foreach (var line in output.Split(NewLineSeparator, StringSplitOptions.RemoveEmptyEntries)) { var trimmed = line.Trim(); if (string.IsNullOrEmpty(trimmed)) continue; // Expected format: " [path]" - var parts = trimmed.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); + var parts = trimmed.Split(SpaceSeparator, StringSplitOptions.RemoveEmptyEntries); if (parts.Length < 2) continue; diff --git a/src/JD.Efcpt.Build.Tasks/packages.lock.json b/src/JD.Efcpt.Build.Tasks/packages.lock.json index 33b9d54..0589cde 100644 --- a/src/JD.Efcpt.Build.Tasks/packages.lock.json +++ b/src/JD.Efcpt.Build.Tasks/packages.lock.json @@ -84,15 +84,6 @@ "SQLitePCLRaw.core": "2.1.10" } }, - "Microsoft.NETFramework.ReferenceAssemblies": { - "type": "Direct", - "requested": "[1.0.3, )", - "resolved": "1.0.3", - "contentHash": "vUc9Npcs14QsyOD01tnv/m8sQUnGTGOw1BCmKcv77LBJY7OxhJ+zJF7UD/sCL3lYNFuqmQEVlkfS4Quif6FyYg==", - "dependencies": { - "Microsoft.NETFramework.ReferenceAssemblies.net472": "1.0.3" - } - }, "MySqlConnector": { "type": "Direct", "requested": "[2.4.0, )", @@ -504,11 +495,6 @@ "System.Runtime.CompilerServices.Unsafe": "6.1.0" } }, - "Microsoft.NETFramework.ReferenceAssemblies.net472": { - "type": "Transitive", - "resolved": "1.0.3", - "contentHash": "0E7evZXHXaDYYiLRfpyXvCh+yzM2rNTyuZDI+ZO7UUqSc6GfjePiXTdqJGtgIKUwdI81tzQKmaWprnUiPj9hAw==" - }, "Mono.Unix": { "type": "Transitive", "resolved": "7.1.0-final.1.21458.1", diff --git a/src/JD.Efcpt.Build.Templates/packages.lock.json b/src/JD.Efcpt.Build.Templates/packages.lock.json new file mode 100644 index 0000000..b7e843e --- /dev/null +++ b/src/JD.Efcpt.Build.Templates/packages.lock.json @@ -0,0 +1,21 @@ +{ + "version": 1, + "dependencies": { + ".NETStandard,Version=v2.0": { + "NETStandard.Library": { + "type": "Direct", + "requested": "[2.0.3, )", + "resolved": "2.0.3", + "contentHash": "st47PosZSHrjECdjeIzZQbzivYBJFv6P2nv4cj2ypdI204DO+vZ7l5raGMiX4eXMJ53RfOIg+/s4DHVZ54Nu2A==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0" + } + }, + "Microsoft.NETCore.Platforms": { + "type": "Transitive", + "resolved": "1.1.0", + "contentHash": "kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==" + } + } + } +} \ No newline at end of file diff --git a/src/JD.Efcpt.Build/GENERATING.md b/src/JD.Efcpt.Build/GENERATING.md new file mode 100644 index 0000000..955d522 --- /dev/null +++ b/src/JD.Efcpt.Build/GENERATING.md @@ -0,0 +1,88 @@ +# Regenerating MSBuild Files + +The `buildTransitive/` MSBuild files (`.props` and `.targets`) are generated from C# definitions using [JD.MSBuild.Fluent](https://www.nuget.org/packages/JD.MSBuild.Fluent). + +## Why Generation is Disabled + +Automatic generation is **disabled by default** due to a file locking issue when multi-targeting: + +1. JD.MSBuild.Fluent loads `JD.Efcpt.Build.dll` to call `DefinitionFactory.Create()` +2. The loaded DLL is locked by the .NET host process +3. MSBuild tries to copy the DLL to `bin/` but fails because it's locked +4. Build fails after 10 retries + +This affects both local builds and CI. + +## When to Regenerate + +Regenerate the MSBuild files when you modify: + +- `Definitions/BuildTransitivePropsFactory.cs` +- `Definitions/BuildTransitiveTargetsFactory.cs` +- `Definitions/Registry/UsingTasksRegistry.cs` +- `Definitions/Shared/SharedPropertyGroups.cs` + +## How to Regenerate + +### Option 1: Single Target Framework (Recommended) + +Build only `net8.0` to avoid multi-targeting file locks: + +```powershell +cd src/JD.Efcpt.Build +dotnet msbuild -t:JDMSBuildFluentGenerate -p:TargetFramework=net8.0 -p:JDMSBuildFluentGenerateEnabled=true +``` + +This generates files to `obj/msbuild_fluent_generated/` which are then copied to `buildTransitive/`. + +### Option 2: Enable in Project File + +Temporarily enable generation in `JD.Efcpt.Build.csproj`: + +```xml +true +``` + +Then build: + +```powershell +dotnet build -p:TargetFramework=net8.0 +``` + +**Warning:** Don't commit with generation enabled, or CI will fail! + +### Option 3: Clean Rebuild + +If you don't have stale processes locking files: + +```powershell +dotnet clean +dotnet build -p:TargetFramework=net8.0 -p:JDMSBuildFluentGenerateEnabled=true +``` + +## Verifying Generated Files + +After regeneration, check that these files exist and are updated: + +``` +buildTransitive/ +├── JD.Efcpt.Build.props +└── JD.Efcpt.Build.targets +``` + +Commit the regenerated files: + +```powershell +git add buildTransitive/ +git commit -m "chore: regenerate MSBuild files from definitions" +``` + +## CI Considerations + +CI always has `JDMSBuildFluentGenerateEnabled=false` because: + +1. Generated files are tracked in git (source of truth) +2. Multi-targeting causes file locking failures +3. Faster CI builds (no generation overhead) + +The generated files should be reviewed in PRs like any other code. diff --git a/src/JD.Efcpt.Build/JD.Efcpt.Build.csproj b/src/JD.Efcpt.Build/JD.Efcpt.Build.csproj index 4c1c6b7..1e52a96 100644 --- a/src/JD.Efcpt.Build/JD.Efcpt.Build.csproj +++ b/src/JD.Efcpt.Build/JD.Efcpt.Build.csproj @@ -4,11 +4,14 @@ net8.0;net9.0;net10.0 true + + false + JD.Efcpt.Build Jerrett Davis JDH Productions - + MSBuild Integration for EF Core Power Tools Enterprise-grade MSBuild integration for EF Core Power Tools CLI. Automate database-first EF Core model generation as part of your build pipeline. Zero manual steps, full CI/CD support, reproducible builds. Automatically builds your SQL Server Database Project (.sqlproj) to a DACPAC, runs efcpt, and generates DbContext and entity classes during dotnet build. @@ -19,19 +22,29 @@ README.md MIT false - + false true $(NoWarn);NU5128;NU5100 false + + + <_JDMSBuildFluentDirectReference>true + + false + JD.Efcpt.Build.Definitions.DefinitionFactory + Create + + + + IncludeAssets="Compile" /> - - + + + + @@ -90,3 +107,5 @@ + + diff --git a/src/JD.Efcpt.Build/JD.Efcpt.Build.props b/src/JD.Efcpt.Build/JD.Efcpt.Build.props new file mode 100644 index 0000000..f5ae7b8 --- /dev/null +++ b/src/JD.Efcpt.Build/JD.Efcpt.Build.props @@ -0,0 +1,15 @@ + + + + + <_EfcptIsDirectReference>true + + + + + diff --git a/src/JD.Efcpt.Build/JD.Efcpt.Build.targets b/src/JD.Efcpt.Build/JD.Efcpt.Build.targets new file mode 100644 index 0000000..6a24d21 --- /dev/null +++ b/src/JD.Efcpt.Build/JD.Efcpt.Build.targets @@ -0,0 +1,9 @@ + + + + + + diff --git a/src/JD.Efcpt.Build/buildTransitive/JD.Efcpt.Build.props b/src/JD.Efcpt.Build/buildTransitive/JD.Efcpt.Build.props index 7f7c97a..a7e08b8 100644 --- a/src/JD.Efcpt.Build/buildTransitive/JD.Efcpt.Build.props +++ b/src/JD.Efcpt.Build/buildTransitive/JD.Efcpt.Build.props @@ -1,7 +1,7 @@ - + + - - true - - - $(BaseIntermediateOutputPath)efcpt\ - $(EfcptOutput)Generated\ - - - - - efcpt-config.json - efcpt.renaming.json - Template - - - - - - DefaultConnection - - mssql - - - $(SolutionDir) - $(SolutionPath) - true - - - auto - ErikEJ.EFCorePowerTools.Cli - 10.* - true - efcpt - - dotnet - - - $(EfcptOutput)fingerprint.txt - $(EfcptOutput).efcpt.stamp - false - - - minimal - false - - + true + + $(BaseIntermediateOutputPath)efcpt\ + $(EfcptOutput)Generated\ + + + + efcpt-config.json + efcpt.renaming.json + Template + + + + + DefaultConnection + + mssql + + $(SolutionDir) + $(SolutionPath) + true + + auto + ErikEJ.EFCorePowerTools.Cli + 10.* + true + efcpt + + dotnet + + $(EfcptOutput)fingerprint.txt + $(EfcptOutput).efcpt.stamp + false + + minimal + false + - Info - Warn - - + Info + Warn + - false - 24 - false - - + false + 24 + false + - false - - obj\efcpt\Generated\ - - - - - + false + + obj\efcpt\Generated\ + + + - true - - - - $(RootNamespace) - $(MSBuildProjectName) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + true + + + $(RootNamespace) + $(MSBuildProjectName) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - false - $(EfcptOutput)build-profile.json - minimal + (values: "minimal", "detailed"; default: "minimal")--> + false + $(EfcptOutput)build-profile.json + minimal - - - microsoft-build-sql - csharp - $(MSBuildProjectDirectory)\ - $(MSBuildProjectDirectory)\ - Sql160 - - true - + + microsoft-build-sql + csharp + $(MSBuildProjectDirectory)\ + $(MSBuildProjectDirectory)\ + Sql160 + + true + diff --git a/src/JD.Efcpt.Build/buildTransitive/JD.Efcpt.Build.targets b/src/JD.Efcpt.Build/buildTransitive/JD.Efcpt.Build.targets index 8ddc286..f08aaea 100644 --- a/src/JD.Efcpt.Build/buildTransitive/JD.Efcpt.Build.targets +++ b/src/JD.Efcpt.Build/buildTransitive/JD.Efcpt.Build.targets @@ -1,81 +1,33 @@ - - - + + + - - true - false + + true + false - - + - + - - - - <_EfcptIsSqlProject Condition="'$(_EfcptIsSqlProject)'==''">false + + <_EfcptIsSqlProject>false - - + - <_EfcptTasksFolder Condition="'$(MSBuildRuntimeType)' == 'Core' and $([MSBuild]::VersionGreaterThanOrEquals('$(MSBuildVersion)', '18.0'))">net10.0 - <_EfcptTasksFolder Condition="'$(_EfcptTasksFolder)' == '' and '$(MSBuildRuntimeType)' == 'Core' and $([MSBuild]::VersionGreaterThanOrEquals('$(MSBuildVersion)', '17.14'))">net10.0 - <_EfcptTasksFolder Condition="'$(_EfcptTasksFolder)' == '' and '$(MSBuildRuntimeType)' == 'Core' and $([MSBuild]::VersionGreaterThanOrEquals('$(MSBuildVersion)', '17.12'))">net9.0 - <_EfcptTasksFolder Condition="'$(_EfcptTasksFolder)' == '' and '$(MSBuildRuntimeType)' == 'Core'">net8.0 - - + <_EfcptTasksFolder Condition="('$(_EfcptTasksFolder)' == '') and ('$(MSBuildRuntimeType)' == 'Core' and $([MSBuild]::VersionGreaterThanOrEquals('$(MSBuildVersion)', '17.14')))">net10.0 + <_EfcptTasksFolder Condition="('$(_EfcptTasksFolder)' == '') and ('$(MSBuildRuntimeType)' == 'Core' and $([MSBuild]::VersionGreaterThanOrEquals('$(MSBuildVersion)', '17.12')))">net9.0 + <_EfcptTasksFolder Condition="('$(_EfcptTasksFolder)' == '') and ('$(MSBuildRuntimeType)' == 'Core')">net8.0 <_EfcptTasksFolder Condition="'$(_EfcptTasksFolder)' == ''">net472 - - - <_EfcptTaskAssembly>$(MSBuildThisFileDirectory)..\tasks\$(_EfcptTasksFolder)\JD.Efcpt.Build.Tasks.dll - - - <_EfcptTaskAssembly Condition="!Exists('$(_EfcptTaskAssembly)')">$(MSBuildThisFileDirectory)..\..\JD.Efcpt.Build.Tasks\bin\$(Configuration)\$(_EfcptTasksFolder)\JD.Efcpt.Build.Tasks.dll - <_EfcptTaskAssembly Condition="!Exists('$(_EfcptTaskAssembly)') and '$(Configuration)' == ''">$(MSBuildThisFileDirectory)..\..\JD.Efcpt.Build.Tasks\bin\Debug\$(_EfcptTasksFolder)\JD.Efcpt.Build.Tasks.dll + <_EfcptTaskAssembly>$(MSBuildThisFileDirectory)\..\tasks\$(_EfcptTasksFolder)\JD.Efcpt.Build.Tasks.dll + <_EfcptTaskAssembly Condition="!Exists('$(_EfcptTaskAssembly)')">$(MSBuildThisFileDirectory)\..\..\JD.Efcpt.Build.Tasks\bin\$(Configuration)\$(_EfcptTasksFolder)\JD.Efcpt.Build.Tasks.dll + <_EfcptTaskAssembly Condition="(!Exists('$(_EfcptTaskAssembly)')) and ('$(Configuration)' == '')">$(MSBuildThisFileDirectory)\..\..\JD.Efcpt.Build.Tasks\bin\Debug\$(_EfcptTasksFolder)\JD.Efcpt.Build.Tasks.dll - - - + + @@ -83,232 +35,83 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - - + + + - - - - - - - - - - + + + + + + + - - + - - - - + + - <_EfcptScriptsDir>$(EfcptSqlScriptsDir) - - - - <_EfcptGeneratedScripts Include="$(_EfcptScriptsDir)**\*.sql" /> - - - + + - - - - - - - + + + - <_EfcptDatabaseName Condition="$(EfcptConnectionString.Contains('Database='))">$([System.Text.RegularExpressions.Regex]::Match($(EfcptConnectionString), 'Database\s*=\s*\"?([^;"]+)\"?').Groups[1].Value) - <_EfcptDatabaseName Condition="$(EfcptConnectionString.Contains('Initial Catalog='))">$([System.Text.RegularExpressions.Regex]::Match($(EfcptConnectionString), 'Initial Catalog\s*=\s*\"?([^;"]+)\"?').Groups[1].Value) + <_EfcptDatabaseName>$([System.Text.RegularExpressions.Regex]::Match($(EfcptConnectionString), 'Database\s*=\s*\"?([^;"]+)\"?').Groups[1].Value) + <_EfcptDatabaseName>$([System.Text.RegularExpressions.Regex]::Match($(EfcptConnectionString), 'Initial Catalog\s*=\s*\"?([^;"]+)\"?').Groups[1].Value) - - + - - - - - - - - + + + + + + + - - - - - + + + + @@ -318,457 +121,150 @@ - - - + + - <_EfcptResolvedConfig Condition="Exists('$(MSBuildProjectDirectory)\$(EfcptConfig)')">$(MSBuildProjectDirectory)\$(EfcptConfig) - <_EfcptResolvedConfig Condition="'$(_EfcptResolvedConfig)' == ''">$(MSBuildThisFileDirectory)Defaults\efcpt-config.json - <_EfcptResolvedRenaming Condition="Exists('$(MSBuildProjectDirectory)\$(EfcptRenaming)')">$(MSBuildProjectDirectory)\$(EfcptRenaming) - <_EfcptResolvedRenaming Condition="'$(_EfcptResolvedRenaming)' == ''">$(MSBuildThisFileDirectory)Defaults\efcpt.renaming.json - <_EfcptResolvedTemplateDir Condition="Exists('$(MSBuildProjectDirectory)\$(EfcptTemplateDir)')">$(MSBuildProjectDirectory)\$(EfcptTemplateDir) - <_EfcptResolvedTemplateDir Condition="'$(_EfcptResolvedTemplateDir)' == ''">$(MSBuildThisFileDirectory)Defaults\Template + <_EfcptResolvedConfig>$(MSBuildProjectDirectory)\$(EfcptConfig) + <_EfcptResolvedConfig>$(MSBuildThisFileDirectory)Defaults\efcpt-config.json + <_EfcptResolvedRenaming>$(MSBuildProjectDirectory)\$(EfcptRenaming) + <_EfcptResolvedRenaming>$(MSBuildThisFileDirectory)Defaults\efcpt.renaming.json + <_EfcptResolvedTemplateDir>$(MSBuildProjectDirectory)\$(EfcptTemplateDir) + <_EfcptResolvedTemplateDir>$(MSBuildThisFileDirectory)Defaults\Template <_EfcptIsUsingDefaultConfig>true <_EfcptUseConnectionString>false - - - + + - - + - - <_EfcptDacpacPath Condition="$([System.IO.Path]::IsPathRooted('$(EfcptDacpac)'))">$(EfcptDacpac) - <_EfcptDacpacPath Condition="!$([System.IO.Path]::IsPathRooted('$(EfcptDacpac)'))">$([System.IO.Path]::GetFullPath($([System.IO.Path]::Combine('$(MSBuildProjectDirectory)', '$(EfcptDacpac)')))) + <_EfcptDacpacPath>$(EfcptDacpac) + <_EfcptDacpacPath>$([System.IO.Path]::GetFullPath($([System.IO.Path]::Combine('$(MSBuildProjectDirectory)', '$(EfcptDacpac)')))) <_EfcptUseDirectDacpac>true - + - - - - - + + + + - - - - - + + + - - - - + + + - - $(_EfcptResolvedDbContextName) + $(_EfcptResolvedDbContextName) - - - + + - - - - + + + - - - - + + + - - - + + - - - - - + + + - - + + - - - - - - - - - - - + + + + + - <_EfcptDataProjectPath Condition="'$(EfcptDataProject)' != '' and $([System.IO.Path]::IsPathRooted('$(EfcptDataProject)'))">$(EfcptDataProject) - <_EfcptDataProjectPath Condition="'$(EfcptDataProject)' != '' and !$([System.IO.Path]::IsPathRooted('$(EfcptDataProject)'))">$([System.IO.Path]::GetFullPath($([System.IO.Path]::Combine('$(MSBuildProjectDirectory)', '$(EfcptDataProject)')))) + <_EfcptDataProjectPath>$(EfcptDataProject) + <_EfcptDataProjectPath>$([System.IO.Path]::GetFullPath($([System.IO.Path]::Combine($(MSBuildProjectDirectory), $(EfcptDataProject))))) - - - - - - - - + + - <_EfcptDataProjectDir>$([System.IO.Path]::GetDirectoryName('$(_EfcptDataProjectPath)'))\ <_EfcptDataDestDir>$(_EfcptDataProjectDir)$(EfcptDataProjectOutputSubdir) + <_EfcptDataProjectDir>$([System.IO.Path]::GetDirectoryName($(_EfcptDataProjectPath)))\ - - - - - - + + - <_EfcptDbContextFiles Include="$(EfcptGeneratedDir)*.g.cs" Exclude="$(EfcptGeneratedDir)*Configuration.g.cs" /> + <_EfcptDbContextFiles Include="$(EfcptGeneratedDir)*.g.cs" /> - - <_EfcptConfigurationFiles Include="$(EfcptGeneratedDir)*Configuration.g.cs" /> <_EfcptConfigurationFiles Include="$(EfcptGeneratedDir)Configurations\**\*.g.cs" /> - - - <_EfcptHasFilesToCopy Condition="'@(_EfcptDbContextFiles)' != '' or '@(_EfcptConfigurationFiles)' != ''">true + <_EfcptHasFilesToCopy>true - - - - - - - - + + + + - - - + - - - - - - - - - + + + + + - - - + + - - - - - + + - - - + + - + - - - - - + + + + - - - - + + + - diff --git a/src/JD.Efcpt.Build/packages.lock.json b/src/JD.Efcpt.Build/packages.lock.json index cee8b4d..ecf7778 100644 --- a/src/JD.Efcpt.Build/packages.lock.json +++ b/src/JD.Efcpt.Build/packages.lock.json @@ -1,8 +1,1481 @@ { "version": 1, "dependencies": { - "net10.0": {}, - "net8.0": {}, - "net9.0": {} + "net10.0": { + "JD.MSBuild.Fluent": { + "type": "Direct", + "requested": "[1.3.9, )", + "resolved": "1.3.9", + "contentHash": "xBBuXuZnHwfqgJu7Z+9TGnrqyOtZnLI7vA4s90R0IfR2Cv+WEyYj9pXQM/fLAxuD74rSmZyGP7NwBW1s/5cqBw==" + }, + "Apache.Arrow": { + "type": "Transitive", + "resolved": "14.0.2", + "contentHash": "2xvo9q2ag/Ze7TKSMsZfcQFMk3zZKWcduttJXoYnoevZD2bv+lKnOPeleyxONuR1ZwhZ00D86pPM9TWx2GMY2w==" + }, + "AWSSDK.Core": { + "type": "Transitive", + "resolved": "4.0.3.8", + "contentHash": "nJyNzaz3pcD8c8hZvtJXuziJm1dkd3/BYmZvhf1TPNfMo3G3lsesGFZl1UVyQhGEfmQOS+efT0H8tf00PMmjug==" + }, + "AWSSDK.S3": { + "type": "Transitive", + "resolved": "4.0.4", + "contentHash": "Xo/s2vef07V3FIuThclCMaM0IbuPRbF0VvtjvIRxnQNfXpAul/kKgrxM+45oFSIqoCYNgD9pVTzhzHixKQ49dg==", + "dependencies": { + "AWSSDK.Core": "[4.0.0.14, 5.0.0)" + } + }, + "Azure.Core": { + "type": "Transitive", + "resolved": "1.47.1", + "contentHash": "oPcncSsDHuxB8SC522z47xbp2+ttkcKv2YZ90KXhRKN0YQd2+7l1UURT9EBzUNEXtkLZUOAB5xbByMTrYRh3yA==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "8.0.0", + "System.ClientModel": "1.5.1", + "System.Memory.Data": "8.0.1" + } + }, + "Azure.Identity": { + "type": "Transitive", + "resolved": "1.14.2", + "contentHash": "YhNMwOTwT+I2wIcJKSdP0ADyB2aK+JaYWZxO8LSRDm5w77LFr0ykR9xmt2ZV5T1gaI7xU6iNFIh/yW1dAlpddQ==", + "dependencies": { + "Azure.Core": "1.46.1", + "Microsoft.Identity.Client": "4.73.1", + "Microsoft.Identity.Client.Extensions.Msal": "4.73.1" + } + }, + "Azure.Storage.Blobs": { + "type": "Transitive", + "resolved": "12.13.0", + "contentHash": "h5ZxRwmS/U1NOFwd+MuHJe4To1hEPu/yeBIKS1cbAHTDc+7RBZEjPf1VFeUZsIIuHvU/AzXtcRaph9BHuPRNMQ==", + "dependencies": { + "Azure.Storage.Common": "12.12.0" + } + }, + "Azure.Storage.Common": { + "type": "Transitive", + "resolved": "12.12.0", + "contentHash": "Ms0XsZ/D9Pcudfbqj+rWeCkhx/ITEq8isY0jkor9JFmDAEHsItFa2XrWkzP3vmJU6EsXQrk4snH63HkW/Jksvg==", + "dependencies": { + "Azure.Core": "1.25.0", + "System.IO.Hashing": "6.0.0" + } + }, + "BouncyCastle.Cryptography": { + "type": "Transitive", + "resolved": "2.3.1", + "contentHash": "buwoISwecYke3CmgG1AQSg+sNZjJeIb93vTAtJiHZX35hP/teYMxsfg0NDXGUKjGx6BKBTNKc77O2M3vKvlXZQ==" + }, + "FirebirdSql.Data.FirebirdClient": { + "type": "Transitive", + "resolved": "10.3.2", + "contentHash": "mo74lexrjTPAQ4XGrVWTdXy1wEnLKl/KcUeHO8HqEcULrqo5HfZmhgbClqIPogeQ6TY6Jh1EClfHa9ALn5IxfQ==" + }, + "Google.Api.Gax": { + "type": "Transitive", + "resolved": "4.8.0", + "contentHash": "xlV8Jq/G5CQAA3PwYAuKGjfzGOP7AvjhREnE6vgZlzxREGYchHudZWa2PWSqFJL+MBtz9YgitLpRogANN3CVvg==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "6.0.0", + "Newtonsoft.Json": "13.0.3" + } + }, + "Google.Api.Gax.Rest": { + "type": "Transitive", + "resolved": "4.8.0", + "contentHash": "zaA5LZ2VvGj/wwIzRB68swr7khi2kWNgqWvsB0fYtScIAl3kGkGtqiBcx63H1YLeKr5xau1866bFjTeReH6FSQ==", + "dependencies": { + "Google.Api.Gax": "4.8.0", + "Google.Apis.Auth": "[1.67.0, 2.0.0)", + "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0" + } + }, + "Google.Apis": { + "type": "Transitive", + "resolved": "1.67.0", + "contentHash": "XM8/fViJaB1pN61OdXy5RMZoQEqd3hKlWvA/K431gFSb5XtQ48BynfgrbBkUtFcPbSRa4BdjBHzSbkBh/skyMg==", + "dependencies": { + "Google.Apis.Core": "1.67.0" + } + }, + "Google.Apis.Auth": { + "type": "Transitive", + "resolved": "1.67.0", + "contentHash": "Bs9BlbZ12Y4NXzMONjpzQhZr9VbwLUTGMHkcQRF36aYnk2fYrmj5HNVNh7PPHDDq1fcEQpCtPic2nSlpYQLKXw==", + "dependencies": { + "Google.Apis": "1.67.0", + "Google.Apis.Core": "1.67.0", + "System.Management": "7.0.2" + } + }, + "Google.Apis.Core": { + "type": "Transitive", + "resolved": "1.67.0", + "contentHash": "IPq0I3B01NYZraPoMl8muELFLg4Vr2sbfyZp4PR2Xe3MAhHkZCiKyV28Yh1L14zIKUb0X0snol1sR5/mx4S6Iw==", + "dependencies": { + "Newtonsoft.Json": "13.0.3" + } + }, + "Google.Apis.Storage.v1": { + "type": "Transitive", + "resolved": "1.67.0.3365", + "contentHash": "N9Rp8aRUV8Fsjl6uojZeJnzZ/zwtImB+crkPz/HsUtIKcC8rx/ZhNdizNJ5YcNFKiVlvGC60p0K7M+Ywk2xTPQ==", + "dependencies": { + "Google.Apis": "1.67.0", + "Google.Apis.Auth": "1.67.0" + } + }, + "Google.Cloud.Storage.V1": { + "type": "Transitive", + "resolved": "4.10.0", + "contentHash": "a4hHQzDkzR/5Fm2gvfKnvuajYwgTJAZ944+8S3gO7S3qxXkXI+rasx8Jz8ldflyq1zHO5MWTyFiHc7+dfmwYhg==", + "dependencies": { + "Google.Api.Gax.Rest": "[4.8.0, 5.0.0)", + "Google.Apis.Storage.v1": "[1.67.0.3365, 2.0.0)" + } + }, + "Microsoft.Bcl.AsyncInterfaces": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "3WA9q9yVqJp222P3x1wYIGDAkpjAku0TMUaaQV22g6L67AI0LdOIrVS7Ht2vJfLHGSPVuqN94vIr15qn+HEkHw==" + }, + "Microsoft.Bcl.Cryptography": { + "type": "Transitive", + "resolved": "9.0.4", + "contentHash": "YgZYAWzyNuPVtPq6WNm0bqOWNjYaWgl5mBWTGZyNoXitYBUYSp6iUB9AwK0V1mo793qRJUXz2t6UZrWITZSvuQ==" + }, + "Microsoft.Build.Framework": { + "type": "Transitive", + "resolved": "18.0.2", + "contentHash": "sOSb+0J4G/jCBW/YqmRuL0eOMXgfw1KQLdC9TkbvfA5xs7uNm+PBQXJCOzSJGXtZcZrtXozcwxPmUiRUbmd7FA==" + }, + "Microsoft.Build.Utilities.Core": { + "type": "Transitive", + "resolved": "18.0.2", + "contentHash": "qsI2Mc8tbJEyg5m4oTvxlu5wY8te0TIVxObxILvrrPdeFUwH5V5UXUT2RV054b3S9msIR+7zViTWp4nRp0YGbQ==", + "dependencies": { + "Microsoft.Build.Framework": "18.0.2", + "Microsoft.NET.StringTools": "18.0.2", + "System.Configuration.ConfigurationManager": "9.0.0", + "System.Diagnostics.EventLog": "9.0.0", + "System.Security.Cryptography.ProtectedData": "9.0.6" + } + }, + "Microsoft.Data.SqlClient": { + "type": "Transitive", + "resolved": "6.1.3", + "contentHash": "ys/z8Tx8074CDU20EilNvBRJuJdwKSthpHkzUpt3JghnjB6GjbZusoOcCtNbhPCCWsEJqN8bxaT7HnS3UZuUDQ==", + "dependencies": { + "Azure.Core": "1.47.1", + "Azure.Identity": "1.14.2", + "Microsoft.Bcl.Cryptography": "9.0.4", + "Microsoft.Data.SqlClient.SNI.runtime": "6.0.2", + "Microsoft.Extensions.Caching.Memory": "9.0.4", + "Microsoft.IdentityModel.JsonWebTokens": "7.7.1", + "Microsoft.IdentityModel.Protocols.OpenIdConnect": "7.7.1", + "Microsoft.SqlServer.Server": "1.0.0", + "System.Configuration.ConfigurationManager": "9.0.4", + "System.Security.Cryptography.Pkcs": "9.0.4" + } + }, + "Microsoft.Data.SqlClient.SNI.runtime": { + "type": "Transitive", + "resolved": "6.0.2", + "contentHash": "f+pRODTWX7Y67jXO3T5S2dIPZ9qMJNySjlZT/TKmWVNWe19N8jcWmHaqHnnchaq3gxEKv1SWVY5EFzOD06l41w==" + }, + "Microsoft.Data.Sqlite.Core": { + "type": "Transitive", + "resolved": "9.0.1", + "contentHash": "useMNbAupB8gpEp/SjanW3LvvyFG9DWPMUcXFwVNjNuFWIxNcrs5zOu9BTmNJEyfDpLlrsSBmcBv7keYVG8UhA==", + "dependencies": { + "SQLitePCLRaw.core": "2.1.10" + } + }, + "Microsoft.Extensions.Caching.Abstractions": { + "type": "Transitive", + "resolved": "9.0.4", + "contentHash": "imcZ5BGhBw5mNsWLepBbqqumWaFe0GtvyCvne2/2wsDIBRa2+Lhx4cU/pKt/4BwOizzUEOls2k1eOJQXHGMalg==", + "dependencies": { + "Microsoft.Extensions.Primitives": "9.0.4" + } + }, + "Microsoft.Extensions.Caching.Memory": { + "type": "Transitive", + "resolved": "9.0.4", + "contentHash": "G5rEq1Qez5VJDTEyRsRUnewAspKjaY57VGsdZ8g8Ja6sXXzoiI3PpTd1t43HjHqNWD5A06MQveb2lscn+2CU+w==", + "dependencies": { + "Microsoft.Extensions.Caching.Abstractions": "9.0.4", + "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.4", + "Microsoft.Extensions.Logging.Abstractions": "9.0.4", + "Microsoft.Extensions.Options": "9.0.4", + "Microsoft.Extensions.Primitives": "9.0.4" + } + }, + "Microsoft.Extensions.DependencyInjection": { + "type": "Transitive", + "resolved": "9.0.5", + "contentHash": "N1Mn0T/tUBPoLL+Fzsp+VCEtneUhhxc1//Dx3BeuQ8AX+XrMlYCfnp2zgpEXnTCB7053CLdiqVWPZ7mEX6MPjg==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.5" + } + }, + "Microsoft.Extensions.DependencyInjection.Abstractions": { + "type": "Transitive", + "resolved": "9.0.5", + "contentHash": "cjnRtsEAzU73aN6W7vkWy8Phj5t3Xm78HSqgrbh/O4Q9SK/yN73wZVa21QQY6amSLQRQ/M8N+koGnY6PuvKQsw==" + }, + "Microsoft.Extensions.Logging": { + "type": "Transitive", + "resolved": "9.0.5", + "contentHash": "rQU61lrgvpE/UgcAd4E56HPxUIkX/VUQCxWmwDTLLVeuwRDYTL0q/FLGfAW17cGTKyCh7ywYAEnY3sTEvURsfg==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection": "9.0.5", + "Microsoft.Extensions.Logging.Abstractions": "9.0.5", + "Microsoft.Extensions.Options": "9.0.5" + } + }, + "Microsoft.Extensions.Logging.Abstractions": { + "type": "Transitive", + "resolved": "9.0.5", + "contentHash": "pP1PADCrIxMYJXxFmTVbAgEU7GVpjK5i0/tyfU9DiE0oXQy3JWQaOVgCkrCiePLgS8b5sghM3Fau3EeHiVWbCg==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.5" + } + }, + "Microsoft.Extensions.Options": { + "type": "Transitive", + "resolved": "9.0.5", + "contentHash": "vPdJQU8YLOUSSK8NL0RmwcXJr2E0w8xH559PGQl4JYsglgilZr9LZnqV2zdgk+XR05+kuvhBEZKoDVd46o7NqA==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.5", + "Microsoft.Extensions.Primitives": "9.0.5" + } + }, + "Microsoft.Extensions.Primitives": { + "type": "Transitive", + "resolved": "9.0.5", + "contentHash": "b4OAv1qE1C9aM+ShWJu3rlo/WjDwa/I30aIPXqDWSKXTtKl1Wwh6BZn+glH5HndGVVn3C6ZAPQj5nv7/7HJNBQ==" + }, + "Microsoft.Identity.Client": { + "type": "Transitive", + "resolved": "4.73.1", + "contentHash": "NnDLS8QwYqO5ZZecL2oioi1LUqjh5Ewk4bMLzbgiXJbQmZhDLtKwLxL3DpGMlQAJ2G4KgEnvGPKa+OOgffeJbw==", + "dependencies": { + "Microsoft.IdentityModel.Abstractions": "6.35.0" + } + }, + "Microsoft.Identity.Client.Extensions.Msal": { + "type": "Transitive", + "resolved": "4.73.1", + "contentHash": "xDztAiV2F0wI0W8FLKv5cbaBefyLD6JVaAsvgSN7bjWNCzGYzHbcOEIP5s4TJXUpQzMfUyBsFl1mC6Zmgpz0PQ==", + "dependencies": { + "Microsoft.Identity.Client": "4.73.1", + "System.Security.Cryptography.ProtectedData": "4.5.0" + } + }, + "Microsoft.IdentityModel.Abstractions": { + "type": "Transitive", + "resolved": "7.7.1", + "contentHash": "S7sHg6gLg7oFqNGLwN1qSbJDI+QcRRj8SuJ1jHyCmKSipnF6ZQL+tFV2NzVfGj/xmGT9TykQdQiBN+p5Idl4TA==" + }, + "Microsoft.IdentityModel.JsonWebTokens": { + "type": "Transitive", + "resolved": "7.7.1", + "contentHash": "3Izi75UCUssvo8LPx3OVnEeZay58qaFicrtSnbtUt7q8qQi0gy46gh4V8VUTkMVMKXV6VMyjBVmeNNgeCUJuIw==", + "dependencies": { + "Microsoft.IdentityModel.Tokens": "7.7.1" + } + }, + "Microsoft.IdentityModel.Logging": { + "type": "Transitive", + "resolved": "7.7.1", + "contentHash": "BZNgSq/o8gsKExdYoBKPR65fdsxW0cTF8PsdqB8y011AGUJJW300S/ZIsEUD0+sOmGc003Gwv3FYbjrVjvsLNQ==", + "dependencies": { + "Microsoft.IdentityModel.Abstractions": "7.7.1" + } + }, + "Microsoft.IdentityModel.Protocols": { + "type": "Transitive", + "resolved": "7.7.1", + "contentHash": "h+fHHBGokepmCX+QZXJk4Ij8OApCb2n2ktoDkNX5CXteXsOxTHMNgjPGpAwdJMFvAL7TtGarUnk3o97NmBq2QQ==", + "dependencies": { + "Microsoft.IdentityModel.Tokens": "7.7.1" + } + }, + "Microsoft.IdentityModel.Protocols.OpenIdConnect": { + "type": "Transitive", + "resolved": "7.7.1", + "contentHash": "yT2Hdj8LpPbcT9C9KlLVxXl09C8zjFaVSaApdOwuecMuoV4s6Sof/mnTDz/+F/lILPIBvrWugR9CC7iRVZgbfQ==", + "dependencies": { + "Microsoft.IdentityModel.Protocols": "7.7.1", + "System.IdentityModel.Tokens.Jwt": "7.7.1" + } + }, + "Microsoft.IdentityModel.Tokens": { + "type": "Transitive", + "resolved": "7.7.1", + "contentHash": "fQ0VVCba75lknUHGldi3iTKAYUQqbzp1Un8+d9cm9nON0Gs8NAkXddNg8iaUB0qi/ybtAmNWizTR4avdkCJ9pQ==", + "dependencies": { + "Microsoft.IdentityModel.Logging": "7.7.1" + } + }, + "Microsoft.NET.StringTools": { + "type": "Transitive", + "resolved": "18.0.2", + "contentHash": "cTZw3GHkAlqZACYGeQT3niS3UfVQ8CH0O5+zUdhxstrg1Z8Q2ViXYFKjSxHmEXTX85mrOT/QnHZOeQhhSsIrkQ==" + }, + "Microsoft.SqlServer.Server": { + "type": "Transitive", + "resolved": "1.0.0", + "contentHash": "N4KeF3cpcm1PUHym1RmakkzfkEv3GRMyofVv40uXsQhCQeglr2OHNcUk2WOG51AKpGO8ynGpo9M/kFXSzghwug==" + }, + "Mono.Unix": { + "type": "Transitive", + "resolved": "7.1.0-final.1.21458.1", + "contentHash": "Rhxz4A7By8Q0wEgDqR+mioDsYXGrcYMYPiWE9bSaUKMpG8yAGArhetEQV5Ms6KhKCLdQTlPYLBKPZYoKbAvT/g==" + }, + "MySqlConnector": { + "type": "Transitive", + "resolved": "2.4.0", + "contentHash": "78M+gVOjbdZEDIyXQqcA7EYlCGS3tpbUELHvn6638A2w0pkPI625ixnzsa5staAd3N9/xFmPJtkKDYwsXpFi/w==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2", + "Microsoft.Extensions.Logging.Abstractions": "8.0.2" + } + }, + "Newtonsoft.Json": { + "type": "Transitive", + "resolved": "13.0.3", + "contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==" + }, + "Npgsql": { + "type": "Transitive", + "resolved": "9.0.3", + "contentHash": "tPvY61CxOAWxNsKLEBg+oR646X4Bc8UmyQ/tJszL/7mEmIXQnnBhVJZrZEEUv0Bstu0mEsHZD5At3EO8zQRAYw==", + "dependencies": { + "Microsoft.Extensions.Logging.Abstractions": "8.0.2" + } + }, + "Oracle.ManagedDataAccess.Core": { + "type": "Transitive", + "resolved": "23.7.0", + "contentHash": "psGvNErUu9CO2xHplyp+4fSwDWv6oPKVUE/BRFTIeP2H2YvlstgBPa+Ze1xfAJuVIp2tT6alNtMNPFzAPmIn6Q==", + "dependencies": { + "System.Diagnostics.PerformanceCounter": "8.0.0", + "System.DirectoryServices.Protocols": "8.0.0", + "System.Security.Cryptography.Pkcs": "8.0.0" + } + }, + "PatternKit.Core": { + "type": "Transitive", + "resolved": "0.17.3", + "contentHash": "tnzK650Bnb5VcggnJEKnYbF2gZ/dajS8E3mfU/iuGOHK2s2LJsKI9+K3t+znd2SVgwxV2axsBHcMCj9dbndndw==" + }, + "Snowflake.Data": { + "type": "Transitive", + "resolved": "5.2.1", + "contentHash": "sdOYDe9u6E2yjQ2wio1wRwM0bvHS0vQDgmj8hFF64Dn2k1hU93+Iqpl61k5jlRAUF8/1Et0iCp+wcy4xnBwV7A==", + "dependencies": { + "AWSSDK.S3": "4.0.4", + "Apache.Arrow": "14.0.2", + "Azure.Storage.Blobs": "12.13.0", + "Azure.Storage.Common": "12.12.0", + "BouncyCastle.Cryptography": "2.3.1", + "Google.Cloud.Storage.V1": "4.10.0", + "Microsoft.Extensions.Logging": "9.0.5", + "Mono.Unix": "7.1.0-final.1.21458.1", + "Newtonsoft.Json": "13.0.3", + "System.IdentityModel.Tokens.Jwt": "6.34.0", + "Tomlyn.Signed": "0.17.0" + } + }, + "SQLitePCLRaw.core": { + "type": "Transitive", + "resolved": "2.1.10", + "contentHash": "Ii8JCbC7oiVclaE/mbDEK000EFIJ+ShRPwAvvV89GOZhQ+ZLtlnSWl6ksCNMKu/VGXA4Nfi2B7LhN/QFN9oBcw==" + }, + "System.ClientModel": { + "type": "Transitive", + "resolved": "1.5.1", + "contentHash": "k2jKSO0X45IqhVOT9iQB4xralNN9foRQsRvXBTyRpAVxyzCJlG895T9qYrQWbcJ6OQXxOouJQ37x5nZH5XKK+A==", + "dependencies": { + "Microsoft.Extensions.Logging.Abstractions": "8.0.3", + "System.Memory.Data": "8.0.1" + } + }, + "System.CodeDom": { + "type": "Transitive", + "resolved": "7.0.0", + "contentHash": "GLltyqEsE5/3IE+zYRP5sNa1l44qKl9v+bfdMcwg+M9qnQf47wK3H0SUR/T+3N4JEQXF3vV4CSuuo0rsg+nq2A==" + }, + "System.Configuration.ConfigurationManager": { + "type": "Transitive", + "resolved": "9.0.4", + "contentHash": "dvjqKp+2LpGid6phzrdrS/2mmEPxFl3jE1+L7614q4ZChKbLJCpHXg6sBILlCCED1t//EE+un/UdAetzIMpqnw==", + "dependencies": { + "System.Diagnostics.EventLog": "9.0.4", + "System.Security.Cryptography.ProtectedData": "9.0.4" + } + }, + "System.Diagnostics.EventLog": { + "type": "Transitive", + "resolved": "9.0.4", + "contentHash": "getRQEXD8idlpb1KW56XuxImMy0FKp2WJPDf3Qr0kI/QKxxJSftqfDFVo0DZ3HCJRLU73qHSruv5q2l5O47jQQ==" + }, + "System.Diagnostics.PerformanceCounter": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "lX6DXxtJqVGWw7N/QmVoiCyVQ+Q/Xp+jVXPr3gLK1jJExSn1qmAjJQeb8gnOYeeBTG3E3PmG1nu92eYj/TEjpg==", + "dependencies": { + "System.Configuration.ConfigurationManager": "8.0.0" + } + }, + "System.DirectoryServices.Protocols": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "puwJxURHDrYLGTQdsHyeMS72ClTqYa4lDYz6LHSbkZEk5hq8H8JfsO4MyYhB5BMMxg93jsQzLUwrnCumj11UIg==" + }, + "System.IdentityModel.Tokens.Jwt": { + "type": "Transitive", + "resolved": "7.7.1", + "contentHash": "rQkO1YbAjLwnDJSMpRhRtrc6XwIcEOcUvoEcge+evurpzSZM3UNK+MZfD3sKyTlYsvknZ6eJjSBfnmXqwOsT9Q==", + "dependencies": { + "Microsoft.IdentityModel.JsonWebTokens": "7.7.1", + "Microsoft.IdentityModel.Tokens": "7.7.1" + } + }, + "System.IO.Hashing": { + "type": "Transitive", + "resolved": "10.0.1", + "contentHash": "Dy6ULPb2S0GmNndjKrEIpfibNsc8+FTOoZnqygtFDuyun8vWboQbfMpQtKUXpgTxokR5E4zFHETpNnGfeWY6NA==" + }, + "System.Management": { + "type": "Transitive", + "resolved": "7.0.2", + "contentHash": "/qEUN91mP/MUQmJnM5y5BdT7ZoPuVrtxnFlbJ8a3kBJGhe2wCzBfnPFtK2wTtEEcf3DMGR9J00GZZfg6HRI6yA==", + "dependencies": { + "System.CodeDom": "7.0.0" + } + }, + "System.Memory.Data": { + "type": "Transitive", + "resolved": "8.0.1", + "contentHash": "BVYuec3jV23EMRDeR7Dr1/qhx7369dZzJ9IWy2xylvb4YfXsrUxspWc4UWYid/tj4zZK58uGZqn2WQiaDMhmAg==" + }, + "System.Security.Cryptography.Pkcs": { + "type": "Transitive", + "resolved": "9.0.4", + "contentHash": "cUFTcMlz/Qw9s90b2wnWSCvHdjv51Bau9FQqhsr4TlwSe1OX+7SoXUqphis5G74MLOvMOCghxPPlEqOdCrVVGA==" + }, + "System.Security.Cryptography.ProtectedData": { + "type": "Transitive", + "resolved": "9.0.6", + "contentHash": "yErfw/3pZkJE/VKza/Cm5idTpIKOy/vsmVi59Ta5SruPVtubzxb8CtnE8tyUpzs5pr0Y28GUFfSVzAhCLN3F/Q==" + }, + "Tomlyn.Signed": { + "type": "Transitive", + "resolved": "0.17.0", + "contentHash": "zSItaqXfXlkWYe4xApYrU2rPgHoSlXvU2NyS5jq66bhOyMYuNj48sc8m/guWOt8id1z+cbnHkmEQPpsRWlYoYg==" + }, + "jd.efcpt.build.tasks": { + "type": "Project", + "dependencies": { + "AWSSDK.Core": "[4.0.3.8, )", + "FirebirdSql.Data.FirebirdClient": "[10.3.2, )", + "Microsoft.Build.Framework": "[18.0.2, )", + "Microsoft.Build.Utilities.Core": "[18.0.2, )", + "Microsoft.Data.SqlClient": "[6.1.3, )", + "Microsoft.Data.Sqlite.Core": "[9.0.1, )", + "MySqlConnector": "[2.4.0, )", + "Npgsql": "[9.0.3, )", + "Oracle.ManagedDataAccess.Core": "[23.7.0, )", + "PatternKit.Core": "[0.17.3, )", + "Snowflake.Data": "[5.2.1, )", + "System.IO.Hashing": "[10.0.1, )" + } + } + }, + "net8.0": { + "JD.MSBuild.Fluent": { + "type": "Direct", + "requested": "[1.3.9, )", + "resolved": "1.3.9", + "contentHash": "xBBuXuZnHwfqgJu7Z+9TGnrqyOtZnLI7vA4s90R0IfR2Cv+WEyYj9pXQM/fLAxuD74rSmZyGP7NwBW1s/5cqBw==" + }, + "Apache.Arrow": { + "type": "Transitive", + "resolved": "14.0.2", + "contentHash": "2xvo9q2ag/Ze7TKSMsZfcQFMk3zZKWcduttJXoYnoevZD2bv+lKnOPeleyxONuR1ZwhZ00D86pPM9TWx2GMY2w==" + }, + "AWSSDK.Core": { + "type": "Transitive", + "resolved": "4.0.3.8", + "contentHash": "nJyNzaz3pcD8c8hZvtJXuziJm1dkd3/BYmZvhf1TPNfMo3G3lsesGFZl1UVyQhGEfmQOS+efT0H8tf00PMmjug==" + }, + "AWSSDK.S3": { + "type": "Transitive", + "resolved": "4.0.4", + "contentHash": "Xo/s2vef07V3FIuThclCMaM0IbuPRbF0VvtjvIRxnQNfXpAul/kKgrxM+45oFSIqoCYNgD9pVTzhzHixKQ49dg==", + "dependencies": { + "AWSSDK.Core": "[4.0.0.14, 5.0.0)" + } + }, + "Azure.Core": { + "type": "Transitive", + "resolved": "1.47.1", + "contentHash": "oPcncSsDHuxB8SC522z47xbp2+ttkcKv2YZ90KXhRKN0YQd2+7l1UURT9EBzUNEXtkLZUOAB5xbByMTrYRh3yA==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "8.0.0", + "System.ClientModel": "1.5.1", + "System.Memory.Data": "8.0.1" + } + }, + "Azure.Identity": { + "type": "Transitive", + "resolved": "1.14.2", + "contentHash": "YhNMwOTwT+I2wIcJKSdP0ADyB2aK+JaYWZxO8LSRDm5w77LFr0ykR9xmt2ZV5T1gaI7xU6iNFIh/yW1dAlpddQ==", + "dependencies": { + "Azure.Core": "1.46.1", + "Microsoft.Identity.Client": "4.73.1", + "Microsoft.Identity.Client.Extensions.Msal": "4.73.1" + } + }, + "Azure.Storage.Blobs": { + "type": "Transitive", + "resolved": "12.13.0", + "contentHash": "h5ZxRwmS/U1NOFwd+MuHJe4To1hEPu/yeBIKS1cbAHTDc+7RBZEjPf1VFeUZsIIuHvU/AzXtcRaph9BHuPRNMQ==", + "dependencies": { + "Azure.Storage.Common": "12.12.0" + } + }, + "Azure.Storage.Common": { + "type": "Transitive", + "resolved": "12.12.0", + "contentHash": "Ms0XsZ/D9Pcudfbqj+rWeCkhx/ITEq8isY0jkor9JFmDAEHsItFa2XrWkzP3vmJU6EsXQrk4snH63HkW/Jksvg==", + "dependencies": { + "Azure.Core": "1.25.0", + "System.IO.Hashing": "6.0.0" + } + }, + "BouncyCastle.Cryptography": { + "type": "Transitive", + "resolved": "2.3.1", + "contentHash": "buwoISwecYke3CmgG1AQSg+sNZjJeIb93vTAtJiHZX35hP/teYMxsfg0NDXGUKjGx6BKBTNKc77O2M3vKvlXZQ==" + }, + "FirebirdSql.Data.FirebirdClient": { + "type": "Transitive", + "resolved": "10.3.2", + "contentHash": "mo74lexrjTPAQ4XGrVWTdXy1wEnLKl/KcUeHO8HqEcULrqo5HfZmhgbClqIPogeQ6TY6Jh1EClfHa9ALn5IxfQ==" + }, + "Google.Api.Gax": { + "type": "Transitive", + "resolved": "4.8.0", + "contentHash": "xlV8Jq/G5CQAA3PwYAuKGjfzGOP7AvjhREnE6vgZlzxREGYchHudZWa2PWSqFJL+MBtz9YgitLpRogANN3CVvg==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "6.0.0", + "Newtonsoft.Json": "13.0.3" + } + }, + "Google.Api.Gax.Rest": { + "type": "Transitive", + "resolved": "4.8.0", + "contentHash": "zaA5LZ2VvGj/wwIzRB68swr7khi2kWNgqWvsB0fYtScIAl3kGkGtqiBcx63H1YLeKr5xau1866bFjTeReH6FSQ==", + "dependencies": { + "Google.Api.Gax": "4.8.0", + "Google.Apis.Auth": "[1.67.0, 2.0.0)", + "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0" + } + }, + "Google.Apis": { + "type": "Transitive", + "resolved": "1.67.0", + "contentHash": "XM8/fViJaB1pN61OdXy5RMZoQEqd3hKlWvA/K431gFSb5XtQ48BynfgrbBkUtFcPbSRa4BdjBHzSbkBh/skyMg==", + "dependencies": { + "Google.Apis.Core": "1.67.0" + } + }, + "Google.Apis.Auth": { + "type": "Transitive", + "resolved": "1.67.0", + "contentHash": "Bs9BlbZ12Y4NXzMONjpzQhZr9VbwLUTGMHkcQRF36aYnk2fYrmj5HNVNh7PPHDDq1fcEQpCtPic2nSlpYQLKXw==", + "dependencies": { + "Google.Apis": "1.67.0", + "Google.Apis.Core": "1.67.0", + "System.Management": "7.0.2" + } + }, + "Google.Apis.Core": { + "type": "Transitive", + "resolved": "1.67.0", + "contentHash": "IPq0I3B01NYZraPoMl8muELFLg4Vr2sbfyZp4PR2Xe3MAhHkZCiKyV28Yh1L14zIKUb0X0snol1sR5/mx4S6Iw==", + "dependencies": { + "Newtonsoft.Json": "13.0.3" + } + }, + "Google.Apis.Storage.v1": { + "type": "Transitive", + "resolved": "1.67.0.3365", + "contentHash": "N9Rp8aRUV8Fsjl6uojZeJnzZ/zwtImB+crkPz/HsUtIKcC8rx/ZhNdizNJ5YcNFKiVlvGC60p0K7M+Ywk2xTPQ==", + "dependencies": { + "Google.Apis": "1.67.0", + "Google.Apis.Auth": "1.67.0" + } + }, + "Google.Cloud.Storage.V1": { + "type": "Transitive", + "resolved": "4.10.0", + "contentHash": "a4hHQzDkzR/5Fm2gvfKnvuajYwgTJAZ944+8S3gO7S3qxXkXI+rasx8Jz8ldflyq1zHO5MWTyFiHc7+dfmwYhg==", + "dependencies": { + "Google.Api.Gax.Rest": "[4.8.0, 5.0.0)", + "Google.Apis.Storage.v1": "[1.67.0.3365, 2.0.0)" + } + }, + "Microsoft.Bcl.AsyncInterfaces": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "3WA9q9yVqJp222P3x1wYIGDAkpjAku0TMUaaQV22g6L67AI0LdOIrVS7Ht2vJfLHGSPVuqN94vIr15qn+HEkHw==" + }, + "Microsoft.Bcl.Cryptography": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "Y3t/c7C5XHJGFDnohjf1/9SYF3ZOfEU1fkNQuKg/dGf9hN18yrQj2owHITGfNS3+lKJdW6J4vY98jYu57jCO8A==" + }, + "Microsoft.Build.Framework": { + "type": "Transitive", + "resolved": "18.0.2", + "contentHash": "sOSb+0J4G/jCBW/YqmRuL0eOMXgfw1KQLdC9TkbvfA5xs7uNm+PBQXJCOzSJGXtZcZrtXozcwxPmUiRUbmd7FA==" + }, + "Microsoft.Build.Utilities.Core": { + "type": "Transitive", + "resolved": "18.0.2", + "contentHash": "qsI2Mc8tbJEyg5m4oTvxlu5wY8te0TIVxObxILvrrPdeFUwH5V5UXUT2RV054b3S9msIR+7zViTWp4nRp0YGbQ==", + "dependencies": { + "Microsoft.Build.Framework": "18.0.2" + } + }, + "Microsoft.Data.SqlClient": { + "type": "Transitive", + "resolved": "6.1.3", + "contentHash": "ys/z8Tx8074CDU20EilNvBRJuJdwKSthpHkzUpt3JghnjB6GjbZusoOcCtNbhPCCWsEJqN8bxaT7HnS3UZuUDQ==", + "dependencies": { + "Azure.Core": "1.47.1", + "Azure.Identity": "1.14.2", + "Microsoft.Bcl.Cryptography": "8.0.0", + "Microsoft.Data.SqlClient.SNI.runtime": "6.0.2", + "Microsoft.Extensions.Caching.Memory": "8.0.1", + "Microsoft.IdentityModel.JsonWebTokens": "7.7.1", + "Microsoft.IdentityModel.Protocols.OpenIdConnect": "7.7.1", + "Microsoft.SqlServer.Server": "1.0.0", + "System.Configuration.ConfigurationManager": "8.0.1", + "System.Security.Cryptography.Pkcs": "8.0.1" + } + }, + "Microsoft.Data.SqlClient.SNI.runtime": { + "type": "Transitive", + "resolved": "6.0.2", + "contentHash": "f+pRODTWX7Y67jXO3T5S2dIPZ9qMJNySjlZT/TKmWVNWe19N8jcWmHaqHnnchaq3gxEKv1SWVY5EFzOD06l41w==" + }, + "Microsoft.Data.Sqlite.Core": { + "type": "Transitive", + "resolved": "9.0.1", + "contentHash": "useMNbAupB8gpEp/SjanW3LvvyFG9DWPMUcXFwVNjNuFWIxNcrs5zOu9BTmNJEyfDpLlrsSBmcBv7keYVG8UhA==", + "dependencies": { + "SQLitePCLRaw.core": "2.1.10" + } + }, + "Microsoft.Extensions.Caching.Abstractions": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "3KuSxeHoNYdxVYfg2IRZCThcrlJ1XJqIXkAWikCsbm5C/bCjv7G0WoKDyuR98Q+T607QT2Zl5GsbGRkENcV2yQ==", + "dependencies": { + "Microsoft.Extensions.Primitives": "8.0.0" + } + }, + "Microsoft.Extensions.Caching.Memory": { + "type": "Transitive", + "resolved": "8.0.1", + "contentHash": "HFDnhYLccngrzyGgHkjEDU5FMLn4MpOsr5ElgsBMC4yx6lJh4jeWO7fHS8+TXPq+dgxCmUa/Trl8svObmwW4QA==", + "dependencies": { + "Microsoft.Extensions.Caching.Abstractions": "8.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2", + "Microsoft.Extensions.Logging.Abstractions": "8.0.2", + "Microsoft.Extensions.Options": "8.0.2", + "Microsoft.Extensions.Primitives": "8.0.0" + } + }, + "Microsoft.Extensions.DependencyInjection": { + "type": "Transitive", + "resolved": "9.0.5", + "contentHash": "N1Mn0T/tUBPoLL+Fzsp+VCEtneUhhxc1//Dx3BeuQ8AX+XrMlYCfnp2zgpEXnTCB7053CLdiqVWPZ7mEX6MPjg==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.5" + } + }, + "Microsoft.Extensions.DependencyInjection.Abstractions": { + "type": "Transitive", + "resolved": "9.0.5", + "contentHash": "cjnRtsEAzU73aN6W7vkWy8Phj5t3Xm78HSqgrbh/O4Q9SK/yN73wZVa21QQY6amSLQRQ/M8N+koGnY6PuvKQsw==" + }, + "Microsoft.Extensions.Logging": { + "type": "Transitive", + "resolved": "9.0.5", + "contentHash": "rQU61lrgvpE/UgcAd4E56HPxUIkX/VUQCxWmwDTLLVeuwRDYTL0q/FLGfAW17cGTKyCh7ywYAEnY3sTEvURsfg==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection": "9.0.5", + "Microsoft.Extensions.Logging.Abstractions": "9.0.5", + "Microsoft.Extensions.Options": "9.0.5" + } + }, + "Microsoft.Extensions.Logging.Abstractions": { + "type": "Transitive", + "resolved": "9.0.5", + "contentHash": "pP1PADCrIxMYJXxFmTVbAgEU7GVpjK5i0/tyfU9DiE0oXQy3JWQaOVgCkrCiePLgS8b5sghM3Fau3EeHiVWbCg==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.5", + "System.Diagnostics.DiagnosticSource": "9.0.5" + } + }, + "Microsoft.Extensions.Options": { + "type": "Transitive", + "resolved": "9.0.5", + "contentHash": "vPdJQU8YLOUSSK8NL0RmwcXJr2E0w8xH559PGQl4JYsglgilZr9LZnqV2zdgk+XR05+kuvhBEZKoDVd46o7NqA==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.5", + "Microsoft.Extensions.Primitives": "9.0.5" + } + }, + "Microsoft.Extensions.Primitives": { + "type": "Transitive", + "resolved": "9.0.5", + "contentHash": "b4OAv1qE1C9aM+ShWJu3rlo/WjDwa/I30aIPXqDWSKXTtKl1Wwh6BZn+glH5HndGVVn3C6ZAPQj5nv7/7HJNBQ==" + }, + "Microsoft.Identity.Client": { + "type": "Transitive", + "resolved": "4.73.1", + "contentHash": "NnDLS8QwYqO5ZZecL2oioi1LUqjh5Ewk4bMLzbgiXJbQmZhDLtKwLxL3DpGMlQAJ2G4KgEnvGPKa+OOgffeJbw==", + "dependencies": { + "Microsoft.IdentityModel.Abstractions": "6.35.0" + } + }, + "Microsoft.Identity.Client.Extensions.Msal": { + "type": "Transitive", + "resolved": "4.73.1", + "contentHash": "xDztAiV2F0wI0W8FLKv5cbaBefyLD6JVaAsvgSN7bjWNCzGYzHbcOEIP5s4TJXUpQzMfUyBsFl1mC6Zmgpz0PQ==", + "dependencies": { + "Microsoft.Identity.Client": "4.73.1", + "System.Security.Cryptography.ProtectedData": "4.5.0" + } + }, + "Microsoft.IdentityModel.Abstractions": { + "type": "Transitive", + "resolved": "7.7.1", + "contentHash": "S7sHg6gLg7oFqNGLwN1qSbJDI+QcRRj8SuJ1jHyCmKSipnF6ZQL+tFV2NzVfGj/xmGT9TykQdQiBN+p5Idl4TA==" + }, + "Microsoft.IdentityModel.JsonWebTokens": { + "type": "Transitive", + "resolved": "7.7.1", + "contentHash": "3Izi75UCUssvo8LPx3OVnEeZay58qaFicrtSnbtUt7q8qQi0gy46gh4V8VUTkMVMKXV6VMyjBVmeNNgeCUJuIw==", + "dependencies": { + "Microsoft.IdentityModel.Tokens": "7.7.1" + } + }, + "Microsoft.IdentityModel.Logging": { + "type": "Transitive", + "resolved": "7.7.1", + "contentHash": "BZNgSq/o8gsKExdYoBKPR65fdsxW0cTF8PsdqB8y011AGUJJW300S/ZIsEUD0+sOmGc003Gwv3FYbjrVjvsLNQ==", + "dependencies": { + "Microsoft.IdentityModel.Abstractions": "7.7.1" + } + }, + "Microsoft.IdentityModel.Protocols": { + "type": "Transitive", + "resolved": "7.7.1", + "contentHash": "h+fHHBGokepmCX+QZXJk4Ij8OApCb2n2ktoDkNX5CXteXsOxTHMNgjPGpAwdJMFvAL7TtGarUnk3o97NmBq2QQ==", + "dependencies": { + "Microsoft.IdentityModel.Tokens": "7.7.1" + } + }, + "Microsoft.IdentityModel.Protocols.OpenIdConnect": { + "type": "Transitive", + "resolved": "7.7.1", + "contentHash": "yT2Hdj8LpPbcT9C9KlLVxXl09C8zjFaVSaApdOwuecMuoV4s6Sof/mnTDz/+F/lILPIBvrWugR9CC7iRVZgbfQ==", + "dependencies": { + "Microsoft.IdentityModel.Protocols": "7.7.1", + "System.IdentityModel.Tokens.Jwt": "7.7.1" + } + }, + "Microsoft.IdentityModel.Tokens": { + "type": "Transitive", + "resolved": "7.7.1", + "contentHash": "fQ0VVCba75lknUHGldi3iTKAYUQqbzp1Un8+d9cm9nON0Gs8NAkXddNg8iaUB0qi/ybtAmNWizTR4avdkCJ9pQ==", + "dependencies": { + "Microsoft.IdentityModel.Logging": "7.7.1" + } + }, + "Microsoft.SqlServer.Server": { + "type": "Transitive", + "resolved": "1.0.0", + "contentHash": "N4KeF3cpcm1PUHym1RmakkzfkEv3GRMyofVv40uXsQhCQeglr2OHNcUk2WOG51AKpGO8ynGpo9M/kFXSzghwug==" + }, + "Mono.Unix": { + "type": "Transitive", + "resolved": "7.1.0-final.1.21458.1", + "contentHash": "Rhxz4A7By8Q0wEgDqR+mioDsYXGrcYMYPiWE9bSaUKMpG8yAGArhetEQV5Ms6KhKCLdQTlPYLBKPZYoKbAvT/g==" + }, + "MySqlConnector": { + "type": "Transitive", + "resolved": "2.4.0", + "contentHash": "78M+gVOjbdZEDIyXQqcA7EYlCGS3tpbUELHvn6638A2w0pkPI625ixnzsa5staAd3N9/xFmPJtkKDYwsXpFi/w==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2", + "Microsoft.Extensions.Logging.Abstractions": "8.0.2" + } + }, + "Newtonsoft.Json": { + "type": "Transitive", + "resolved": "13.0.3", + "contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==" + }, + "Npgsql": { + "type": "Transitive", + "resolved": "9.0.3", + "contentHash": "tPvY61CxOAWxNsKLEBg+oR646X4Bc8UmyQ/tJszL/7mEmIXQnnBhVJZrZEEUv0Bstu0mEsHZD5At3EO8zQRAYw==", + "dependencies": { + "Microsoft.Extensions.Logging.Abstractions": "8.0.2" + } + }, + "Oracle.ManagedDataAccess.Core": { + "type": "Transitive", + "resolved": "23.7.0", + "contentHash": "psGvNErUu9CO2xHplyp+4fSwDWv6oPKVUE/BRFTIeP2H2YvlstgBPa+Ze1xfAJuVIp2tT6alNtMNPFzAPmIn6Q==", + "dependencies": { + "System.Diagnostics.PerformanceCounter": "8.0.0", + "System.DirectoryServices.Protocols": "8.0.0", + "System.Security.Cryptography.Pkcs": "8.0.0" + } + }, + "PatternKit.Core": { + "type": "Transitive", + "resolved": "0.17.3", + "contentHash": "tnzK650Bnb5VcggnJEKnYbF2gZ/dajS8E3mfU/iuGOHK2s2LJsKI9+K3t+znd2SVgwxV2axsBHcMCj9dbndndw==" + }, + "Snowflake.Data": { + "type": "Transitive", + "resolved": "5.2.1", + "contentHash": "sdOYDe9u6E2yjQ2wio1wRwM0bvHS0vQDgmj8hFF64Dn2k1hU93+Iqpl61k5jlRAUF8/1Et0iCp+wcy4xnBwV7A==", + "dependencies": { + "AWSSDK.S3": "4.0.4", + "Apache.Arrow": "14.0.2", + "Azure.Storage.Blobs": "12.13.0", + "Azure.Storage.Common": "12.12.0", + "BouncyCastle.Cryptography": "2.3.1", + "Google.Cloud.Storage.V1": "4.10.0", + "Microsoft.Extensions.Logging": "9.0.5", + "Mono.Unix": "7.1.0-final.1.21458.1", + "Newtonsoft.Json": "13.0.3", + "System.IdentityModel.Tokens.Jwt": "6.34.0", + "Tomlyn.Signed": "0.17.0" + } + }, + "SQLitePCLRaw.core": { + "type": "Transitive", + "resolved": "2.1.10", + "contentHash": "Ii8JCbC7oiVclaE/mbDEK000EFIJ+ShRPwAvvV89GOZhQ+ZLtlnSWl6ksCNMKu/VGXA4Nfi2B7LhN/QFN9oBcw==" + }, + "System.ClientModel": { + "type": "Transitive", + "resolved": "1.5.1", + "contentHash": "k2jKSO0X45IqhVOT9iQB4xralNN9foRQsRvXBTyRpAVxyzCJlG895T9qYrQWbcJ6OQXxOouJQ37x5nZH5XKK+A==", + "dependencies": { + "Microsoft.Extensions.Logging.Abstractions": "8.0.3", + "System.Memory.Data": "8.0.1" + } + }, + "System.CodeDom": { + "type": "Transitive", + "resolved": "7.0.0", + "contentHash": "GLltyqEsE5/3IE+zYRP5sNa1l44qKl9v+bfdMcwg+M9qnQf47wK3H0SUR/T+3N4JEQXF3vV4CSuuo0rsg+nq2A==" + }, + "System.Configuration.ConfigurationManager": { + "type": "Transitive", + "resolved": "8.0.1", + "contentHash": "gPYFPDyohW2gXNhdQRSjtmeS6FymL2crg4Sral1wtvEJ7DUqFCDWDVbbLobASbzxfic8U1hQEdC7hmg9LHncMw==", + "dependencies": { + "System.Diagnostics.EventLog": "8.0.1", + "System.Security.Cryptography.ProtectedData": "8.0.0" + } + }, + "System.Diagnostics.DiagnosticSource": { + "type": "Transitive", + "resolved": "9.0.5", + "contentHash": "WoI5or8kY2VxFdDmsaRZ5yaYvvb+4MCyy66eXo79Cy1uMa7qXeGIlYmZx7R9Zy5S4xZjmqvkk2V8L6/vDwAAEA==" + }, + "System.Diagnostics.EventLog": { + "type": "Transitive", + "resolved": "8.0.1", + "contentHash": "n1ZP7NM2Gkn/MgD8+eOT5MulMj6wfeQMNS2Pizvq5GHCZfjlFMXV2irQlQmJhwA2VABC57M0auudO89Iu2uRLg==" + }, + "System.Diagnostics.PerformanceCounter": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "lX6DXxtJqVGWw7N/QmVoiCyVQ+Q/Xp+jVXPr3gLK1jJExSn1qmAjJQeb8gnOYeeBTG3E3PmG1nu92eYj/TEjpg==", + "dependencies": { + "System.Configuration.ConfigurationManager": "8.0.0" + } + }, + "System.DirectoryServices.Protocols": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "puwJxURHDrYLGTQdsHyeMS72ClTqYa4lDYz6LHSbkZEk5hq8H8JfsO4MyYhB5BMMxg93jsQzLUwrnCumj11UIg==" + }, + "System.IdentityModel.Tokens.Jwt": { + "type": "Transitive", + "resolved": "7.7.1", + "contentHash": "rQkO1YbAjLwnDJSMpRhRtrc6XwIcEOcUvoEcge+evurpzSZM3UNK+MZfD3sKyTlYsvknZ6eJjSBfnmXqwOsT9Q==", + "dependencies": { + "Microsoft.IdentityModel.JsonWebTokens": "7.7.1", + "Microsoft.IdentityModel.Tokens": "7.7.1" + } + }, + "System.IO.Hashing": { + "type": "Transitive", + "resolved": "10.0.1", + "contentHash": "Dy6ULPb2S0GmNndjKrEIpfibNsc8+FTOoZnqygtFDuyun8vWboQbfMpQtKUXpgTxokR5E4zFHETpNnGfeWY6NA==" + }, + "System.Management": { + "type": "Transitive", + "resolved": "7.0.2", + "contentHash": "/qEUN91mP/MUQmJnM5y5BdT7ZoPuVrtxnFlbJ8a3kBJGhe2wCzBfnPFtK2wTtEEcf3DMGR9J00GZZfg6HRI6yA==", + "dependencies": { + "System.CodeDom": "7.0.0" + } + }, + "System.Memory.Data": { + "type": "Transitive", + "resolved": "8.0.1", + "contentHash": "BVYuec3jV23EMRDeR7Dr1/qhx7369dZzJ9IWy2xylvb4YfXsrUxspWc4UWYid/tj4zZK58uGZqn2WQiaDMhmAg==" + }, + "System.Security.Cryptography.Pkcs": { + "type": "Transitive", + "resolved": "8.0.1", + "contentHash": "CoCRHFym33aUSf/NtWSVSZa99dkd0Hm7OCZUxORBjRB16LNhIEOf8THPqzIYlvKM0nNDAPTRBa1FxEECrgaxxA==" + }, + "System.Security.Cryptography.ProtectedData": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "+TUFINV2q2ifyXauQXRwy4CiBhqvDEDZeVJU7qfxya4aRYOKzVBpN+4acx25VcPB9ywUN6C0n8drWl110PhZEg==" + }, + "Tomlyn.Signed": { + "type": "Transitive", + "resolved": "0.17.0", + "contentHash": "zSItaqXfXlkWYe4xApYrU2rPgHoSlXvU2NyS5jq66bhOyMYuNj48sc8m/guWOt8id1z+cbnHkmEQPpsRWlYoYg==" + }, + "jd.efcpt.build.tasks": { + "type": "Project", + "dependencies": { + "AWSSDK.Core": "[4.0.3.8, )", + "FirebirdSql.Data.FirebirdClient": "[10.3.2, )", + "Microsoft.Build.Framework": "[18.0.2, )", + "Microsoft.Build.Utilities.Core": "[18.0.2, )", + "Microsoft.Data.SqlClient": "[6.1.3, )", + "Microsoft.Data.Sqlite.Core": "[9.0.1, )", + "MySqlConnector": "[2.4.0, )", + "Npgsql": "[9.0.3, )", + "Oracle.ManagedDataAccess.Core": "[23.7.0, )", + "PatternKit.Core": "[0.17.3, )", + "Snowflake.Data": "[5.2.1, )", + "System.IO.Hashing": "[10.0.1, )" + } + } + }, + "net9.0": { + "JD.MSBuild.Fluent": { + "type": "Direct", + "requested": "[1.3.9, )", + "resolved": "1.3.9", + "contentHash": "xBBuXuZnHwfqgJu7Z+9TGnrqyOtZnLI7vA4s90R0IfR2Cv+WEyYj9pXQM/fLAxuD74rSmZyGP7NwBW1s/5cqBw==" + }, + "Apache.Arrow": { + "type": "Transitive", + "resolved": "14.0.2", + "contentHash": "2xvo9q2ag/Ze7TKSMsZfcQFMk3zZKWcduttJXoYnoevZD2bv+lKnOPeleyxONuR1ZwhZ00D86pPM9TWx2GMY2w==" + }, + "AWSSDK.Core": { + "type": "Transitive", + "resolved": "4.0.3.8", + "contentHash": "nJyNzaz3pcD8c8hZvtJXuziJm1dkd3/BYmZvhf1TPNfMo3G3lsesGFZl1UVyQhGEfmQOS+efT0H8tf00PMmjug==" + }, + "AWSSDK.S3": { + "type": "Transitive", + "resolved": "4.0.4", + "contentHash": "Xo/s2vef07V3FIuThclCMaM0IbuPRbF0VvtjvIRxnQNfXpAul/kKgrxM+45oFSIqoCYNgD9pVTzhzHixKQ49dg==", + "dependencies": { + "AWSSDK.Core": "[4.0.0.14, 5.0.0)" + } + }, + "Azure.Core": { + "type": "Transitive", + "resolved": "1.47.1", + "contentHash": "oPcncSsDHuxB8SC522z47xbp2+ttkcKv2YZ90KXhRKN0YQd2+7l1UURT9EBzUNEXtkLZUOAB5xbByMTrYRh3yA==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "8.0.0", + "System.ClientModel": "1.5.1", + "System.Memory.Data": "8.0.1" + } + }, + "Azure.Identity": { + "type": "Transitive", + "resolved": "1.14.2", + "contentHash": "YhNMwOTwT+I2wIcJKSdP0ADyB2aK+JaYWZxO8LSRDm5w77LFr0ykR9xmt2ZV5T1gaI7xU6iNFIh/yW1dAlpddQ==", + "dependencies": { + "Azure.Core": "1.46.1", + "Microsoft.Identity.Client": "4.73.1", + "Microsoft.Identity.Client.Extensions.Msal": "4.73.1" + } + }, + "Azure.Storage.Blobs": { + "type": "Transitive", + "resolved": "12.13.0", + "contentHash": "h5ZxRwmS/U1NOFwd+MuHJe4To1hEPu/yeBIKS1cbAHTDc+7RBZEjPf1VFeUZsIIuHvU/AzXtcRaph9BHuPRNMQ==", + "dependencies": { + "Azure.Storage.Common": "12.12.0" + } + }, + "Azure.Storage.Common": { + "type": "Transitive", + "resolved": "12.12.0", + "contentHash": "Ms0XsZ/D9Pcudfbqj+rWeCkhx/ITEq8isY0jkor9JFmDAEHsItFa2XrWkzP3vmJU6EsXQrk4snH63HkW/Jksvg==", + "dependencies": { + "Azure.Core": "1.25.0", + "System.IO.Hashing": "6.0.0" + } + }, + "BouncyCastle.Cryptography": { + "type": "Transitive", + "resolved": "2.3.1", + "contentHash": "buwoISwecYke3CmgG1AQSg+sNZjJeIb93vTAtJiHZX35hP/teYMxsfg0NDXGUKjGx6BKBTNKc77O2M3vKvlXZQ==" + }, + "FirebirdSql.Data.FirebirdClient": { + "type": "Transitive", + "resolved": "10.3.2", + "contentHash": "mo74lexrjTPAQ4XGrVWTdXy1wEnLKl/KcUeHO8HqEcULrqo5HfZmhgbClqIPogeQ6TY6Jh1EClfHa9ALn5IxfQ==" + }, + "Google.Api.Gax": { + "type": "Transitive", + "resolved": "4.8.0", + "contentHash": "xlV8Jq/G5CQAA3PwYAuKGjfzGOP7AvjhREnE6vgZlzxREGYchHudZWa2PWSqFJL+MBtz9YgitLpRogANN3CVvg==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "6.0.0", + "Newtonsoft.Json": "13.0.3" + } + }, + "Google.Api.Gax.Rest": { + "type": "Transitive", + "resolved": "4.8.0", + "contentHash": "zaA5LZ2VvGj/wwIzRB68swr7khi2kWNgqWvsB0fYtScIAl3kGkGtqiBcx63H1YLeKr5xau1866bFjTeReH6FSQ==", + "dependencies": { + "Google.Api.Gax": "4.8.0", + "Google.Apis.Auth": "[1.67.0, 2.0.0)", + "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0" + } + }, + "Google.Apis": { + "type": "Transitive", + "resolved": "1.67.0", + "contentHash": "XM8/fViJaB1pN61OdXy5RMZoQEqd3hKlWvA/K431gFSb5XtQ48BynfgrbBkUtFcPbSRa4BdjBHzSbkBh/skyMg==", + "dependencies": { + "Google.Apis.Core": "1.67.0" + } + }, + "Google.Apis.Auth": { + "type": "Transitive", + "resolved": "1.67.0", + "contentHash": "Bs9BlbZ12Y4NXzMONjpzQhZr9VbwLUTGMHkcQRF36aYnk2fYrmj5HNVNh7PPHDDq1fcEQpCtPic2nSlpYQLKXw==", + "dependencies": { + "Google.Apis": "1.67.0", + "Google.Apis.Core": "1.67.0", + "System.Management": "7.0.2" + } + }, + "Google.Apis.Core": { + "type": "Transitive", + "resolved": "1.67.0", + "contentHash": "IPq0I3B01NYZraPoMl8muELFLg4Vr2sbfyZp4PR2Xe3MAhHkZCiKyV28Yh1L14zIKUb0X0snol1sR5/mx4S6Iw==", + "dependencies": { + "Newtonsoft.Json": "13.0.3" + } + }, + "Google.Apis.Storage.v1": { + "type": "Transitive", + "resolved": "1.67.0.3365", + "contentHash": "N9Rp8aRUV8Fsjl6uojZeJnzZ/zwtImB+crkPz/HsUtIKcC8rx/ZhNdizNJ5YcNFKiVlvGC60p0K7M+Ywk2xTPQ==", + "dependencies": { + "Google.Apis": "1.67.0", + "Google.Apis.Auth": "1.67.0" + } + }, + "Google.Cloud.Storage.V1": { + "type": "Transitive", + "resolved": "4.10.0", + "contentHash": "a4hHQzDkzR/5Fm2gvfKnvuajYwgTJAZ944+8S3gO7S3qxXkXI+rasx8Jz8ldflyq1zHO5MWTyFiHc7+dfmwYhg==", + "dependencies": { + "Google.Api.Gax.Rest": "[4.8.0, 5.0.0)", + "Google.Apis.Storage.v1": "[1.67.0.3365, 2.0.0)" + } + }, + "Microsoft.Bcl.AsyncInterfaces": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "3WA9q9yVqJp222P3x1wYIGDAkpjAku0TMUaaQV22g6L67AI0LdOIrVS7Ht2vJfLHGSPVuqN94vIr15qn+HEkHw==" + }, + "Microsoft.Bcl.Cryptography": { + "type": "Transitive", + "resolved": "9.0.4", + "contentHash": "YgZYAWzyNuPVtPq6WNm0bqOWNjYaWgl5mBWTGZyNoXitYBUYSp6iUB9AwK0V1mo793qRJUXz2t6UZrWITZSvuQ==" + }, + "Microsoft.Build.Framework": { + "type": "Transitive", + "resolved": "18.0.2", + "contentHash": "sOSb+0J4G/jCBW/YqmRuL0eOMXgfw1KQLdC9TkbvfA5xs7uNm+PBQXJCOzSJGXtZcZrtXozcwxPmUiRUbmd7FA==" + }, + "Microsoft.Build.Utilities.Core": { + "type": "Transitive", + "resolved": "18.0.2", + "contentHash": "qsI2Mc8tbJEyg5m4oTvxlu5wY8te0TIVxObxILvrrPdeFUwH5V5UXUT2RV054b3S9msIR+7zViTWp4nRp0YGbQ==", + "dependencies": { + "Microsoft.Build.Framework": "18.0.2" + } + }, + "Microsoft.Data.SqlClient": { + "type": "Transitive", + "resolved": "6.1.3", + "contentHash": "ys/z8Tx8074CDU20EilNvBRJuJdwKSthpHkzUpt3JghnjB6GjbZusoOcCtNbhPCCWsEJqN8bxaT7HnS3UZuUDQ==", + "dependencies": { + "Azure.Core": "1.47.1", + "Azure.Identity": "1.14.2", + "Microsoft.Bcl.Cryptography": "9.0.4", + "Microsoft.Data.SqlClient.SNI.runtime": "6.0.2", + "Microsoft.Extensions.Caching.Memory": "9.0.4", + "Microsoft.IdentityModel.JsonWebTokens": "7.7.1", + "Microsoft.IdentityModel.Protocols.OpenIdConnect": "7.7.1", + "Microsoft.SqlServer.Server": "1.0.0", + "System.Configuration.ConfigurationManager": "9.0.4", + "System.Security.Cryptography.Pkcs": "9.0.4" + } + }, + "Microsoft.Data.SqlClient.SNI.runtime": { + "type": "Transitive", + "resolved": "6.0.2", + "contentHash": "f+pRODTWX7Y67jXO3T5S2dIPZ9qMJNySjlZT/TKmWVNWe19N8jcWmHaqHnnchaq3gxEKv1SWVY5EFzOD06l41w==" + }, + "Microsoft.Data.Sqlite.Core": { + "type": "Transitive", + "resolved": "9.0.1", + "contentHash": "useMNbAupB8gpEp/SjanW3LvvyFG9DWPMUcXFwVNjNuFWIxNcrs5zOu9BTmNJEyfDpLlrsSBmcBv7keYVG8UhA==", + "dependencies": { + "SQLitePCLRaw.core": "2.1.10" + } + }, + "Microsoft.Extensions.Caching.Abstractions": { + "type": "Transitive", + "resolved": "9.0.4", + "contentHash": "imcZ5BGhBw5mNsWLepBbqqumWaFe0GtvyCvne2/2wsDIBRa2+Lhx4cU/pKt/4BwOizzUEOls2k1eOJQXHGMalg==", + "dependencies": { + "Microsoft.Extensions.Primitives": "9.0.4" + } + }, + "Microsoft.Extensions.Caching.Memory": { + "type": "Transitive", + "resolved": "9.0.4", + "contentHash": "G5rEq1Qez5VJDTEyRsRUnewAspKjaY57VGsdZ8g8Ja6sXXzoiI3PpTd1t43HjHqNWD5A06MQveb2lscn+2CU+w==", + "dependencies": { + "Microsoft.Extensions.Caching.Abstractions": "9.0.4", + "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.4", + "Microsoft.Extensions.Logging.Abstractions": "9.0.4", + "Microsoft.Extensions.Options": "9.0.4", + "Microsoft.Extensions.Primitives": "9.0.4" + } + }, + "Microsoft.Extensions.DependencyInjection": { + "type": "Transitive", + "resolved": "9.0.5", + "contentHash": "N1Mn0T/tUBPoLL+Fzsp+VCEtneUhhxc1//Dx3BeuQ8AX+XrMlYCfnp2zgpEXnTCB7053CLdiqVWPZ7mEX6MPjg==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.5" + } + }, + "Microsoft.Extensions.DependencyInjection.Abstractions": { + "type": "Transitive", + "resolved": "9.0.5", + "contentHash": "cjnRtsEAzU73aN6W7vkWy8Phj5t3Xm78HSqgrbh/O4Q9SK/yN73wZVa21QQY6amSLQRQ/M8N+koGnY6PuvKQsw==" + }, + "Microsoft.Extensions.Logging": { + "type": "Transitive", + "resolved": "9.0.5", + "contentHash": "rQU61lrgvpE/UgcAd4E56HPxUIkX/VUQCxWmwDTLLVeuwRDYTL0q/FLGfAW17cGTKyCh7ywYAEnY3sTEvURsfg==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection": "9.0.5", + "Microsoft.Extensions.Logging.Abstractions": "9.0.5", + "Microsoft.Extensions.Options": "9.0.5" + } + }, + "Microsoft.Extensions.Logging.Abstractions": { + "type": "Transitive", + "resolved": "9.0.5", + "contentHash": "pP1PADCrIxMYJXxFmTVbAgEU7GVpjK5i0/tyfU9DiE0oXQy3JWQaOVgCkrCiePLgS8b5sghM3Fau3EeHiVWbCg==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.5" + } + }, + "Microsoft.Extensions.Options": { + "type": "Transitive", + "resolved": "9.0.5", + "contentHash": "vPdJQU8YLOUSSK8NL0RmwcXJr2E0w8xH559PGQl4JYsglgilZr9LZnqV2zdgk+XR05+kuvhBEZKoDVd46o7NqA==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.5", + "Microsoft.Extensions.Primitives": "9.0.5" + } + }, + "Microsoft.Extensions.Primitives": { + "type": "Transitive", + "resolved": "9.0.5", + "contentHash": "b4OAv1qE1C9aM+ShWJu3rlo/WjDwa/I30aIPXqDWSKXTtKl1Wwh6BZn+glH5HndGVVn3C6ZAPQj5nv7/7HJNBQ==" + }, + "Microsoft.Identity.Client": { + "type": "Transitive", + "resolved": "4.73.1", + "contentHash": "NnDLS8QwYqO5ZZecL2oioi1LUqjh5Ewk4bMLzbgiXJbQmZhDLtKwLxL3DpGMlQAJ2G4KgEnvGPKa+OOgffeJbw==", + "dependencies": { + "Microsoft.IdentityModel.Abstractions": "6.35.0" + } + }, + "Microsoft.Identity.Client.Extensions.Msal": { + "type": "Transitive", + "resolved": "4.73.1", + "contentHash": "xDztAiV2F0wI0W8FLKv5cbaBefyLD6JVaAsvgSN7bjWNCzGYzHbcOEIP5s4TJXUpQzMfUyBsFl1mC6Zmgpz0PQ==", + "dependencies": { + "Microsoft.Identity.Client": "4.73.1", + "System.Security.Cryptography.ProtectedData": "4.5.0" + } + }, + "Microsoft.IdentityModel.Abstractions": { + "type": "Transitive", + "resolved": "7.7.1", + "contentHash": "S7sHg6gLg7oFqNGLwN1qSbJDI+QcRRj8SuJ1jHyCmKSipnF6ZQL+tFV2NzVfGj/xmGT9TykQdQiBN+p5Idl4TA==" + }, + "Microsoft.IdentityModel.JsonWebTokens": { + "type": "Transitive", + "resolved": "7.7.1", + "contentHash": "3Izi75UCUssvo8LPx3OVnEeZay58qaFicrtSnbtUt7q8qQi0gy46gh4V8VUTkMVMKXV6VMyjBVmeNNgeCUJuIw==", + "dependencies": { + "Microsoft.IdentityModel.Tokens": "7.7.1" + } + }, + "Microsoft.IdentityModel.Logging": { + "type": "Transitive", + "resolved": "7.7.1", + "contentHash": "BZNgSq/o8gsKExdYoBKPR65fdsxW0cTF8PsdqB8y011AGUJJW300S/ZIsEUD0+sOmGc003Gwv3FYbjrVjvsLNQ==", + "dependencies": { + "Microsoft.IdentityModel.Abstractions": "7.7.1" + } + }, + "Microsoft.IdentityModel.Protocols": { + "type": "Transitive", + "resolved": "7.7.1", + "contentHash": "h+fHHBGokepmCX+QZXJk4Ij8OApCb2n2ktoDkNX5CXteXsOxTHMNgjPGpAwdJMFvAL7TtGarUnk3o97NmBq2QQ==", + "dependencies": { + "Microsoft.IdentityModel.Tokens": "7.7.1" + } + }, + "Microsoft.IdentityModel.Protocols.OpenIdConnect": { + "type": "Transitive", + "resolved": "7.7.1", + "contentHash": "yT2Hdj8LpPbcT9C9KlLVxXl09C8zjFaVSaApdOwuecMuoV4s6Sof/mnTDz/+F/lILPIBvrWugR9CC7iRVZgbfQ==", + "dependencies": { + "Microsoft.IdentityModel.Protocols": "7.7.1", + "System.IdentityModel.Tokens.Jwt": "7.7.1" + } + }, + "Microsoft.IdentityModel.Tokens": { + "type": "Transitive", + "resolved": "7.7.1", + "contentHash": "fQ0VVCba75lknUHGldi3iTKAYUQqbzp1Un8+d9cm9nON0Gs8NAkXddNg8iaUB0qi/ybtAmNWizTR4avdkCJ9pQ==", + "dependencies": { + "Microsoft.IdentityModel.Logging": "7.7.1" + } + }, + "Microsoft.SqlServer.Server": { + "type": "Transitive", + "resolved": "1.0.0", + "contentHash": "N4KeF3cpcm1PUHym1RmakkzfkEv3GRMyofVv40uXsQhCQeglr2OHNcUk2WOG51AKpGO8ynGpo9M/kFXSzghwug==" + }, + "Mono.Unix": { + "type": "Transitive", + "resolved": "7.1.0-final.1.21458.1", + "contentHash": "Rhxz4A7By8Q0wEgDqR+mioDsYXGrcYMYPiWE9bSaUKMpG8yAGArhetEQV5Ms6KhKCLdQTlPYLBKPZYoKbAvT/g==" + }, + "MySqlConnector": { + "type": "Transitive", + "resolved": "2.4.0", + "contentHash": "78M+gVOjbdZEDIyXQqcA7EYlCGS3tpbUELHvn6638A2w0pkPI625ixnzsa5staAd3N9/xFmPJtkKDYwsXpFi/w==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2", + "Microsoft.Extensions.Logging.Abstractions": "8.0.2" + } + }, + "Newtonsoft.Json": { + "type": "Transitive", + "resolved": "13.0.3", + "contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==" + }, + "Npgsql": { + "type": "Transitive", + "resolved": "9.0.3", + "contentHash": "tPvY61CxOAWxNsKLEBg+oR646X4Bc8UmyQ/tJszL/7mEmIXQnnBhVJZrZEEUv0Bstu0mEsHZD5At3EO8zQRAYw==", + "dependencies": { + "Microsoft.Extensions.Logging.Abstractions": "8.0.2" + } + }, + "Oracle.ManagedDataAccess.Core": { + "type": "Transitive", + "resolved": "23.7.0", + "contentHash": "psGvNErUu9CO2xHplyp+4fSwDWv6oPKVUE/BRFTIeP2H2YvlstgBPa+Ze1xfAJuVIp2tT6alNtMNPFzAPmIn6Q==", + "dependencies": { + "System.Diagnostics.PerformanceCounter": "8.0.0", + "System.DirectoryServices.Protocols": "8.0.0", + "System.Security.Cryptography.Pkcs": "8.0.0" + } + }, + "PatternKit.Core": { + "type": "Transitive", + "resolved": "0.17.3", + "contentHash": "tnzK650Bnb5VcggnJEKnYbF2gZ/dajS8E3mfU/iuGOHK2s2LJsKI9+K3t+znd2SVgwxV2axsBHcMCj9dbndndw==" + }, + "Snowflake.Data": { + "type": "Transitive", + "resolved": "5.2.1", + "contentHash": "sdOYDe9u6E2yjQ2wio1wRwM0bvHS0vQDgmj8hFF64Dn2k1hU93+Iqpl61k5jlRAUF8/1Et0iCp+wcy4xnBwV7A==", + "dependencies": { + "AWSSDK.S3": "4.0.4", + "Apache.Arrow": "14.0.2", + "Azure.Storage.Blobs": "12.13.0", + "Azure.Storage.Common": "12.12.0", + "BouncyCastle.Cryptography": "2.3.1", + "Google.Cloud.Storage.V1": "4.10.0", + "Microsoft.Extensions.Logging": "9.0.5", + "Mono.Unix": "7.1.0-final.1.21458.1", + "Newtonsoft.Json": "13.0.3", + "System.IdentityModel.Tokens.Jwt": "6.34.0", + "Tomlyn.Signed": "0.17.0" + } + }, + "SQLitePCLRaw.core": { + "type": "Transitive", + "resolved": "2.1.10", + "contentHash": "Ii8JCbC7oiVclaE/mbDEK000EFIJ+ShRPwAvvV89GOZhQ+ZLtlnSWl6ksCNMKu/VGXA4Nfi2B7LhN/QFN9oBcw==" + }, + "System.ClientModel": { + "type": "Transitive", + "resolved": "1.5.1", + "contentHash": "k2jKSO0X45IqhVOT9iQB4xralNN9foRQsRvXBTyRpAVxyzCJlG895T9qYrQWbcJ6OQXxOouJQ37x5nZH5XKK+A==", + "dependencies": { + "Microsoft.Extensions.Logging.Abstractions": "8.0.3", + "System.Memory.Data": "8.0.1" + } + }, + "System.CodeDom": { + "type": "Transitive", + "resolved": "7.0.0", + "contentHash": "GLltyqEsE5/3IE+zYRP5sNa1l44qKl9v+bfdMcwg+M9qnQf47wK3H0SUR/T+3N4JEQXF3vV4CSuuo0rsg+nq2A==" + }, + "System.Configuration.ConfigurationManager": { + "type": "Transitive", + "resolved": "9.0.4", + "contentHash": "dvjqKp+2LpGid6phzrdrS/2mmEPxFl3jE1+L7614q4ZChKbLJCpHXg6sBILlCCED1t//EE+un/UdAetzIMpqnw==", + "dependencies": { + "System.Diagnostics.EventLog": "9.0.4", + "System.Security.Cryptography.ProtectedData": "9.0.4" + } + }, + "System.Diagnostics.EventLog": { + "type": "Transitive", + "resolved": "9.0.4", + "contentHash": "getRQEXD8idlpb1KW56XuxImMy0FKp2WJPDf3Qr0kI/QKxxJSftqfDFVo0DZ3HCJRLU73qHSruv5q2l5O47jQQ==" + }, + "System.Diagnostics.PerformanceCounter": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "lX6DXxtJqVGWw7N/QmVoiCyVQ+Q/Xp+jVXPr3gLK1jJExSn1qmAjJQeb8gnOYeeBTG3E3PmG1nu92eYj/TEjpg==", + "dependencies": { + "System.Configuration.ConfigurationManager": "8.0.0" + } + }, + "System.DirectoryServices.Protocols": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "puwJxURHDrYLGTQdsHyeMS72ClTqYa4lDYz6LHSbkZEk5hq8H8JfsO4MyYhB5BMMxg93jsQzLUwrnCumj11UIg==" + }, + "System.IdentityModel.Tokens.Jwt": { + "type": "Transitive", + "resolved": "7.7.1", + "contentHash": "rQkO1YbAjLwnDJSMpRhRtrc6XwIcEOcUvoEcge+evurpzSZM3UNK+MZfD3sKyTlYsvknZ6eJjSBfnmXqwOsT9Q==", + "dependencies": { + "Microsoft.IdentityModel.JsonWebTokens": "7.7.1", + "Microsoft.IdentityModel.Tokens": "7.7.1" + } + }, + "System.IO.Hashing": { + "type": "Transitive", + "resolved": "10.0.1", + "contentHash": "Dy6ULPb2S0GmNndjKrEIpfibNsc8+FTOoZnqygtFDuyun8vWboQbfMpQtKUXpgTxokR5E4zFHETpNnGfeWY6NA==" + }, + "System.Management": { + "type": "Transitive", + "resolved": "7.0.2", + "contentHash": "/qEUN91mP/MUQmJnM5y5BdT7ZoPuVrtxnFlbJ8a3kBJGhe2wCzBfnPFtK2wTtEEcf3DMGR9J00GZZfg6HRI6yA==", + "dependencies": { + "System.CodeDom": "7.0.0" + } + }, + "System.Memory.Data": { + "type": "Transitive", + "resolved": "8.0.1", + "contentHash": "BVYuec3jV23EMRDeR7Dr1/qhx7369dZzJ9IWy2xylvb4YfXsrUxspWc4UWYid/tj4zZK58uGZqn2WQiaDMhmAg==" + }, + "System.Security.Cryptography.Pkcs": { + "type": "Transitive", + "resolved": "9.0.4", + "contentHash": "cUFTcMlz/Qw9s90b2wnWSCvHdjv51Bau9FQqhsr4TlwSe1OX+7SoXUqphis5G74MLOvMOCghxPPlEqOdCrVVGA==" + }, + "System.Security.Cryptography.ProtectedData": { + "type": "Transitive", + "resolved": "9.0.4", + "contentHash": "o94k2RKuAce3GeDMlUvIXlhVa1kWpJw95E6C9LwW0KlG0nj5+SgCiIxJ2Eroqb9sLtG1mEMbFttZIBZ13EJPvQ==" + }, + "Tomlyn.Signed": { + "type": "Transitive", + "resolved": "0.17.0", + "contentHash": "zSItaqXfXlkWYe4xApYrU2rPgHoSlXvU2NyS5jq66bhOyMYuNj48sc8m/guWOt8id1z+cbnHkmEQPpsRWlYoYg==" + }, + "jd.efcpt.build.tasks": { + "type": "Project", + "dependencies": { + "AWSSDK.Core": "[4.0.3.8, )", + "FirebirdSql.Data.FirebirdClient": "[10.3.2, )", + "Microsoft.Build.Framework": "[18.0.2, )", + "Microsoft.Build.Utilities.Core": "[18.0.2, )", + "Microsoft.Data.SqlClient": "[6.1.3, )", + "Microsoft.Data.Sqlite.Core": "[9.0.1, )", + "MySqlConnector": "[2.4.0, )", + "Npgsql": "[9.0.3, )", + "Oracle.ManagedDataAccess.Core": "[23.7.0, )", + "PatternKit.Core": "[0.17.3, )", + "Snowflake.Data": "[5.2.1, )", + "System.IO.Hashing": "[10.0.1, )" + } + } + } } } \ No newline at end of file diff --git a/src/JD.Efcpt.Sdk/DefinitionFactory.cs b/src/JD.Efcpt.Sdk/DefinitionFactory.cs new file mode 100644 index 0000000..661a738 --- /dev/null +++ b/src/JD.Efcpt.Sdk/DefinitionFactory.cs @@ -0,0 +1,95 @@ +using JD.MSBuild.Fluent; +using JD.MSBuild.Fluent.Fluent; + +namespace JD.Efcpt.Sdk.Definitions; + +/// +/// Main definition factory for JD.Efcpt.Sdk package. +/// +public static class DefinitionFactory +{ + public static PackageDefinition Create() + { + return Package.Define("JD.Efcpt.Sdk") + .Description("MSBuild SDK for Entity Framework Core power tools") + // Sdk/Sdk.props - imports Microsoft.NET.Sdk then our props + .SdkProps(p => p + .Comment(@" + JD.Efcpt.Sdk - MSBuild SDK for EF Core Power Tools Build Integration + + This SDK extends Microsoft.NET.Sdk to provide automatic EF Core code generation + from DACPAC files, SQL projects, or database connections during build. + + Usage: + + + net8.0 + + + ") + .Comment("Import Microsoft.NET.Sdk props first (base .NET SDK)") + .Import("Sdk.props", sdk: "Microsoft.NET.Sdk") + .Comment("Import our SDK-specific props") + .Import("$(MSBuildThisFileDirectory)..\\build\\JD.Efcpt.Sdk.props")) + // Sdk/Sdk.targets - imports Microsoft.NET.Sdk then our targets + .SdkTargets(t => t + .Comment(@" + JD.Efcpt.Sdk - MSBuild SDK Targets + + Imports Microsoft.NET.Sdk targets first, then our SDK-specific targets. + This ensures our targets run after the standard .NET SDK targets are defined. + ") + .Comment("Import Microsoft.NET.Sdk targets first (base .NET SDK)") + .Import("Sdk.targets", sdk: "Microsoft.NET.Sdk") + .Comment("Import our SDK-specific targets") + .Import("$(MSBuildThisFileDirectory)..\\build\\JD.Efcpt.Sdk.targets")) + // build/JD.Efcpt.Sdk.props - SDK-specific properties + .BuildProps(p => p + .Comment(@" + JD.Efcpt.Sdk Props + + This file imports the shared property definitions from the build folder. + The build folder contains the actual EFCPT configuration properties. + + NOTE: We use build/ (not buildTransitive/) so targets only apply to + projects that DIRECTLY use this SDK, not transitive consumers. + ") + .Comment(@" + Mark this as a direct SDK reference. + This marker is used to only enable generation for direct consumers, + not transitive ones. + ") + .PropertyGroup(null, g => g + .Property("_EfcptIsDirectReference", "true") + .Comment(@" + SDK users get automatic version checking enabled by default. + This helps ensure SDK users are always aware of updates. + Users can still opt-out by setting EfcptCheckForUpdates=false in their project. + ") + .Property("EfcptCheckForUpdates", "true", "'$(EfcptCheckForUpdates)' == ''")) + .Comment("Import SDK version for update check feature") + .Import("$(MSBuildThisFileDirectory)JD.Efcpt.Sdk.Version.props", + condition: "Exists('$(MSBuildThisFileDirectory)JD.Efcpt.Sdk.Version.props')") + .Comment("Import the shared props (same as JD.Efcpt.Build uses)") + .Import("$(MSBuildThisFileDirectory)JD.Efcpt.Build.props")) + // build/JD.Efcpt.Sdk.targets - imports shared targets + .BuildTargets(t => t + .Comment(@" + JD.Efcpt.Sdk Targets + + This file imports the shared target definitions from the build folder. + The build folder contains the actual EFCPT build targets and tasks. + + NOTE: We use build/ (not buildTransitive/) so targets only apply to + projects that DIRECTLY use this SDK, not transitive consumers. + ") + .Comment("Import the shared targets (same as JD.Efcpt.Build uses)") + .Import("$(MSBuildThisFileDirectory)JD.Efcpt.Build.targets")) + .Pack(o => + { + o.EmitSdk = true; + o.SdkFlatLayout = true; + }) + .Build(); + } +} diff --git a/src/JD.Efcpt.Sdk/JD.Efcpt.Sdk.csproj b/src/JD.Efcpt.Sdk/JD.Efcpt.Sdk.csproj index 2ab217b..1244f55 100644 --- a/src/JD.Efcpt.Sdk/JD.Efcpt.Sdk.csproj +++ b/src/JD.Efcpt.Sdk/JD.Efcpt.Sdk.csproj @@ -22,11 +22,22 @@ false - false + true true $(NoWarn);NU5128;NU5100;NU5129 false + + + <_JDMSBuildFluentDirectReference>true + false + JD.Efcpt.Sdk.Definitions.DefinitionFactory + Create + + + + + diff --git a/src/JD.Efcpt.Sdk/JD.Efcpt.Sdk.props b/src/JD.Efcpt.Sdk/JD.Efcpt.Sdk.props new file mode 100644 index 0000000..7e04bad --- /dev/null +++ b/src/JD.Efcpt.Sdk/JD.Efcpt.Sdk.props @@ -0,0 +1,30 @@ + + + + + + <_EfcptIsDirectReference>true + + true + + + + + + diff --git a/src/JD.Efcpt.Sdk/JD.Efcpt.Sdk.targets b/src/JD.Efcpt.Sdk/JD.Efcpt.Sdk.targets new file mode 100644 index 0000000..b81c83d --- /dev/null +++ b/src/JD.Efcpt.Sdk/JD.Efcpt.Sdk.targets @@ -0,0 +1,14 @@ + + + + + + diff --git a/src/JD.Efcpt.Sdk/Sdk/Sdk.props b/src/JD.Efcpt.Sdk/Sdk/Sdk.props index 59a19ea..614b94e 100644 --- a/src/JD.Efcpt.Sdk/Sdk/Sdk.props +++ b/src/JD.Efcpt.Sdk/Sdk/Sdk.props @@ -1,4 +1,5 @@ - + + - - + - - + diff --git a/src/JD.Efcpt.Sdk/Sdk/Sdk.targets b/src/JD.Efcpt.Sdk/Sdk/Sdk.targets index bf7b1f7..172d670 100644 --- a/src/JD.Efcpt.Sdk/Sdk/Sdk.targets +++ b/src/JD.Efcpt.Sdk/Sdk/Sdk.targets @@ -1,14 +1,13 @@ - + + - - + - - + diff --git a/src/JD.Efcpt.Sdk/build/JD.Efcpt.Sdk.props b/src/JD.Efcpt.Sdk/build/JD.Efcpt.Sdk.props index d8e2019..7e04bad 100644 --- a/src/JD.Efcpt.Sdk/build/JD.Efcpt.Sdk.props +++ b/src/JD.Efcpt.Sdk/build/JD.Efcpt.Sdk.props @@ -1,4 +1,5 @@ - + + - true - - + - - + diff --git a/src/JD.Efcpt.Sdk/build/JD.Efcpt.Sdk.targets b/src/JD.Efcpt.Sdk/build/JD.Efcpt.Sdk.targets index 6e846a5..b81c83d 100644 --- a/src/JD.Efcpt.Sdk/build/JD.Efcpt.Sdk.targets +++ b/src/JD.Efcpt.Sdk/build/JD.Efcpt.Sdk.targets @@ -1,4 +1,5 @@ - + + - - + diff --git a/src/JD.Efcpt.Sdk/packages.lock.json b/src/JD.Efcpt.Sdk/packages.lock.json new file mode 100644 index 0000000..0045cfb --- /dev/null +++ b/src/JD.Efcpt.Sdk/packages.lock.json @@ -0,0 +1,29 @@ +{ + "version": 1, + "dependencies": { + "net10.0": { + "JD.MSBuild.Fluent": { + "type": "Direct", + "requested": "[1.3.15, )", + "resolved": "1.3.15", + "contentHash": "MT8+Bfbt36zcgwXX59x034yP1sGh+u0nVqPtoauhuktT2aEf3ay1JlwZKgWElBoGUSu+DxksE0vkZzZ8BxRkAQ==" + } + }, + "net8.0": { + "JD.MSBuild.Fluent": { + "type": "Direct", + "requested": "[1.3.15, )", + "resolved": "1.3.15", + "contentHash": "MT8+Bfbt36zcgwXX59x034yP1sGh+u0nVqPtoauhuktT2aEf3ay1JlwZKgWElBoGUSu+DxksE0vkZzZ8BxRkAQ==" + } + }, + "net9.0": { + "JD.MSBuild.Fluent": { + "type": "Direct", + "requested": "[1.3.15, )", + "resolved": "1.3.15", + "contentHash": "MT8+Bfbt36zcgwXX59x034yP1sGh+u0nVqPtoauhuktT2aEf3ay1JlwZKgWElBoGUSu+DxksE0vkZzZ8BxRkAQ==" + } + } + } +} \ No newline at end of file diff --git a/tests/JD.Efcpt.Build.Tests/BuildLogTests.cs b/tests/JD.Efcpt.Build.Tests/BuildLogTests.cs index 1edb898..80c151c 100644 --- a/tests/JD.Efcpt.Build.Tests/BuildLogTests.cs +++ b/tests/JD.Efcpt.Build.Tests/BuildLogTests.cs @@ -206,6 +206,145 @@ await Given("a build engine", Setup) s.Engine.Errors.Count == 1) .AssertPassed(); } + + [Scenario("Log with MessageLevel.None does nothing")] + [Fact] + public async Task Log_with_none_level_does_nothing() + { + await Given("a build engine", Setup) + .When("Log is called with None level", s => + { + var log = new Tasks.BuildLog(s.Engine.TaskLoggingHelper, "minimal"); + log.Log(Tasks.MessageLevel.None, "Should not appear"); + return s; + }) + .Then("no message is logged", s => s.Engine.Messages.All(m => m.Message != "Should not appear")) + .And("no warning is logged", s => s.Engine.Warnings.Count == 0) + .And("no error is logged", s => s.Engine.Errors.Count == 0) + .AssertPassed(); + } + + [Scenario("Log with MessageLevel.Info logs message")] + [Fact] + public async Task Log_with_info_level() + { + await Given("a build engine", Setup) + .When("Log is called with Info level", s => + { + var log = new Tasks.BuildLog(s.Engine.TaskLoggingHelper, "minimal"); + log.Log(Tasks.MessageLevel.Info, "Info via Log method"); + return s; + }) + .Then("message is logged", s => + s.Engine.Messages.Any(m => m.Message == "Info via Log method")) + .And("importance is high", s => + s.Engine.Messages.Any(m => m.Message == "Info via Log method" && m.Importance == MessageImportance.High)) + .AssertPassed(); + } + + [Scenario("Log with MessageLevel.Warn logs warning")] + [Fact] + public async Task Log_with_warn_level() + { + await Given("a build engine", Setup) + .When("Log is called with Warn level", s => + { + var log = new Tasks.BuildLog(s.Engine.TaskLoggingHelper, "minimal"); + log.Log(Tasks.MessageLevel.Warn, "Warning via Log method"); + return s; + }) + .Then("warning is logged", s => + s.Engine.Warnings.Any(w => w.Message == "Warning via Log method")) + .AssertPassed(); + } + + [Scenario("Log with MessageLevel.Warn and code logs warning with code")] + [Fact] + public async Task Log_with_warn_level_and_code() + { + await Given("a build engine", Setup) + .When("Log is called with Warn level and code", s => + { + var log = new Tasks.BuildLog(s.Engine.TaskLoggingHelper, "minimal"); + log.Log(Tasks.MessageLevel.Warn, "Warning with code via Log", "EFCPT100"); + return s; + }) + .Then("warning is logged", s => + s.Engine.Warnings.Any(w => w.Message == "Warning with code via Log")) + .And("warning has code", s => + s.Engine.Warnings.Any(w => w.Code == "EFCPT100")) + .AssertPassed(); + } + + [Scenario("Log with MessageLevel.Error logs error")] + [Fact] + public async Task Log_with_error_level() + { + await Given("a build engine", Setup) + .When("Log is called with Error level", s => + { + var log = new Tasks.BuildLog(s.Engine.TaskLoggingHelper, "minimal"); + log.Log(Tasks.MessageLevel.Error, "Error via Log method"); + return s; + }) + .Then("error is logged", s => + s.Engine.Errors.Any(e => e.Message == "Error via Log method")) + .AssertPassed(); + } + + [Scenario("Log with MessageLevel.Error and code logs error with code")] + [Fact] + public async Task Log_with_error_level_and_code() + { + await Given("a build engine", Setup) + .When("Log is called with Error level and code", s => + { + var log = new Tasks.BuildLog(s.Engine.TaskLoggingHelper, "minimal"); + log.Log(Tasks.MessageLevel.Error, "Error with code via Log", "EFCPT200"); + return s; + }) + .Then("error is logged", s => + s.Engine.Errors.Any(e => e.Message == "Error with code via Log")) + .And("error has code", s => + s.Engine.Errors.Any(e => e.Code == "EFCPT200")) + .AssertPassed(); + } + + [Scenario("Log with empty code uses codeless variant")] + [Fact] + public async Task Log_with_empty_code_uses_codeless() + { + await Given("a build engine", Setup) + .When("Log is called with Error level and empty code", s => + { + var log = new Tasks.BuildLog(s.Engine.TaskLoggingHelper, "minimal"); + log.Log(Tasks.MessageLevel.Error, "Error without code", ""); + return s; + }) + .Then("error is logged", s => + s.Engine.Errors.Any(e => e.Message == "Error without code")) + .And("error has no code", s => + s.Engine.Errors.Any(e => e.Message == "Error without code" && string.IsNullOrEmpty(e.Code))) + .AssertPassed(); + } + + [Scenario("Log with null code uses codeless variant")] + [Fact] + public async Task Log_with_null_code_uses_codeless() + { + await Given("a build engine", Setup) + .When("Log is called with Warn level and null code", s => + { + var log = new Tasks.BuildLog(s.Engine.TaskLoggingHelper, "minimal"); + log.Log(Tasks.MessageLevel.Warn, "Warning without code", null); + return s; + }) + .Then("warning is logged", s => + s.Engine.Warnings.Any(w => w.Message == "Warning without code")) + .And("warning has no code", s => + s.Engine.Warnings.Any(w => w.Message == "Warning without code" && string.IsNullOrEmpty(w.Code))) + .AssertPassed(); + } } /// @@ -342,4 +481,21 @@ await Given("a NullBuildLog instance", () => Tasks.NullBuildLog.Instance) .Then("implements IBuildLog", result => result) .AssertPassed(); } + + [Scenario("Log method does not throw")] + [Fact] + public async Task Log_does_not_throw() + { + await Given("a NullBuildLog instance", () => Tasks.NullBuildLog.Instance) + .When("Log is called with various levels", log => + { + log.Log(Tasks.MessageLevel.None, "None message"); + log.Log(Tasks.MessageLevel.Info, "Info message"); + log.Log(Tasks.MessageLevel.Warn, "Warn message", "CODE"); + log.Log(Tasks.MessageLevel.Error, "Error message", null); + return true; + }) + .Then("no exception is thrown", success => success) + .AssertPassed(); + } } diff --git a/tests/JD.Efcpt.Build.Tests/CleanTargetTests.cs b/tests/JD.Efcpt.Build.Tests/CleanTargetTests.cs index 1915d6e..925d1ee 100644 --- a/tests/JD.Efcpt.Build.Tests/CleanTargetTests.cs +++ b/tests/JD.Efcpt.Build.Tests/CleanTargetTests.cs @@ -42,13 +42,13 @@ private static CleanTestContext SetupProjectWithEfcptOutput() enable - + true - + """; diff --git a/tests/JD.Efcpt.Build.Tests/ConnectionStrings/AppConfigConnectionStringParserTests.cs b/tests/JD.Efcpt.Build.Tests/ConnectionStrings/AppConfigConnectionStringParserTests.cs index be5dbb3..04fe5dd 100644 --- a/tests/JD.Efcpt.Build.Tests/ConnectionStrings/AppConfigConnectionStringParserTests.cs +++ b/tests/JD.Efcpt.Build.Tests/ConnectionStrings/AppConfigConnectionStringParserTests.cs @@ -24,9 +24,8 @@ private static BuildLog CreateTestLog() private static ParseResult ExecuteParse(SetupState setup) { - var parser = new AppConfigConnectionStringParser(); var log = CreateTestLog(); - var result = parser.Parse(setup.FilePath, setup.KeyName, log); + var result = AppConfigConnectionStringParser.Parse(setup.FilePath, setup.KeyName, log); return new ParseResult(setup, result); } diff --git a/tests/JD.Efcpt.Build.Tests/ConnectionStrings/AppSettingsConnectionStringParserTests.cs b/tests/JD.Efcpt.Build.Tests/ConnectionStrings/AppSettingsConnectionStringParserTests.cs index 7ee4a62..529064f 100644 --- a/tests/JD.Efcpt.Build.Tests/ConnectionStrings/AppSettingsConnectionStringParserTests.cs +++ b/tests/JD.Efcpt.Build.Tests/ConnectionStrings/AppSettingsConnectionStringParserTests.cs @@ -26,7 +26,7 @@ private static ParseResult ExecuteParse(SetupState setup) { var parser = new AppSettingsConnectionStringParser(); var log = CreateTestLog(); - var result = parser.Parse(setup.FilePath, setup.KeyName, log); + var result = AppSettingsConnectionStringParser.Parse(setup.FilePath, setup.KeyName, log); return new ParseResult(setup, result); } diff --git a/tests/JD.Efcpt.Build.Tests/ConnectionStrings/ConfigurationFileTypeValidatorTests.cs b/tests/JD.Efcpt.Build.Tests/ConnectionStrings/ConfigurationFileTypeValidatorTests.cs index b5aa4b2..7de3313 100644 --- a/tests/JD.Efcpt.Build.Tests/ConnectionStrings/ConfigurationFileTypeValidatorTests.cs +++ b/tests/JD.Efcpt.Build.Tests/ConnectionStrings/ConfigurationFileTypeValidatorTests.cs @@ -34,7 +34,7 @@ public async Task Warns_when_app_settings_receives_config_file() await Given("a validator context", CreateContext) .When("validating .config file for EfcptAppSettings", ctx => { - ctx.Validator.ValidateAndWarn("/path/to/app.config", "EfcptAppSettings", ctx.Log); + ConfigurationFileTypeValidator.ValidateAndWarn("/path/to/app.config", "EfcptAppSettings", ctx.Log); return ctx; }) .Then("logs a warning about file type mismatch", ctx => @@ -51,7 +51,7 @@ public async Task Warns_when_app_config_receives_json_file() await Given("a validator context", CreateContext) .When("validating .json file for EfcptAppConfig", ctx => { - ctx.Validator.ValidateAndWarn("/path/to/appsettings.json", "EfcptAppConfig", ctx.Log); + ConfigurationFileTypeValidator.ValidateAndWarn("/path/to/appsettings.json", "EfcptAppConfig", ctx.Log); return ctx; }) .Then("logs a warning about file type mismatch", ctx => @@ -68,7 +68,7 @@ public async Task No_warning_when_app_settings_receives_json_file() await Given("a validator context", CreateContext) .When("validating .json file for EfcptAppSettings", ctx => { - ctx.Validator.ValidateAndWarn("/path/to/appsettings.json", "EfcptAppSettings", ctx.Log); + ConfigurationFileTypeValidator.ValidateAndWarn("/path/to/appsettings.json", "EfcptAppSettings", ctx.Log); return ctx; }) .Then("no warnings logged", ctx => ctx.BuildEngine.Warnings.Count == 0) @@ -82,7 +82,7 @@ public async Task No_warning_when_app_config_receives_config_file() await Given("a validator context", CreateContext) .When("validating .config file for EfcptAppConfig", ctx => { - ctx.Validator.ValidateAndWarn("/path/to/app.config", "EfcptAppConfig", ctx.Log); + ConfigurationFileTypeValidator.ValidateAndWarn("/path/to/app.config", "EfcptAppConfig", ctx.Log); return ctx; }) .Then("no warnings logged", ctx => ctx.BuildEngine.Warnings.Count == 0) @@ -99,7 +99,7 @@ public async Task No_warning_for_unknown_file_types(string filePath, string para await Given("a validator context", CreateContext) .When("validating unknown file type", ctx => { - ctx.Validator.ValidateAndWarn(filePath, parameterName, ctx.Log); + ConfigurationFileTypeValidator.ValidateAndWarn(filePath, parameterName, ctx.Log); return ctx; }) .Then("no warnings logged", ctx => ctx.BuildEngine.Warnings.Count == 0) @@ -115,7 +115,7 @@ public async Task Handles_case_insensitive_extensions(string filePath, string pa await Given("a validator context", CreateContext) .When("validating file with mixed-case extension", ctx => { - ctx.Validator.ValidateAndWarn(filePath, parameterName, ctx.Log); + ConfigurationFileTypeValidator.ValidateAndWarn(filePath, parameterName, ctx.Log); return ctx; }) .Then("logs appropriate warning", ctx => ctx.BuildEngine.Warnings.Count == 1) diff --git a/tests/JD.Efcpt.Build.Tests/Decorators/ProfileAttributeTests.cs b/tests/JD.Efcpt.Build.Tests/Decorators/ProfileAttributeTests.cs new file mode 100644 index 0000000..8241476 --- /dev/null +++ b/tests/JD.Efcpt.Build.Tests/Decorators/ProfileAttributeTests.cs @@ -0,0 +1,73 @@ +using JD.Efcpt.Build.Tasks.Decorators; +using TinyBDD; +using TinyBDD.Xunit; +using Xunit; +using Xunit.Abstractions; + +namespace JD.Efcpt.Build.Tests.Decorators; + +/// +/// Tests for profile decorator attributes used in MSBuild property definitions. +/// +[Feature("ProfileAttribute: Decorators for mapping MSBuild properties to config overrides")] +public sealed class ProfileAttributeTests(ITestOutputHelper output) : TinyBddXunitBase(output) +{ + [Scenario("ProfileInputAttribute has default values")] + [Fact] + public async Task ProfileInputAttribute_defaults() + { + await Given("ProfileInputAttribute constructed", () => new ProfileInputAttribute()) + .Then("Exclude is false by default", attr => !attr.Exclude) + .AssertPassed(); + } + + [Scenario("ProfileInputAttribute with Exclude=true sets property")] + [Fact] + public async Task ProfileInputAttribute_with_exclude() + { + await Given("ProfileInputAttribute with Exclude", () => new ProfileInputAttribute { Exclude = true }) + .Then("Exclude is true", attr => attr.Exclude) + .AssertPassed(); + } + + [Scenario("ProfileInputAttribute with custom name sets Name property")] + [Fact] + public async Task ProfileInputAttribute_with_custom_name() + { + const string customName = "CustomProperty"; + await Given("ProfileInputAttribute with name", () => new ProfileInputAttribute { Name = customName }) + .Then("Name matches", attr => attr.Name == customName) + .AssertPassed(); + } + + [Scenario("ProfileOutputAttribute can be instantiated")] + [Fact] + public async Task ProfileOutputAttribute_instantiates() + { + await Given("ProfileOutputAttribute created", () => new ProfileOutputAttribute()) + .Then("instance is not null", attr => attr != null) + .AssertPassed(); + } + + [Scenario("ProfileOutputAttribute can be applied to properties")] + [Fact] + public async Task ProfileOutputAttribute_applies_to_properties() + { + await Given("class with ProfileOutput attribute", () => + { + var type = typeof(TestClassWithProfileOutput); + var prop = type.GetProperty(nameof(TestClassWithProfileOutput.Output)); + var attr = prop?.GetCustomAttributes(typeof(ProfileOutputAttribute), false).FirstOrDefault(); + return attr; + }) + .Then("attribute is found", attr => attr is ProfileOutputAttribute) + .AssertPassed(); + } + + // Helper class for testing attribute application + private class TestClassWithProfileOutput + { + [ProfileOutput] + public string? Output { get; set; } + } +} diff --git a/tests/JD.Efcpt.Build.Tests/DetectSqlProjectTests.cs b/tests/JD.Efcpt.Build.Tests/DetectSqlProjectTests.cs new file mode 100644 index 0000000..4d8aecc --- /dev/null +++ b/tests/JD.Efcpt.Build.Tests/DetectSqlProjectTests.cs @@ -0,0 +1,284 @@ +using JD.Efcpt.Build.Tasks; +using JD.Efcpt.Build.Tests.Infrastructure; +using TinyBDD; +using TinyBDD.Xunit; +using Xunit; +using Xunit.Abstractions; + +namespace JD.Efcpt.Build.Tests; + +/// +/// Tests for the DetectSqlProject MSBuild task. +/// This task detects whether a project is a SQL database project via SDK or properties. +/// +[Feature("DetectSqlProject: MSBuild task for SQL project detection")] +[Collection(nameof(AssemblySetup))] +public sealed class DetectSqlProjectTests(ITestOutputHelper output) : TinyBddXunitBase(output) +{ + private sealed record SetupState(TestBuildEngine Engine, TestFolder Folder, DetectSqlProject Task); + private sealed record ExecutionResult(SetupState Setup, bool Success, bool IsSqlProject); + + private static SetupState SetupTask(string projectFileName, string projectContent, string? sqlServerVersion = null, string? dsp = null) + { + var folder = new TestFolder(); + var projectPath = folder.WriteFile(projectFileName, projectContent); + var engine = new TestBuildEngine(); + + var task = new DetectSqlProject + { + BuildEngine = engine, + ProjectPath = projectPath, + SqlServerVersion = sqlServerVersion, + DSP = dsp + }; + + return new SetupState(engine, folder, task); + } + + private static ExecutionResult Execute(SetupState setup) + { + var success = setup.Task.Execute(); + return new ExecutionResult(setup, success, setup.Task.IsSqlProject); + } + + [Scenario("Modern SQL SDK project is detected via SDK attribute")] + [Fact] + public async Task Modern_sql_sdk_detected() + { + await Given("a project with MSBuild.Sdk.SqlProj SDK", () => + SetupTask("Database.csproj", "")) + .When("detection runs", Execute) + .Then("execution succeeds", r => r.Success) + .And("IsSqlProject is true", r => r.IsSqlProject) + .Finally(r => r.Setup.Folder.Dispose()) + .AssertPassed(); + } + + [Scenario("Modern SQL SDK project is detected via Sdk element")] + [Fact] + public async Task Modern_sql_sdk_via_element_detected() + { + await Given("a project with Microsoft.Build.Sql SDK element", () => + SetupTask("Database.csproj", + "")) + .When("detection runs", Execute) + .Then("execution succeeds", r => r.Success) + .And("IsSqlProject is true", r => r.IsSqlProject) + .Finally(r => r.Setup.Folder.Dispose()) + .AssertPassed(); + } + + [Scenario("Legacy SSDT project detected via SqlServerVersion property")] + [Fact] + public async Task Legacy_ssdt_via_sqlserverversion_detected() + { + await Given("a project with SqlServerVersion property", () => + SetupTask("Database.sqlproj", + "Sql150", + sqlServerVersion: "Sql150")) + .When("detection runs", Execute) + .Then("execution succeeds", r => r.Success) + .And("IsSqlProject is true", r => r.IsSqlProject) + .Finally(r => r.Setup.Folder.Dispose()) + .AssertPassed(); + } + + [Scenario("Legacy SSDT project detected via DSP property")] + [Fact] + public async Task Legacy_ssdt_via_dsp_detected() + { + await Given("a project with DSP property", () => + SetupTask("Database.sqlproj", + "Microsoft.Data.Tools.Schema.Sql.Sql150DatabaseSchemaProvider", + dsp: "Microsoft.Data.Tools.Schema.Sql.Sql150DatabaseSchemaProvider")) + .When("detection runs", Execute) + .Then("execution succeeds", r => r.Success) + .And("IsSqlProject is true", r => r.IsSqlProject) + .Finally(r => r.Setup.Folder.Dispose()) + .AssertPassed(); + } + + [Scenario("Legacy SSDT project detected with both properties")] + [Fact] + public async Task Legacy_ssdt_with_both_properties_detected() + { + await Given("a project with both SqlServerVersion and DSP", () => + SetupTask("Database.sqlproj", + "", + sqlServerVersion: "Sql150", + dsp: "Microsoft.Data.Tools.Schema.Sql.Sql150DatabaseSchemaProvider")) + .When("detection runs", Execute) + .Then("execution succeeds", r => r.Success) + .And("IsSqlProject is true", r => r.IsSqlProject) + .Finally(r => r.Setup.Folder.Dispose()) + .AssertPassed(); + } + + [Scenario("Non-SQL project returns false")] + [Fact] + public async Task Non_sql_project_returns_false() + { + await Given("a regular .NET project", () => + SetupTask("App.csproj", "")) + .When("detection runs", Execute) + .Then("execution succeeds", r => r.Success) + .And("IsSqlProject is false", r => !r.IsSqlProject) + .Finally(r => r.Setup.Folder.Dispose()) + .AssertPassed(); + } + + [Scenario("Null ProjectPath returns error")] + [Fact] + public async Task Null_project_path_returns_error() + { + await Given("a task with null ProjectPath", () => + { + var engine = new TestBuildEngine(); + var task = new DetectSqlProject + { + BuildEngine = engine, + ProjectPath = null! + }; + return new SetupState(engine, new TestFolder(), task); + }) + .When("detection runs", Execute) + .Then("execution fails", r => !r.Success) + .And("error is logged", r => r.Setup.Engine.Errors.Count > 0) + .And("error mentions ProjectPath", r => r.Setup.Engine.Errors[0].Message?.Contains("ProjectPath") ?? false) + .Finally(r => r.Setup.Folder.Dispose()) + .AssertPassed(); + } + + [Scenario("Empty ProjectPath returns error")] + [Fact] + public async Task Empty_project_path_returns_error() + { + await Given("a task with empty ProjectPath", () => + { + var engine = new TestBuildEngine(); + var task = new DetectSqlProject + { + BuildEngine = engine, + ProjectPath = " " + }; + return new SetupState(engine, new TestFolder(), task); + }) + .When("detection runs", Execute) + .Then("execution fails", r => !r.Success) + .And("error is logged", r => r.Setup.Engine.Errors.Count > 0) + .Finally(r => r.Setup.Folder.Dispose()) + .AssertPassed(); + } + + [Scenario("Missing project file returns false gracefully")] + [Fact] + public async Task Missing_project_file_returns_false() + { + await Given("a task with non-existent project path", () => + { + var folder = new TestFolder(); + var engine = new TestBuildEngine(); + var task = new DetectSqlProject + { + BuildEngine = engine, + ProjectPath = Path.Combine(folder.Root, "NotExists.csproj") + }; + return new SetupState(engine, folder, task); + }) + .When("detection runs", Execute) + .Then("execution succeeds", r => r.Success) + .And("IsSqlProject is false", r => !r.IsSqlProject) + .Finally(r => r.Setup.Folder.Dispose()) + .AssertPassed(); + } + + [Scenario("Project with no SQL indicators returns false")] + [Fact] + public async Task No_sql_indicators_returns_false() + { + await Given("a project with no SQL SDK or properties", () => + SetupTask("Library.csproj", + "net8.0", + sqlServerVersion: null, + dsp: null)) + .When("detection runs", Execute) + .Then("execution succeeds", r => r.Success) + .And("IsSqlProject is false", r => !r.IsSqlProject) + .And("low importance message logged", r => r.Setup.Engine.Messages.Exists(m => m.Message?.Contains("Not a SQL project") ?? false)) + .Finally(r => r.Setup.Folder.Dispose()) + .AssertPassed(); + } + + [Scenario("Modern SDK takes precedence over properties")] + [Fact] + public async Task Modern_sdk_takes_precedence() + { + await Given("a project with modern SDK and legacy properties", () => + SetupTask("Database.csproj", + "", + sqlServerVersion: "Sql150")) + .When("detection runs", Execute) + .Then("execution succeeds", r => r.Success) + .And("IsSqlProject is true", r => r.IsSqlProject) + .And("SDK detection message logged", r => r.Setup.Engine.Messages.Exists(m => m.Message?.Contains("SDK attribute") ?? false)) + .Finally(r => r.Setup.Folder.Dispose()) + .AssertPassed(); + } + + [Scenario("Invalid XML project file returns false gracefully")] + [Fact] + public async Task Invalid_xml_returns_false() + { + await Given("a project with invalid XML", () => + SetupTask("Broken.csproj", " r.Success) + .And("IsSqlProject is false", r => !r.IsSqlProject) + .Finally(r => r.Setup.Folder.Dispose()) + .AssertPassed(); + } + + [Scenario("Multiple SDK values with SQL SDK detected")] + [Fact] + public async Task Multiple_sdks_with_sql_detected() + { + await Given("a project with multiple SDKs including SQL", () => + SetupTask("Database.csproj", + "")) + .When("detection runs", Execute) + .Then("execution succeeds", r => r.Success) + .And("IsSqlProject is true", r => r.IsSqlProject) + .Finally(r => r.Setup.Folder.Dispose()) + .AssertPassed(); + } + + [Scenario("Whitespace-only SqlServerVersion is ignored")] + [Fact] + public async Task Whitespace_sqlserverversion_ignored() + { + await Given("a project with whitespace SqlServerVersion", () => + SetupTask("App.csproj", + "", + sqlServerVersion: " ")) + .When("detection runs", Execute) + .Then("execution succeeds", r => r.Success) + .And("IsSqlProject is false", r => !r.IsSqlProject) + .Finally(r => r.Setup.Folder.Dispose()) + .AssertPassed(); + } + + [Scenario("Whitespace-only DSP is ignored")] + [Fact] + public async Task Whitespace_dsp_ignored() + { + await Given("a project with whitespace DSP", () => + SetupTask("App.csproj", + "", + dsp: " ")) + .When("detection runs", Execute) + .Then("execution succeeds", r => r.Success) + .And("IsSqlProject is false", r => !r.IsSqlProject) + .Finally(r => r.Setup.Folder.Dispose()) + .AssertPassed(); + } +} diff --git a/tests/JD.Efcpt.Build.Tests/DotNetToolUtilitiesTests.cs b/tests/JD.Efcpt.Build.Tests/DotNetToolUtilitiesTests.cs index cd3a452..7f94680 100644 --- a/tests/JD.Efcpt.Build.Tests/DotNetToolUtilitiesTests.cs +++ b/tests/JD.Efcpt.Build.Tests/DotNetToolUtilitiesTests.cs @@ -220,4 +220,47 @@ await Given("a non-existent dotnet command", () => "nonexistent-dotnet-command-1 // would require the .NET SDK to be installed, which is environment-dependent. // These tests would be better suited for integration tests. // The current tests verify error handling and invalid input scenarios. + + [Scenario("IsDotNet10OrLater handles frameworks with modifiers")] + [Theory] + [InlineData("net10.0-windows", true)] + [InlineData("net10.0-macos", true)] + [InlineData("net10.0-android", true)] + [InlineData("net9.0-android", false)] + [InlineData("net8.0-ios", false)] + public async Task IsDotNet10OrLater_handles_framework_modifiers(string tfm, bool expected) + { + await Given($"target framework '{tfm}' with modifier", () => tfm) + .When("IsDotNet10OrLater is called", t => DotNetToolUtilities.IsDotNet10OrLater(t)) + .Then($"returns {expected}", result => result == expected) + .AssertPassed(); + } + + [Scenario("IsDotNet10OrLater handles single-digit major version")] + [Theory] + [InlineData("net5", false)] + [InlineData("net6", false)] + [InlineData("net7", false)] + [InlineData("net8", false)] + [InlineData("net9", false)] + public async Task IsDotNet10OrLater_handles_single_digit_versions(string tfm, bool expected) + { + await Given($"target framework '{tfm}' without minor version", () => tfm) + .When("IsDotNet10OrLater is called", t => DotNetToolUtilities.IsDotNet10OrLater(t)) + .Then($"returns {expected}", result => result == expected) + .AssertPassed(); + } + + [Scenario("IsDotNet10OrLater handles whitespace")] + [Theory] + [InlineData(" net10.0 ", true)] + [InlineData("\tnet10.0\t", true)] + [InlineData(" net9.0 ", false)] + public async Task IsDotNet10OrLater_handles_whitespace(string tfm, bool expected) + { + await Given($"target framework with whitespace", () => tfm) + .When("IsDotNet10OrLater is called", t => DotNetToolUtilities.IsDotNet10OrLater(t)) + .Then($"returns {expected}", result => result == expected) + .AssertPassed(); + } } diff --git a/tests/JD.Efcpt.Build.Tests/EnumerableExtensionsTests.cs b/tests/JD.Efcpt.Build.Tests/EnumerableExtensionsTests.cs index 1e64456..a89bbf9 100644 --- a/tests/JD.Efcpt.Build.Tests/EnumerableExtensionsTests.cs +++ b/tests/JD.Efcpt.Build.Tests/EnumerableExtensionsTests.cs @@ -17,7 +17,8 @@ public sealed class EnumerableExtensionsTests(ITestOutputHelper output) : TinyBd [Fact] public async Task BuildCandidateNames_fallback_only() { - await Given("no override and two fallback names", () => ((string?)null, new[] { "file1.json", "file2.json" })) + var setup = new[] { "file1.json", "file2.json" }; + await Given("no override and two fallback names", () => ((string?)null, setup)) .When("BuildCandidateNames is called", t => EnumerableExtensions.BuildCandidateNames(t.Item1, t.Item2)) .Then("result contains both fallbacks", r => r.Count == 2 && r[0] == "file1.json" && r[1] == "file2.json") .AssertPassed(); @@ -27,7 +28,8 @@ await Given("no override and two fallback names", () => ((string?)null, new[] { [Fact] public async Task BuildCandidateNames_override_first() { - await Given("an override and fallback names", () => ("custom.json", new[] { "file1.json", "file2.json" })) + var setup = new[] { "file1.json", "file2.json" }; + await Given("an override and fallback names", () => ("custom.json", setup)) .When("BuildCandidateNames is called", t => EnumerableExtensions.BuildCandidateNames(t.Item1, t.Item2)) .Then("override is first", r => r[0] == "custom.json") .And("result contains all names", r => r.Count == 3) @@ -38,7 +40,8 @@ await Given("an override and fallback names", () => ("custom.json", new[] { "fil [Fact] public async Task BuildCandidateNames_extracts_filename_from_path() { - await Given("an override path and fallback", () => ("path/to/custom.json", new[] { "default.json" })) + var setup = new[] { "default.json" }; + await Given("an override path and fallback", () => ("path/to/custom.json", setup)) .When("BuildCandidateNames is called", t => EnumerableExtensions.BuildCandidateNames(t.Item1, t.Item2)) .Then("extracted filename is first", r => r[0] == "custom.json") .And("result contains default", r => r.Contains("default.json")) @@ -49,7 +52,8 @@ await Given("an override path and fallback", () => ("path/to/custom.json", new[] [Fact] public async Task BuildCandidateNames_deduplicates() { - await Given("override matching a fallback with different case", () => ("FILE.JSON", new[] { "file.json", "other.json" })) + var setup = new[] { "file.json", "other.json" }; + await Given("override matching a fallback with different case", () => ("FILE.JSON", setup)) .When("BuildCandidateNames is called", t => EnumerableExtensions.BuildCandidateNames(t.Item1, t.Item2)) .Then("result is deduplicated", r => r.Count == 2) .And("first is override version", r => r[0] == "FILE.JSON") @@ -70,7 +74,8 @@ await Given("override only", () => ("custom.json", Array.Empty())) [Fact] public async Task BuildCandidateNames_filters_invalid_fallbacks() { - await Given("fallbacks with nulls and empties", () => ((string?)null, new[] { "valid.json", "", " ", "also-valid.json" })) + var setup = new[] { "valid.json", "", " ", "also-valid.json" }; + await Given("fallbacks with nulls and empties", () => ((string?)null, setup)) .When("BuildCandidateNames is called", t => EnumerableExtensions.BuildCandidateNames(t.Item1, t.Item2)) .Then("only valid names included", r => r.Count == 2) .And("contains valid.json", r => r.Contains("valid.json")) @@ -82,7 +87,8 @@ await Given("fallbacks with nulls and empties", () => ((string?)null, new[] { "v [Fact] public async Task BuildCandidateNames_whitespace_override() { - await Given("whitespace override and fallbacks", () => (" ", new[] { "file.json" })) + var setup = new[] { "file.json" }; + await Given("whitespace override and fallbacks", () => (" ", setup)) .When("BuildCandidateNames is called", t => EnumerableExtensions.BuildCandidateNames(t.Item1, t.Item2)) .Then("override is ignored", r => r.Count == 1 && r[0] == "file.json") .AssertPassed(); @@ -92,7 +98,8 @@ await Given("whitespace override and fallbacks", () => (" ", new[] { "file.jso [Fact] public async Task BuildCandidateNames_preserves_fallback_order() { - await Given("multiple fallbacks", () => ((string?)null, new[] { "first.json", "second.json", "third.json" })) + var setup = new[] { "first.json", "second.json", "third.json" }; + await Given("multiple fallbacks", () => ((string?)null, setup)) .When("BuildCandidateNames is called", t => EnumerableExtensions.BuildCandidateNames(t.Item1, t.Item2)) .Then("order is preserved", r => r.Count == 3 && r[0] == "first.json" && r[1] == "second.json" && r[2] == "third.json") @@ -110,7 +117,8 @@ public async Task BuildCandidateNames_windows_path_override() return; // Skip on non-Windows platforms } - await Given("Windows-style path override", () => (@"C:\path\to\custom.json", new[] { "default.json" })) + var setup = new[] { "default.json" }; + await Given("Windows-style path override", () => (@"C:\path\to\custom.json", setup)) .When("BuildCandidateNames is called", t => EnumerableExtensions.BuildCandidateNames(t.Item1, t.Item2)) .Then("extracted filename is first", r => r[0] == "custom.json") .AssertPassed(); @@ -120,7 +128,8 @@ await Given("Windows-style path override", () => (@"C:\path\to\custom.json", new [Fact] public async Task BuildCandidateNames_unix_path_override() { - await Given("Unix-style path override", () => ("/path/to/custom.json", new[] { "default.json" })) + var setup = new[] { "default.json" }; + await Given("Unix-style path override", () => ("/path/to/custom.json", setup)) .When("BuildCandidateNames is called", t => EnumerableExtensions.BuildCandidateNames(t.Item1, t.Item2)) .Then("extracted filename is first", r => r[0] == "custom.json") .AssertPassed(); diff --git a/tests/JD.Efcpt.Build.Tests/Integration/SnowflakeSchemaIntegrationTests.cs b/tests/JD.Efcpt.Build.Tests/Integration/SnowflakeSchemaIntegrationTests.cs index e32b423..9234f0a 100644 --- a/tests/JD.Efcpt.Build.Tests/Integration/SnowflakeSchemaIntegrationTests.cs +++ b/tests/JD.Efcpt.Build.Tests/Integration/SnowflakeSchemaIntegrationTests.cs @@ -241,9 +241,9 @@ public async Task Reads_columns_with_metadata() await Given("a Snowflake container with test schema", SetupDatabaseWithSchema) .When("schema is read", ExecuteReadSchema) .Then("customers table has correct column count", r => - r.Schema.Tables.First(t => t.Name.Equals("CUSTOMERS", StringComparison.OrdinalIgnoreCase)).Columns.Count() == 4) + r.Schema.Tables.First(t => t.Name.Equals("CUSTOMERS", StringComparison.OrdinalIgnoreCase)).Columns.Count == 4) .And("products table has correct column count", r => - r.Schema.Tables.First(t => t.Name.Equals("PRODUCTS", StringComparison.OrdinalIgnoreCase)).Columns.Count() == 4) + r.Schema.Tables.First(t => t.Name.Equals("PRODUCTS", StringComparison.OrdinalIgnoreCase)).Columns.Count == 4) .Finally(r => r.Context.Dispose()) .AssertPassed(); } diff --git a/tests/JD.Efcpt.Build.Tests/Profiling/BuildRunOutputTests.cs b/tests/JD.Efcpt.Build.Tests/Profiling/BuildRunOutputTests.cs index d569648..b360534 100644 --- a/tests/JD.Efcpt.Build.Tests/Profiling/BuildRunOutputTests.cs +++ b/tests/JD.Efcpt.Build.Tests/Profiling/BuildRunOutputTests.cs @@ -84,7 +84,7 @@ public async Task BuildStatus_enum_has_expected_values(BuildStatus status) { await Given("a BuildStatus value", () => status) .When("value is checked", s => s) - .Then("value is defined", s => Enum.IsDefined(typeof(BuildStatus), s)) + .Then("value is defined", s => Enum.IsDefined(s)) .AssertPassed(); } @@ -98,7 +98,7 @@ public async Task TaskStatus_enum_has_expected_values(ProfilingTaskStatus status { await Given("a TaskStatus value", () => status) .When("value is checked", s => s) - .Then("value is defined", s => Enum.IsDefined(typeof(ProfilingTaskStatus), s)) + .Then("value is defined", s => Enum.IsDefined(s)) .AssertPassed(); } @@ -111,7 +111,7 @@ public async Task DiagnosticLevel_enum_has_expected_values(DiagnosticLevel level { await Given("a DiagnosticLevel value", () => level) .When("value is checked", l => l) - .Then("value is defined", l => Enum.IsDefined(typeof(DiagnosticLevel), l)) + .Then("value is defined", l => Enum.IsDefined(l)) .AssertPassed(); } diff --git a/tests/JD.Efcpt.Build.Tests/Profiling/JsonTimeSpanConverterTests.cs b/tests/JD.Efcpt.Build.Tests/Profiling/JsonTimeSpanConverterTests.cs index 18fc8bc..9c8e943 100644 --- a/tests/JD.Efcpt.Build.Tests/Profiling/JsonTimeSpanConverterTests.cs +++ b/tests/JD.Efcpt.Build.Tests/Profiling/JsonTimeSpanConverterTests.cs @@ -75,4 +75,137 @@ await Given("an object with zero duration", () => obj) deserialized != null && deserialized.Duration == TimeSpan.Zero) .AssertPassed(); } + + [Scenario("Empty string is deserialized to zero TimeSpan")] + [Fact] + public async Task Empty_string_returns_zero() + { + var json = """{"Duration":""}"""; + TestObject? obj = null; + + await Given("JSON with empty duration", () => json) + .When("JSON is deserialized", j => + { + obj = JsonSerializer.Deserialize(j); + return j; + }) + .Then("TimeSpan is zero", _ => + obj != null && obj.Duration == TimeSpan.Zero) + .AssertPassed(); + } + + [Scenario("Whitespace string is deserialized to zero TimeSpan")] + [Fact] + public async Task Whitespace_returns_zero() + { + var json = """{"Duration":" "}"""; + TestObject? obj = null; + + await Given("JSON with whitespace duration", () => json) + .When("JSON is deserialized", j => + { + obj = JsonSerializer.Deserialize(j); + return j; + }) + .Then("TimeSpan is zero", _ => + obj != null && obj.Duration == TimeSpan.Zero) + .AssertPassed(); + } + + [Scenario("Numeric seconds format is parsed correctly")] + [Fact] + public async Task Numeric_seconds_format_is_parsed() + { + var json = """{"Duration":"90"}"""; + TestObject? obj = null; + + await Given("JSON with numeric seconds", () => json) + .When("JSON is deserialized", j => + { + obj = JsonSerializer.Deserialize(j); + return j; + }) + .Then("TimeSpan is correctly parsed", _ => + obj != null && obj.Duration == TimeSpan.FromSeconds(90)) + .AssertPassed(); + } + + [Scenario("Decimal seconds format is parsed correctly")] + [Fact] + public async Task Decimal_seconds_format_is_parsed() + { + var json = """{"Duration":"1.5"}"""; + TestObject? obj = null; + + await Given("JSON with decimal seconds", () => json) + .When("JSON is deserialized", j => + { + obj = JsonSerializer.Deserialize(j); + return j; + }) + .Then("TimeSpan is correctly parsed", _ => + obj != null && obj.Duration == TimeSpan.FromSeconds(1.5)) + .AssertPassed(); + } + + [Scenario("Invalid format throws JsonException")] + [Fact] + public async Task Invalid_format_throws_exception() + { + var json = """{"Duration":"invalid-duration"}"""; + + await Given("JSON with invalid duration", () => json) + .When("JSON is deserialized", j => + { + try + { + JsonSerializer.Deserialize(j); + return (success: true, exception: (Exception?)null); + } + catch (JsonException ex) + { + return (success: false, exception: (Exception?)ex); + } + }) + .Then("JsonException is thrown", r => !r.success && r.exception is JsonException) + .And("exception message mentions parse error", r => + r.exception?.Message?.Contains("Unable to parse") ?? false) + .AssertPassed(); + } + + [Scenario("Case insensitive ISO 8601 format is supported")] + [Fact] + public async Task Case_insensitive_iso8601() + { + var json = """{"Duration":"PT1M30S"}"""; // XmlConvert requires uppercase PT + TestObject? obj = null; + + await Given("JSON with uppercase ISO 8601", () => json) + .When("JSON is deserialized", j => + { + obj = JsonSerializer.Deserialize(j); + return j; + }) + .Then("TimeSpan is correctly parsed", _ => + obj != null && obj.Duration == TimeSpan.FromSeconds(90)) + .AssertPassed(); + } + + [Scenario("Complex ISO 8601 duration is parsed")] + [Fact] + public async Task Complex_iso8601_duration() + { + var json = """{"Duration":"PT1H30M15.5S"}"""; + TestObject? obj = null; + + await Given("JSON with complex ISO 8601 duration", () => json) + .When("JSON is deserialized", j => + { + obj = JsonSerializer.Deserialize(j); + return j; + }) + .Then("TimeSpan is correctly parsed", _ => + obj != null && obj.Duration == TimeSpan.FromHours(1) + TimeSpan.FromMinutes(30) + TimeSpan.FromSeconds(15.5)) + .AssertPassed(); + } } diff --git a/tests/JD.Efcpt.Build.Tests/RunEfcptTests.cs b/tests/JD.Efcpt.Build.Tests/RunEfcptTests.cs index 44c0438..62be4d7 100644 --- a/tests/JD.Efcpt.Build.Tests/RunEfcptTests.cs +++ b/tests/JD.Efcpt.Build.Tests/RunEfcptTests.cs @@ -238,9 +238,9 @@ public async Task Logs_execution_info() .When("task executes with minimal verbosity", s => ExecuteTaskWithFakeMode(s, t => t.LogVerbosity = "minimal")) .Then("task succeeds", r => r.Success) .And("info message about working directory logged", r => - r.Setup.Engine.Messages.Any(m => m.Message?.Contains("working directory") == true)) + r.Setup.Engine.Messages.Any(m => m.Message?.Contains("working directory") ?? false)) .And("info message about output logged", r => - r.Setup.Engine.Messages.Any(m => m.Message?.Contains("Output") == true)) + r.Setup.Engine.Messages.Any(m => m.Message?.Contains("Output") ?? false)) .Finally(r => r.Setup.Folder.Dispose()) .AssertPassed(); } @@ -253,7 +253,7 @@ public async Task Logs_detailed_info() .When("task executes with detailed verbosity", s => ExecuteTaskWithFakeMode(s, t => t.LogVerbosity = "detailed")) .Then("task succeeds", r => r.Success) .And("detail message about fake mode logged", r => - r.Setup.Engine.Messages.Any(m => m.Message?.Contains("EFCPT_FAKE_EFCPT") == true)) + r.Setup.Engine.Messages.Any(m => m.Message?.Contains("EFCPT_FAKE_EFCPT") ?? false)) .Finally(r => r.Setup.Folder.Dispose()) .AssertPassed(); } @@ -412,4 +412,234 @@ public async Task Handles_various_target_framework_formats(string targetFramewor .Finally(r => r.Setup.Folder.Dispose()) .AssertPassed(); } + + [Scenario("Resolves relative tool path correctly")] + [Fact] + public async Task Resolves_relative_tool_path() + { + await Given("inputs with relative tool path", () => + { + var setup = SetupForDacpacMode(); + // Create a fake tool in a subdirectory + var toolDir = setup.Folder.CreateDir("tools"); + var toolPath = Path.Combine(toolDir, "fake-efcpt.exe"); + File.WriteAllText(toolPath, "fake tool"); + return (setup, toolPath: Path.Combine("tools", "fake-efcpt.exe")); + }) + .When("task executes with relative path", ctx => + ExecuteTaskWithFakeMode(ctx.setup, t => t.ToolPath = ctx.toolPath)) + .Then("task succeeds", r => r.Success) + .Finally(r => r.Setup.Folder.Dispose()) + .AssertPassed(); + } + + [Scenario("Logs error when explicit tool path does not exist")] + [Fact] + public async Task Explicit_tool_path_not_exists_logs_error() + { + await Given("inputs with non-existent tool path", SetupForDacpacMode) + .When("task executes without fake mode", s => + { + // Use an absolute path that's valid on both Windows and Unix + var nonExistentPath = Path.Combine( + Path.GetTempPath(), + "nonexistent_dir_" + Guid.NewGuid().ToString("N"), + "nonexistent_tool.exe"); + + var task = new RunEfcpt + { + BuildEngine = s.Engine, + WorkingDirectory = s.WorkingDir, + DacpacPath = s.DacpacPath, + ConfigPath = s.ConfigPath, + RenamingPath = s.RenamingPath, + TemplateDir = s.TemplateDir, + OutputDir = s.OutputDir, + ToolPath = nonExistentPath + }; + var success = task.Execute(); + return new TaskResult(s, task, success); + }) + .Then("task fails", r => !r.Success) + .And("error is logged", r => r.Setup.Engine.Errors.Count > 0) + .And("error mentions tool path or file not found", r => + r.Setup.Engine.Errors.Any(e => + (e.Message?.Contains("nonexistent_tool.exe", StringComparison.OrdinalIgnoreCase) ?? false) || + (e.Message?.Contains("cannot find", StringComparison.OrdinalIgnoreCase) ?? false) || + (e.Message?.Contains("No such file", StringComparison.OrdinalIgnoreCase) ?? false))) + .Finally(r => r.Setup.Folder.Dispose()) + .AssertPassed(); + } + + [Scenario("Walks up directory tree to find tool manifest")] + [Fact] + public async Task Walks_up_to_find_manifest() + { + await Given("inputs with manifest in parent directory", () => + { + var folder = new TestFolder(); + // Create manifest in root + var configDir = folder.CreateDir(".config"); + var manifestPath = Path.Combine(configDir, "dotnet-tools.json"); + File.WriteAllText(manifestPath, """ + { + "version": 1, + "isRoot": true, + "tools": { + "erikej.efcorepowertools.cli": { + "version": "10.0.0", + "commands": ["efcpt"] + } + } + } + """); + + // Working directory is nested deep + var workingDir = folder.CreateDir(Path.Combine("a", "b", "c", "obj")); + var dacpac = folder.WriteFile("db.dacpac", "content"); + var config = folder.WriteFile("config.json", "{}"); + var renaming = folder.WriteFile("renaming.json", "[]"); + var templateDir = folder.CreateDir("Templates"); + var outputDir = Path.Combine(folder.Root, "Generated"); + var engine = new TestBuildEngine(); + + return new SetupState(folder, workingDir, dacpac, config, renaming, templateDir, outputDir, engine); + }) + .When("task executes in fake mode with auto mode", s => + ExecuteTaskWithFakeMode(s, t => t.ToolMode = "auto")) + .Then("task succeeds", r => r.Success) + .Finally(r => r.Setup.Folder.Dispose()) + .AssertPassed(); + } + + [Scenario("Forwards EFCPT_TEST_DACPAC environment variable to process")] + [Fact] + public async Task Forwards_test_dacpac_env_var() + { + const string testDacpacValue = "C:\\test\\fake.dacpac"; + Environment.SetEnvironmentVariable("EFCPT_TEST_DACPAC", testDacpacValue); + try + { + await Given("inputs for DACPAC mode", SetupForDacpacMode) + .When("task executes in fake mode", s => ExecuteTaskWithFakeMode(s)) + .Then("task succeeds", r => r.Success) + .And("environment variable is preserved", _ => + Environment.GetEnvironmentVariable("EFCPT_TEST_DACPAC") == testDacpacValue) + .Finally(r => r.Setup.Folder.Dispose()) + .AssertPassed(); + } + finally + { + Environment.SetEnvironmentVariable("EFCPT_TEST_DACPAC", null); + } + } + + [Scenario("Passes all required arguments in DACPAC mode")] + [Fact] + public async Task Passes_dacpac_mode_arguments() + { + await Given("inputs for DACPAC mode", SetupForDacpacMode) + .When("task executes in fake mode", s => ExecuteTaskWithFakeMode(s)) + .Then("task succeeds", r => r.Success) + .And("DACPAC path is used", r => !string.IsNullOrEmpty(r.Task.DacpacPath)) + .And("config path is used", r => !string.IsNullOrEmpty(r.Task.ConfigPath)) + .And("renaming path is used", r => !string.IsNullOrEmpty(r.Task.RenamingPath)) + .And("template dir is used", r => !string.IsNullOrEmpty(r.Task.TemplateDir)) + .And("output dir is used", r => !string.IsNullOrEmpty(r.Task.OutputDir)) + .Finally(r => r.Setup.Folder.Dispose()) + .AssertPassed(); + } + + [Scenario("Passes all required arguments in connection string mode")] + [Fact] + public async Task Passes_connection_string_mode_arguments() + { + await Given("inputs for connection string mode", SetupForConnectionStringMode) + .When("task executes in fake mode", s => + { + Environment.SetEnvironmentVariable("EFCPT_FAKE_EFCPT", "true"); + try + { + var task = new RunEfcpt + { + BuildEngine = s.Engine, + WorkingDirectory = s.WorkingDir, + ConnectionString = "Server=.;Database=test;", + UseConnectionStringMode = "true", + ConfigPath = s.ConfigPath, + RenamingPath = s.RenamingPath, + TemplateDir = s.TemplateDir, + OutputDir = s.OutputDir, + ToolMode = "auto", + ToolPackageId = "ErikEJ.EFCorePowerTools.Cli" + }; + var success = task.Execute(); + return new TaskResult(s, task, success); + } + finally + { + Environment.SetEnvironmentVariable("EFCPT_FAKE_EFCPT", null); + } + }) + .Then("task succeeds", r => r.Success) + .And("connection string is used", r => !string.IsNullOrEmpty(r.Task.ConnectionString)) + .And("connection string mode flag is set", r => r.Task.UseConnectionStringMode == "true") + .And("config path is used", r => !string.IsNullOrEmpty(r.Task.ConfigPath)) + .Finally(r => r.Setup.Folder.Dispose()) + .AssertPassed(); + } + + [Scenario("Template directory path is passed correctly")] + [Fact] + public async Task Template_directory_passed_correctly() + { + await Given("inputs with custom template directory", () => + { + var setup = SetupForDacpacMode(); + var customTemplateDir = setup.Folder.CreateDir("CustomTemplates"); + File.WriteAllText(Path.Combine(customTemplateDir, "test.template"), "template content"); + return (setup, customTemplateDir); + }) + .When("task executes with custom template dir", ctx => + ExecuteTaskWithFakeMode(ctx.setup, t => t.TemplateDir = ctx.customTemplateDir)) + .Then("task succeeds", r => r.Success) + .And("custom template dir is used", r => r.Task.TemplateDir.Contains("CustomTemplates")) + .Finally(r => r.Setup.Folder.Dispose()) + .AssertPassed(); + } + + [Scenario("Provider parameter is passed correctly")] + [Theory] + [InlineData("mssql")] + [InlineData("sqlite")] + [InlineData("postgres")] + public async Task Provider_parameter_passed_correctly(string provider) + { + await Given("inputs for DACPAC mode", SetupForDacpacMode) + .When("task executes with specific provider", s => + ExecuteTaskWithFakeMode(s, t => t.Provider = provider)) + .Then("task succeeds", r => r.Success) + .And("provider is set correctly", r => r.Task.Provider == provider) + .Finally(r => r.Setup.Folder.Dispose()) + .AssertPassed(); + } + + [Scenario("ProjectPath parameter is passed correctly")] + [Fact] + public async Task Project_path_passed_correctly() + { + await Given("inputs with project path", () => + { + var setup = SetupForDacpacMode(); + var projectPath = Path.Combine(setup.Folder.Root, "Test.csproj"); + File.WriteAllText(projectPath, ""); + return (setup, projectPath); + }) + .When("task executes with project path", ctx => + ExecuteTaskWithFakeMode(ctx.setup, t => t.ProjectPath = ctx.projectPath)) + .Then("task succeeds", r => r.Success) + .And("project path is set", r => !string.IsNullOrEmpty(r.Task.ProjectPath)) + .Finally(r => r.Setup.Folder.Dispose()) + .AssertPassed(); + } } diff --git a/tests/JD.Efcpt.Build.Tests/RunSqlPackageTests.cs b/tests/JD.Efcpt.Build.Tests/RunSqlPackageTests.cs index 9d4fae7..81153f7 100644 --- a/tests/JD.Efcpt.Build.Tests/RunSqlPackageTests.cs +++ b/tests/JD.Efcpt.Build.Tests/RunSqlPackageTests.cs @@ -140,6 +140,8 @@ await Given("a target directory that doesn't exist", () => .AssertPassed(); } + private static readonly string[] stringArray = new[] { "Security", "ServerObjects", "Storage" }; + [Scenario("File movement skips system security objects")] [Fact] public async Task File_movement_skips_system_objects() @@ -178,7 +180,7 @@ await Given("extracted files including system objects", () => .When("MoveDirectoryContents logic is simulated", s => { // Simulate the MoveDirectoryContents logic - var excludedPaths = new[] { "Security", "ServerObjects", "Storage" }; + var excludedPaths = stringArray; var sourceDirNormalized = s.sourceDir.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar) + Path.DirectorySeparatorChar; foreach (var file in Directory.GetFiles(s.sourceDir, "*", SearchOption.AllDirectories)) @@ -237,6 +239,7 @@ await Given("extracted files including system objects", () => [Fact] public async Task File_movement_handles_nested_directories() { + var excludedPaths = new[] { "Security", "ServerObjects", "Storage" }; await Given("extracted files in nested directories", () => { var state = Setup(); @@ -254,7 +257,6 @@ await Given("extracted files in nested directories", () => }) .When("MoveDirectoryContents logic is simulated", s => { - var excludedPaths = new[] { "Security", "ServerObjects", "Storage" }; var sourceDirNormalized = s.sourceDir.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar) + Path.DirectorySeparatorChar; foreach (var file in Directory.GetFiles(s.sourceDir, "*", SearchOption.AllDirectories)) @@ -313,7 +315,7 @@ await Given("source and target with conflicting files", () => }) .When("MoveDirectoryContents logic is simulated with overwrite", s => { - var excludedPaths = new[] { "Security", "ServerObjects", "Storage" }; + var excludedPaths = stringArray; var sourceDirNormalized = s.sourceDir.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar) + Path.DirectorySeparatorChar; foreach (var file in Directory.GetFiles(s.sourceDir, "*", SearchOption.AllDirectories)) @@ -748,4 +750,195 @@ await Given("a custom dotnet exe path", () => .Finally(r => Cleanup(r.state)) .AssertPassed(); } + + [Scenario("Cleanup removes temporary directory")] + [Fact] + public async Task Cleanup_removes_temporary_directory() + { + await Given("extraction completed with temp directory", () => + { + var state = Setup(); + var tempExtractDir = Path.Combine(state.TempDir, "extract_temp"); + Directory.CreateDirectory(tempExtractDir); + File.WriteAllText(Path.Combine(tempExtractDir, "temp.sql"), "-- temp"); + return (state, tempExtractDir); + }) + .When("cleanup is performed", ctx => + { + // Simulate cleanup + if (Directory.Exists(ctx.tempExtractDir)) + Directory.Delete(ctx.tempExtractDir, true); + return ctx; + }) + .Then("temp directory is removed", r => !Directory.Exists(r.tempExtractDir)) + .Finally(r => Cleanup(r.state)) + .AssertPassed(); + } + + [Scenario("File movement skips Security.RoleMembership objects")] + [Fact] + public async Task File_movement_skips_security_role_membership() + { + await Given("extracted files with security role membership", () => + { + var state = Setup(); + var extractDir = Path.Combine(state.TempDir, "extracted"); + Directory.CreateDirectory(extractDir); + + // Create security objects that should be skipped + File.WriteAllText(Path.Combine(extractDir, "Security.RoleMembership.sql"), "-- role membership"); + File.WriteAllText(Path.Combine(extractDir, "dbo.Table1.sql"), "-- table"); + + return (state, extractDir); + }) + .When("files are filtered", ctx => + { + var files = Directory.GetFiles(ctx.extractDir); + var nonSecurityFiles = files.Where(f => !Path.GetFileName(f).StartsWith("Security.")).ToList(); + return (ctx.state, nonSecurityFiles); + }) + .Then("security files are excluded", r => r.nonSecurityFiles.All(f => !Path.GetFileName(f).StartsWith("Security."))) + .And("regular files are included", r => r.nonSecurityFiles.Any(f => f.Contains("Table1"))) + .Finally(r => Cleanup(r.state)) + .AssertPassed(); + } + + [Scenario("File movement skips Server Triggers")] + [Fact] + public async Task File_movement_skips_server_triggers() + { + await Given("extracted files with server triggers", () => + { + var state = Setup(); + var extractDir = Path.Combine(state.TempDir, "extracted"); + Directory.CreateDirectory(extractDir); + + // Create server trigger that should be skipped + var serverDir = Path.Combine(extractDir, "Server Triggers"); + Directory.CreateDirectory(serverDir); + File.WriteAllText(Path.Combine(serverDir, "trigger1.sql"), "-- server trigger"); + File.WriteAllText(Path.Combine(extractDir, "dbo.StoredProc.sql"), "-- proc"); + + return (state, extractDir); + }) + .When("files are filtered", ctx => + { + var files = Directory.GetFiles(ctx.extractDir, "*.sql", SearchOption.AllDirectories); + var nonServerFiles = files.Where(f => !f.Contains("Server Triggers")).ToList(); + return (ctx.state, nonServerFiles); + }) + .Then("server trigger files are excluded", r => !r.nonServerFiles.Any(f => f.Contains("Server Triggers"))) + .And("regular files are included", r => r.nonServerFiles.Any(f => f.Contains("StoredProc"))) + .Finally(r => Cleanup(r.state)) + .AssertPassed(); + } + + [Scenario("File movement skips Storage filegroups")] + [Fact] + public async Task File_movement_skips_storage_filegroups() + { + await Given("extracted files with storage filegroups", () => + { + var state = Setup(); + var extractDir = Path.Combine(state.TempDir, "extracted"); + Directory.CreateDirectory(extractDir); + + // Create storage objects that should be skipped + var storageDir = Path.Combine(extractDir, "Storage"); + Directory.CreateDirectory(storageDir); + File.WriteAllText(Path.Combine(storageDir, "PRIMARY.sql"), "-- filegroup"); + File.WriteAllText(Path.Combine(extractDir, "dbo.View1.sql"), "-- view"); + + return (state, extractDir); + }) + .When("files are filtered", ctx => + { + var files = Directory.GetFiles(ctx.extractDir, "*.sql", SearchOption.AllDirectories); + var nonStorageFiles = files.Where(f => !f.Contains("Storage")).ToList(); + return (ctx.state, nonStorageFiles); + }) + .Then("storage files are excluded", r => !r.nonStorageFiles.Any(f => f.Contains("Storage"))) + .And("regular files are included", r => r.nonStorageFiles.Any(f => f.Contains("View1"))) + .Finally(r => Cleanup(r.state)) + .AssertPassed(); + } + + [Scenario("ToolVersion can be set on task")] + [Fact] + public async Task ToolVersion_can_be_set() + { + await Given("a task with tool version", () => + { + var state = Setup(); + const string toolVersion = "1.2.3"; + return (state, toolVersion); + }) + .When("tool version is set on task", ctx => + { + var task = new RunSqlPackage + { + BuildEngine = ctx.state.Engine, + TargetDirectory = ctx.state.TempDir, + ConnectionString = "Server=.;", + ToolVersion = ctx.toolVersion + }; + return (ctx.state, task); + }) + .Then("ToolVersion property is set correctly", r => r.task.ToolVersion == "1.2.3") + .Finally(r => Cleanup(r.state)) + .AssertPassed(); + } + + [Scenario("ProjectPath can be set on task")] + [Fact] + public async Task ProjectPath_can_be_set() + { + await Given("a task with project path", () => + { + var state = Setup(); + var projectPath = Path.Combine(state.TempDir, "Test.sqlproj"); + return (state, projectPath); + }) + .When("project path is set on task", ctx => + { + var task = new RunSqlPackage + { + BuildEngine = ctx.state.Engine, + TargetDirectory = ctx.state.TempDir, + ConnectionString = "Server=.;", + ProjectPath = ctx.projectPath + }; + return (ctx.state, ctx.projectPath, task); + }) + .Then("ProjectPath property is set correctly", r => r.task.ProjectPath == r.Item2) + .Finally(r => Cleanup(r.state)) + .AssertPassed(); + } + + [Scenario("WorkingDirectory can be set on task")] + [Fact] + public async Task WorkingDirectory_can_be_set() + { + await Given("a task with working directory", () => + { + var state = Setup(); + var workingDir = Path.Combine(state.TempDir, "working"); + Directory.CreateDirectory(workingDir); + return (state, workingDir); + }) + .When("working directory is set on task", ctx => + { + var task = new RunSqlPackage + { + BuildEngine = ctx.state.Engine, + TargetDirectory = ctx.state.TempDir, + ConnectionString = "Server=.;", + WorkingDirectory = ctx.workingDir + }; + return (ctx.state, ctx.workingDir, task); + }) + .Then("WorkingDirectory property is set correctly", r => r.task.WorkingDirectory == r.Item2) + .Finally(r => Cleanup(r.state)) + .AssertPassed(); + } } diff --git a/tests/JD.Efcpt.Build.Tests/SqlProjectTargetGenerationTests.cs b/tests/JD.Efcpt.Build.Tests/SqlProjectTargetGenerationTests.cs new file mode 100644 index 0000000..ed051d3 --- /dev/null +++ b/tests/JD.Efcpt.Build.Tests/SqlProjectTargetGenerationTests.cs @@ -0,0 +1,130 @@ +using JD.Efcpt.Build.Tests.Infrastructure; +using Xunit; +using Xunit.Abstractions; + +namespace JD.Efcpt.Build.Tests; + +/// +/// Tests to validate that SQL project detection targets execute correctly in generated MSBuild XML. +/// These tests validate our assumptions about the generated targets file structure. +/// +public sealed class SqlProjectTargetGenerationTests(ITestOutputHelper output) +{ + private readonly ITestOutputHelper _output = output; + + [Fact] + public void Generated_targets_file_uses_semicolons_not_backslashes() + { + // Arrange - locate the generated targets file + var testAssemblyPath = typeof(SqlProjectTargetGenerationTests).Assembly.Location; + var repoRoot = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(testAssemblyPath)!, "..", "..", "..", "..", "..")); + var targetsPath = Path.Combine(repoRoot, "src", "JD.Efcpt.Build", "buildTransitive", "JD.Efcpt.Build.targets"); + + _output.WriteLine($"Checking targets file at: {targetsPath}"); + + // Act - read the file + Assert.True(File.Exists(targetsPath), $"Targets file not found at: {targetsPath}"); + var targetsContent = File.ReadAllText(targetsPath); + + // Assert - validate semicolons are used for target lists + Assert.Contains("_EfcptDetectSqlProject", targetsContent); + Assert.Contains("BeforeTargets=\"BeforeBuild;BeforeRebuild\"", targetsContent); + + // Critical assertion: must NOT contain backslash separator + Assert.DoesNotContain("BeforeTargets=\"BeforeBuild\\BeforeRebuild\"", targetsContent); + + _output.WriteLine("✓ _EfcptDetectSqlProject uses correct semicolon separator"); + } + + [Fact] + public void Generated_targets_file_has_correct_sql_detection_target() + { + // Arrange + var testAssemblyPath = typeof(SqlProjectTargetGenerationTests).Assembly.Location; + var repoRoot = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(testAssemblyPath)!, "..", "..", "..", "..", "..")); + var targetsPath = Path.Combine(repoRoot, "src", "JD.Efcpt.Build", "buildTransitive", "JD.Efcpt.Build.targets"); + + // Act + var targetsContent = File.ReadAllText(targetsPath); + + // Assert - target structure + Assert.Contains("]*BeforeTargets=""Build"""; + Assert.Matches(afterSqlGenPattern, targetsContent); + + // And it depends on the SQL file warnings task + Assert.Contains("DependsOnTargets=\"EfcptAddSqlFileWarnings\"", targetsContent); + + // And it's conditional on being a SQL project + var lineWithAfter = targetsContent.Split('\n').First(l => l.Contains("AfterSqlProjGeneration") && l.Contains(" l.Contains("_EfcptIsSqlProject") && l.Contains("Condition=")) + .ToList(); + + Assert.NotEmpty(sqlTargetLines); + + foreach (var line in sqlTargetLines) + { + // Should have proper condition formatting + Assert.Contains("Condition=", line); + _output.WriteLine($"Condition line: {line.Trim()}"); + } + + _output.WriteLine($"✓ Found {sqlTargetLines.Count} condition statements"); + } +} diff --git a/tests/JD.Efcpt.Build.Tests/coverlet.runsettings b/tests/JD.Efcpt.Build.Tests/coverlet.runsettings new file mode 100644 index 0000000..47e4389 --- /dev/null +++ b/tests/JD.Efcpt.Build.Tests/coverlet.runsettings @@ -0,0 +1,15 @@ + + + + + + + cobertura,opencover + [*.Tests]*,[xunit.*]* + [JD.Efcpt.Build.Tasks]* + ../../../src/ + + + + + diff --git a/tests/JD.Efcpt.Sdk.IntegrationTests/BuildTransitiveTests.cs b/tests/JD.Efcpt.Sdk.IntegrationTests/BuildTransitiveTests.cs index 32f1f72..cf4fb24 100644 --- a/tests/JD.Efcpt.Sdk.IntegrationTests/BuildTransitiveTests.cs +++ b/tests/JD.Efcpt.Sdk.IntegrationTests/BuildTransitiveTests.cs @@ -22,42 +22,42 @@ public BuildTransitiveTests(SdkPackageTestFixture fixture) [Fact] public void SdkPackage_ContainsSdkFolder() { - var entries = GetPackageEntries(_fixture.SdkPackagePath); + var entries = GetPackageEntries(SdkPackageTestFixture.SdkPackagePath); entries.Should().Contain(e => e.StartsWith("Sdk/"), "SDK package should contain Sdk folder"); } [Fact] public void SdkPackage_ContainsSdkProps() { - var entries = GetPackageEntries(_fixture.SdkPackagePath); + var entries = GetPackageEntries(SdkPackageTestFixture.SdkPackagePath); entries.Should().Contain("Sdk/Sdk.props", "SDK package should contain Sdk/Sdk.props"); } [Fact] public void SdkPackage_ContainsSdkTargets() { - var entries = GetPackageEntries(_fixture.SdkPackagePath); + var entries = GetPackageEntries(SdkPackageTestFixture.SdkPackagePath); entries.Should().Contain("Sdk/Sdk.targets", "SDK package should contain Sdk/Sdk.targets"); } [Fact] public void SdkPackage_ContainsBuildFolder() { - var entries = GetPackageEntries(_fixture.SdkPackagePath); + var entries = GetPackageEntries(SdkPackageTestFixture.SdkPackagePath); entries.Should().Contain(e => e.StartsWith("build/"), "SDK package should contain build folder"); } [Fact] public void SdkPackage_ContainsSharedBuildProps() { - var entries = GetPackageEntries(_fixture.SdkPackagePath); + var entries = GetPackageEntries(SdkPackageTestFixture.SdkPackagePath); entries.Should().Contain("build/JD.Efcpt.Build.props", "SDK package should contain shared build props in build folder"); } [Fact] public void SdkPackage_ContainsSharedBuildTargets() { - var entries = GetPackageEntries(_fixture.SdkPackagePath); + var entries = GetPackageEntries(SdkPackageTestFixture.SdkPackagePath); entries.Should().Contain("build/JD.Efcpt.Build.targets", "SDK package should contain shared build targets in build folder"); } @@ -68,7 +68,7 @@ public void SdkPackage_ContainsSharedBuildTargets() [Fact] public void SdkPackage_DoesNotContainBuildTransitiveFolder() { - var entries = GetPackageEntries(_fixture.SdkPackagePath); + var entries = GetPackageEntries(SdkPackageTestFixture.SdkPackagePath); entries.Should().NotContain(e => e.StartsWith("buildTransitive/"), "SDK package should NOT contain buildTransitive folder - we use build/ to prevent transitive propagation"); } @@ -76,14 +76,14 @@ public void SdkPackage_DoesNotContainBuildTransitiveFolder() [Fact] public void SdkPackage_ContainsTasksFolder() { - var entries = GetPackageEntries(_fixture.SdkPackagePath); + var entries = GetPackageEntries(SdkPackageTestFixture.SdkPackagePath); entries.Should().Contain(e => e.StartsWith("tasks/"), "SDK package should contain tasks folder"); } [Fact] public void SdkPackage_ContainsNet80Tasks() { - var entries = GetPackageEntries(_fixture.SdkPackagePath); + var entries = GetPackageEntries(SdkPackageTestFixture.SdkPackagePath); entries.Should().Contain(e => e.StartsWith("tasks/net8.0/") && e.EndsWith(".dll"), "SDK package should contain net8.0 task assemblies"); } @@ -91,7 +91,7 @@ public void SdkPackage_ContainsNet80Tasks() [Fact] public void SdkPackage_ContainsNet90Tasks() { - var entries = GetPackageEntries(_fixture.SdkPackagePath); + var entries = GetPackageEntries(SdkPackageTestFixture.SdkPackagePath); entries.Should().Contain(e => e.StartsWith("tasks/net9.0/") && e.EndsWith(".dll"), "SDK package should contain net9.0 task assemblies"); } @@ -99,7 +99,7 @@ public void SdkPackage_ContainsNet90Tasks() [Fact] public void SdkPackage_ContainsNet100Tasks() { - var entries = GetPackageEntries(_fixture.SdkPackagePath); + var entries = GetPackageEntries(SdkPackageTestFixture.SdkPackagePath); entries.Should().Contain(e => e.StartsWith("tasks/net10.0/") && e.EndsWith(".dll"), "SDK package should contain net10.0 task assemblies"); } @@ -107,21 +107,21 @@ public void SdkPackage_ContainsNet100Tasks() [Fact] public void SdkPackage_ContainsDefaultsFolder() { - var entries = GetPackageEntries(_fixture.SdkPackagePath); + var entries = GetPackageEntries(SdkPackageTestFixture.SdkPackagePath); entries.Should().Contain(e => e.Contains("Defaults/"), "SDK package should contain Defaults folder"); } [Fact] public void SdkPackage_ContainsDefaultConfig() { - var entries = GetPackageEntries(_fixture.SdkPackagePath); + var entries = GetPackageEntries(SdkPackageTestFixture.SdkPackagePath); entries.Should().Contain(e => e.Contains("efcpt-config.json"), "SDK package should contain default config file"); } [Fact] public void SdkPackage_ContainsT4Templates() { - var entries = GetPackageEntries(_fixture.SdkPackagePath); + var entries = GetPackageEntries(SdkPackageTestFixture.SdkPackagePath); entries.Should().Contain(e => e.EndsWith(".t4"), "SDK package should contain T4 templates"); } @@ -133,7 +133,7 @@ public void SdkPackage_ContainsT4Templates() [Fact] public void BuildPackage_ContainsBuildFolder() { - var entries = GetPackageEntries(_fixture.BuildPackagePath); + var entries = GetPackageEntries(SdkPackageTestFixture.BuildPackagePath); entries.Should().Contain(e => e.StartsWith("build/"), "Build package should contain build folder for direct consumers only"); } @@ -145,7 +145,7 @@ public void BuildPackage_ContainsBuildFolder() [Fact] public void BuildPackage_DoesNotContainBuildTransitiveFolder() { - var entries = GetPackageEntries(_fixture.BuildPackagePath); + var entries = GetPackageEntries(SdkPackageTestFixture.BuildPackagePath); entries.Should().NotContain(e => e.StartsWith("buildTransitive/"), "Build package should NOT contain buildTransitive folder - we use build/ to prevent transitive propagation"); } @@ -154,12 +154,12 @@ public void BuildPackage_DoesNotContainBuildTransitiveFolder() public void SdkAndBuildPackages_HaveMatchingSharedBuildContent() { // Get shared build content from SDK (JD.Efcpt.Build.props and JD.Efcpt.Build.targets) - var sdkSharedEntries = GetPackageEntries(_fixture.SdkPackagePath) + var sdkSharedEntries = GetPackageEntries(SdkPackageTestFixture.SdkPackagePath) .Where(e => e.StartsWith("build/JD.Efcpt.Build.") && !e.EndsWith("/")) .Select(e => e.Replace("build/", "")) .ToHashSet(); - var buildEntries = GetPackageEntries(_fixture.BuildPackagePath) + var buildEntries = GetPackageEntries(SdkPackageTestFixture.BuildPackagePath) .Where(e => e.StartsWith("build/JD.Efcpt.Build.") && !e.EndsWith("/")) .Select(e => e.Replace("build/", "")) .ToHashSet(); @@ -177,7 +177,7 @@ public void SdkAndBuildPackages_HaveMatchingSharedBuildContent() public void BuildPackage_BuildPropsEnablesByDefault() { // Arrange & Act - var propsContent = GetFileContentFromPackage(_fixture.BuildPackagePath, "build/JD.Efcpt.Build.props"); + var propsContent = GetFileContentFromPackage(SdkPackageTestFixture.BuildPackagePath, "build/JD.Efcpt.Build.props"); // Assert - Must enable EfcptEnabled by default propsContent.Should().Contain("EfcptEnabled", @@ -194,7 +194,7 @@ public void BuildPackage_BuildPropsEnablesByDefault() public void BuildPackage_BuildTargetsHasTaskRegistrations() { // Arrange & Act - var targetsContent = GetFileContentFromPackage(_fixture.BuildPackagePath, "build/JD.Efcpt.Build.targets"); + var targetsContent = GetFileContentFromPackage(SdkPackageTestFixture.BuildPackagePath, "build/JD.Efcpt.Build.targets"); // Assert - Must have UsingTask elements targetsContent.Should().Contain("UsingTask", @@ -210,7 +210,7 @@ public void BuildPackage_BuildTargetsHasTaskRegistrations() public void BuildPackage_TaskAssemblyPathUsesMSBuildThisFileDirectory() { // Arrange & Act - var targetsContent = GetFileContentFromPackage(_fixture.BuildPackagePath, "build/JD.Efcpt.Build.targets"); + var targetsContent = GetFileContentFromPackage(SdkPackageTestFixture.BuildPackagePath, "build/JD.Efcpt.Build.targets"); // Assert - Task assembly path must be relative to the targets file targetsContent.Should().Contain("$(MSBuildThisFileDirectory)", diff --git a/tests/JD.Efcpt.Sdk.IntegrationTests/CodeGenerationTests.cs b/tests/JD.Efcpt.Sdk.IntegrationTests/CodeGenerationTests.cs index 87d2437..2c762fb 100644 --- a/tests/JD.Efcpt.Sdk.IntegrationTests/CodeGenerationTests.cs +++ b/tests/JD.Efcpt.Sdk.IntegrationTests/CodeGenerationTests.cs @@ -150,7 +150,7 @@ public async Task IncrementalBuild_SkipsGenerationWhenUnchanged() public async Task CustomRootNamespace_IsApplied() { // Arrange - _builder.CopyDatabaseProject(_fixture.GetTestFixturesPath()); + TestProjectBuilder.CopyDatabaseProject(SdkPackageTestFixture.GetTestFixturesPath()); var additionalContent = @" MyCustomNamespace @@ -169,7 +169,7 @@ public async Task CustomRootNamespace_IsApplied() private async Task BuildSdkProject(string targetFramework) { - _builder.CopyDatabaseProject(_fixture.GetTestFixturesPath()); + TestProjectBuilder.CopyDatabaseProject(SdkPackageTestFixture.GetTestFixturesPath()); _builder.CreateSdkProject($"TestProject_{targetFramework.Replace(".", "")}", targetFramework); // BuildAsync handles restore automatically var buildResult = await _builder.BuildAsync(); diff --git a/tests/JD.Efcpt.Sdk.IntegrationTests/FrameworkMsBuildTests.cs b/tests/JD.Efcpt.Sdk.IntegrationTests/FrameworkMsBuildTests.cs index 2843a3b..f674544 100644 --- a/tests/JD.Efcpt.Sdk.IntegrationTests/FrameworkMsBuildTests.cs +++ b/tests/JD.Efcpt.Sdk.IntegrationTests/FrameworkMsBuildTests.cs @@ -39,7 +39,7 @@ public async Task FrameworkMsBuild_BuildPackage_GeneratesEntityModels() "MSBuild.exe not found - Visual Studio must be installed to run this test"); // Arrange - _builder.CopyDatabaseProject(_fixture.GetTestFixturesPath()); + TestProjectBuilder.CopyDatabaseProject(SdkPackageTestFixture.GetTestFixturesPath()); _builder.CreateBuildPackageProject("TestEfProject_framework", "net8.0"); // Act - Build with MSBuild.exe (Framework MSBuild) @@ -67,7 +67,7 @@ public async Task FrameworkMsBuild_BuildPackage_GeneratesDbContext() "MSBuild.exe not found - Visual Studio must be installed to run this test"); // Arrange - _builder.CopyDatabaseProject(_fixture.GetTestFixturesPath()); + TestProjectBuilder.CopyDatabaseProject(SdkPackageTestFixture.GetTestFixturesPath()); _builder.CreateBuildPackageProject("TestEfProject_framework_ctx", "net8.0"); // Act - BuildWithMSBuildExeAsync passes -restore to MSBuild.exe @@ -89,7 +89,7 @@ public async Task FrameworkMsBuild_Sdk_GeneratesEntityModels() "MSBuild.exe not found - Visual Studio must be installed to run this test"); // Arrange - _builder.CopyDatabaseProject(_fixture.GetTestFixturesPath()); + TestProjectBuilder.CopyDatabaseProject(SdkPackageTestFixture.GetTestFixturesPath()); _builder.CreateSdkProject("TestEfProject_sdk_framework", "net8.0"); // Act - BuildWithMSBuildExeAsync passes -restore to MSBuild.exe @@ -115,7 +115,7 @@ public async Task FrameworkMsBuild_SelectsNet472TaskFolder() "MSBuild.exe not found - Visual Studio must be installed to run this test"); // Arrange - _builder.CopyDatabaseProject(_fixture.GetTestFixturesPath()); + TestProjectBuilder.CopyDatabaseProject(SdkPackageTestFixture.GetTestFixturesPath()); _builder.CreateBuildPackageProject("TestEfProject_net472_check", "net8.0"); // Add detailed logging to see task assembly selection @@ -144,7 +144,7 @@ public async Task FrameworkMsBuild_IncrementalBuild_SkipsRegenerationWhenUnchang "MSBuild.exe not found - Visual Studio must be installed to run this test"); // Arrange - _builder.CopyDatabaseProject(_fixture.GetTestFixturesPath()); + TestProjectBuilder.CopyDatabaseProject(SdkPackageTestFixture.GetTestFixturesPath()); _builder.CreateBuildPackageProject("TestEfProject_incremental", "net8.0"); // Act - First build (BuildWithMSBuildExeAsync passes -restore to MSBuild.exe) diff --git a/tests/JD.Efcpt.Sdk.IntegrationTests/JD.Efcpt.Sdk.IntegrationTests.csproj b/tests/JD.Efcpt.Sdk.IntegrationTests/JD.Efcpt.Sdk.IntegrationTests.csproj index fe6bb88..7280fe2 100644 --- a/tests/JD.Efcpt.Sdk.IntegrationTests/JD.Efcpt.Sdk.IntegrationTests.csproj +++ b/tests/JD.Efcpt.Sdk.IntegrationTests/JD.Efcpt.Sdk.IntegrationTests.csproj @@ -10,6 +10,7 @@ + diff --git a/tests/JD.Efcpt.Sdk.IntegrationTests/SdkIntegrationTests.cs b/tests/JD.Efcpt.Sdk.IntegrationTests/SdkIntegrationTests.cs index 930da87..44a92da 100644 --- a/tests/JD.Efcpt.Sdk.IntegrationTests/SdkIntegrationTests.cs +++ b/tests/JD.Efcpt.Sdk.IntegrationTests/SdkIntegrationTests.cs @@ -23,7 +23,7 @@ public SdkNet80Tests(SdkPackageTestFixture fixture) public async Task Sdk_Net80_BuildsSuccessfully() { // Arrange - _builder.CopyDatabaseProject(_fixture.GetTestFixturesPath()); + TestProjectBuilder.CopyDatabaseProject(SdkPackageTestFixture.GetTestFixturesPath()); _builder.CreateSdkProject("TestEfProject_net80", "net8.0"); // Act - BuildAsync handles restore automatically @@ -37,7 +37,7 @@ public async Task Sdk_Net80_BuildsSuccessfully() public async Task Sdk_Net80_GeneratesEntityModels() { // Arrange - _builder.CopyDatabaseProject(_fixture.GetTestFixturesPath()); + TestProjectBuilder.CopyDatabaseProject(SdkPackageTestFixture.GetTestFixturesPath()); _builder.CreateSdkProject("TestEfProject_net80", "net8.0"); // Act - BuildAsync handles restore automatically @@ -56,7 +56,7 @@ public async Task Sdk_Net80_GeneratesEntityModels() public async Task Sdk_Net80_GeneratesDbContext() { // Arrange - _builder.CopyDatabaseProject(_fixture.GetTestFixturesPath()); + TestProjectBuilder.CopyDatabaseProject(SdkPackageTestFixture.GetTestFixturesPath()); _builder.CreateSdkProject("TestEfProject_net80", "net8.0"); // Act - BuildAsync handles restore automatically @@ -72,7 +72,7 @@ public async Task Sdk_Net80_GeneratesDbContext() public async Task Sdk_Net80_GeneratesEntityConfigurationsInDbContext() { // Arrange - _builder.CopyDatabaseProject(_fixture.GetTestFixturesPath()); + TestProjectBuilder.CopyDatabaseProject(SdkPackageTestFixture.GetTestFixturesPath()); _builder.CreateSdkProject("TestEfProject_net80", "net8.0"); // Act - BuildAsync handles restore automatically @@ -93,7 +93,7 @@ public async Task Sdk_Net80_GeneratesEntityConfigurationsInDbContext() public async Task Sdk_Net80_CleanRemovesGeneratedFiles() { // Arrange - _builder.CopyDatabaseProject(_fixture.GetTestFixturesPath()); + TestProjectBuilder.CopyDatabaseProject(SdkPackageTestFixture.GetTestFixturesPath()); _builder.CreateSdkProject("TestEfProject_clean_net80", "net8.0"); var buildResult = await _builder.BuildAsync(); buildResult.Success.Should().BeTrue($"Build should succeed.\n{buildResult}"); @@ -130,7 +130,7 @@ public SdkNet90Tests(SdkPackageTestFixture fixture) public async Task Sdk_Net90_BuildsSuccessfully() { // Arrange - _builder.CopyDatabaseProject(_fixture.GetTestFixturesPath()); + TestProjectBuilder.CopyDatabaseProject(SdkPackageTestFixture.GetTestFixturesPath()); _builder.CreateSdkProject("TestEfProject_net90", "net9.0"); // Act - BuildAsync handles restore automatically @@ -144,7 +144,7 @@ public async Task Sdk_Net90_BuildsSuccessfully() public async Task Sdk_Net90_GeneratesEntityModels() { // Arrange - _builder.CopyDatabaseProject(_fixture.GetTestFixturesPath()); + TestProjectBuilder.CopyDatabaseProject(SdkPackageTestFixture.GetTestFixturesPath()); _builder.CreateSdkProject("TestEfProject_net90", "net9.0"); // Act - BuildAsync handles restore automatically @@ -180,7 +180,7 @@ public SdkNet100Tests(SdkPackageTestFixture fixture) public async Task Sdk_Net100_BuildsSuccessfully() { // Arrange - _builder.CopyDatabaseProject(_fixture.GetTestFixturesPath()); + TestProjectBuilder.CopyDatabaseProject(SdkPackageTestFixture.GetTestFixturesPath()); _builder.CreateSdkProject("TestEfProject_net100", "net10.0"); // Act - BuildAsync handles restore automatically @@ -194,7 +194,7 @@ public async Task Sdk_Net100_BuildsSuccessfully() public async Task Sdk_Net100_GeneratesEntityModels() { // Arrange - _builder.CopyDatabaseProject(_fixture.GetTestFixturesPath()); + TestProjectBuilder.CopyDatabaseProject(SdkPackageTestFixture.GetTestFixturesPath()); _builder.CreateSdkProject("TestEfProject_net100", "net10.0"); // Act - BuildAsync handles restore automatically @@ -230,7 +230,7 @@ public BuildPackageTests(SdkPackageTestFixture fixture) public async Task BuildPackage_Net80_BuildsSuccessfully() { // Arrange - _builder.CopyDatabaseProject(_fixture.GetTestFixturesPath()); + TestProjectBuilder.CopyDatabaseProject(SdkPackageTestFixture.GetTestFixturesPath()); _builder.CreateBuildPackageProject("TestEfProject_net80_pkg", "net8.0"); // Act - BuildAsync handles restore automatically @@ -244,7 +244,7 @@ public async Task BuildPackage_Net80_BuildsSuccessfully() public async Task BuildPackage_Net90_BuildsSuccessfully() { // Arrange - _builder.CopyDatabaseProject(_fixture.GetTestFixturesPath()); + TestProjectBuilder.CopyDatabaseProject(SdkPackageTestFixture.GetTestFixturesPath()); _builder.CreateBuildPackageProject("TestEfProject_net90_pkg", "net9.0"); // Act - BuildAsync handles restore automatically @@ -258,7 +258,7 @@ public async Task BuildPackage_Net90_BuildsSuccessfully() public async Task BuildPackage_Net100_BuildsSuccessfully() { // Arrange - _builder.CopyDatabaseProject(_fixture.GetTestFixturesPath()); + TestProjectBuilder.CopyDatabaseProject(SdkPackageTestFixture.GetTestFixturesPath()); _builder.CreateBuildPackageProject("TestEfProject_net100_pkg", "net10.0"); // Act - BuildAsync handles restore automatically @@ -276,7 +276,7 @@ public async Task BuildPackage_Net100_BuildsSuccessfully() public async Task BuildPackage_Net80_GeneratesEntityModels() { // Arrange - _builder.CopyDatabaseProject(_fixture.GetTestFixturesPath()); + TestProjectBuilder.CopyDatabaseProject(SdkPackageTestFixture.GetTestFixturesPath()); _builder.CreateBuildPackageProject("TestEfProject_net80_models", "net8.0"); // Act - BuildAsync handles restore automatically @@ -298,7 +298,7 @@ public async Task BuildPackage_Net80_GeneratesEntityModels() public async Task BuildPackage_Net80_GeneratesDbContext() { // Arrange - _builder.CopyDatabaseProject(_fixture.GetTestFixturesPath()); + TestProjectBuilder.CopyDatabaseProject(SdkPackageTestFixture.GetTestFixturesPath()); _builder.CreateBuildPackageProject("TestEfProject_net80_ctx", "net8.0"); // Act - BuildAsync handles restore automatically @@ -318,7 +318,7 @@ public async Task BuildPackage_Net80_GeneratesDbContext() public async Task BuildPackage_DefaultEnablesEfcpt() { // Arrange - Create project WITHOUT explicitly setting EfcptEnabled - _builder.CopyDatabaseProject(_fixture.GetTestFixturesPath()); + TestProjectBuilder.CopyDatabaseProject(SdkPackageTestFixture.GetTestFixturesPath()); _builder.CreateBuildPackageProject("TestEfProject_autoenable", "net8.0"); // Act - BuildAsync handles restore automatically @@ -338,7 +338,7 @@ public async Task BuildPackage_DefaultEnablesEfcpt() public async Task BuildPackage_Net90_GeneratesEntityModels() { // Arrange - _builder.CopyDatabaseProject(_fixture.GetTestFixturesPath()); + TestProjectBuilder.CopyDatabaseProject(SdkPackageTestFixture.GetTestFixturesPath()); _builder.CreateBuildPackageProject("TestEfProject_net90_models", "net9.0"); // Act - BuildAsync handles restore automatically @@ -358,7 +358,7 @@ public async Task BuildPackage_Net90_GeneratesEntityModels() public async Task BuildPackage_Net100_GeneratesEntityModels() { // Arrange - _builder.CopyDatabaseProject(_fixture.GetTestFixturesPath()); + TestProjectBuilder.CopyDatabaseProject(SdkPackageTestFixture.GetTestFixturesPath()); _builder.CreateBuildPackageProject("TestEfProject_net100_models", "net10.0"); // Act - BuildAsync handles restore automatically diff --git a/tests/JD.Efcpt.Sdk.IntegrationTests/SdkPackageTestFixture.cs b/tests/JD.Efcpt.Sdk.IntegrationTests/SdkPackageTestFixture.cs index edbf35f..4533e12 100644 --- a/tests/JD.Efcpt.Sdk.IntegrationTests/SdkPackageTestFixture.cs +++ b/tests/JD.Efcpt.Sdk.IntegrationTests/SdkPackageTestFixture.cs @@ -8,14 +8,14 @@ namespace JD.Efcpt.Sdk.IntegrationTests; /// public class SdkPackageTestFixture { - public string PackageOutputPath => AssemblyFixture.PackageOutputPath; - public string SdkPackagePath => AssemblyFixture.SdkPackagePath; - public string BuildPackagePath => AssemblyFixture.BuildPackagePath; - public string SdkVersion => AssemblyFixture.SdkVersion; - public string BuildVersion => AssemblyFixture.BuildVersion; - public string SharedDatabaseProjectPath => AssemblyFixture.SharedDatabaseProjectPath; - - public string GetTestFixturesPath() => AssemblyFixture.TestFixturesPath; + public static string PackageOutputPath => AssemblyFixture.PackageOutputPath; + public static string SdkPackagePath => AssemblyFixture.SdkPackagePath; + public static string BuildPackagePath => AssemblyFixture.BuildPackagePath; + public static string SdkVersion => AssemblyFixture.SdkVersion; + public static string BuildVersion => AssemblyFixture.BuildVersion; + public static string SharedDatabaseProjectPath => AssemblyFixture.SharedDatabaseProjectPath; + + public static string GetTestFixturesPath() => AssemblyFixture.TestFixturesPath; } // Collection definitions for parallel test execution diff --git a/tests/JD.Efcpt.Sdk.IntegrationTests/SqlProjectTargetDiagnosticTests.cs b/tests/JD.Efcpt.Sdk.IntegrationTests/SqlProjectTargetDiagnosticTests.cs new file mode 100644 index 0000000..31aa60e --- /dev/null +++ b/tests/JD.Efcpt.Sdk.IntegrationTests/SqlProjectTargetDiagnosticTests.cs @@ -0,0 +1,166 @@ +using FluentAssertions; +using Xunit; +using Xunit.Abstractions; + +namespace JD.Efcpt.Sdk.IntegrationTests; + +/// +/// Focused diagnostic tests to understand why SQL generation targets aren't executing. +/// These tests will use binlog and detailed logging to trace target execution. +/// +[Collection("SQL Generation Tests")] +public class SqlProjectTargetDiagnosticTests : IAsyncDisposable +{ + private readonly SdkPackageTestFixture _fixture; + private readonly TestProjectBuilder _builder; + private readonly ITestOutputHelper _output; + + public SqlProjectTargetDiagnosticTests(SdkPackageTestFixture fixture, ITestOutputHelper output) + { + _fixture = fixture; + _output = output; + _builder = new TestProjectBuilder(fixture); + } + + public async ValueTask DisposeAsync() + { + _builder.Dispose(); + } + + [Fact(Skip = "Requires SQL Server - skipped in CI environment")] + public async Task Diagnostic_SqlProject_ShowsAllTargetExecution() + { + // Arrange - Create SQL project using the proper API + var connectionString = "Server=.;Database=DiagnosticTest;Integrated Security=true;"; + _builder.CreateSqlProject("DiagnosticSqlProj", "net8.0", connectionString); + + // Act - Build with detailed verbosity to see ALL target execution + var buildResult = await _builder.BuildAsync("-v:d -p:EfcptLogVerbosity=detailed"); + + // Output diagnostic info + _output.WriteLine("=== BUILD OUTPUT (first 5000 chars) ==="); + _output.WriteLine(buildResult.Output.Substring(0, Math.Min(5000, buildResult.Output.Length))); + _output.WriteLine(""); + _output.WriteLine("=== BUILD ERRORS ==="); + _output.WriteLine(buildResult.Error); + _output.WriteLine(""); + + // Assert - Check what we find + _output.WriteLine("=== DIAGNOSTIC ANALYSIS ==="); + + // Check if EfcptEnabled is set + var hasEfcptEnabled = buildResult.Output.Contains("EfcptEnabled"); + _output.WriteLine($"EfcptEnabled mentioned: {hasEfcptEnabled}"); + + // Check if _EfcptDetectSqlProject ran + var hasDetectTarget = buildResult.Output.Contains("_EfcptDetectSqlProject"); + _output.WriteLine($"_EfcptDetectSqlProject target mentioned: {hasDetectTarget}"); + + // Check if _EfcptIsSqlProject was set + var hasIsSqlProjectProp = buildResult.Output.Contains("_EfcptIsSqlProject"); + _output.WriteLine($"_EfcptIsSqlProject property mentioned: {hasIsSqlProjectProp}"); + + // Check if any SQL generation targets ran + var hasQueryTarget = buildResult.Output.Contains("EfcptQueryDatabaseSchemaForSqlProj"); + _output.WriteLine($"EfcptQueryDatabaseSchemaForSqlProj mentioned: {hasQueryTarget}"); + + var hasExtractTarget = buildResult.Output.Contains("EfcptExtractDatabaseSchemaToScripts"); + _output.WriteLine($"EfcptExtractDatabaseSchemaToScripts mentioned: {hasExtractTarget}"); + + var hasAfterTarget = buildResult.Output.Contains("AfterSqlProjGeneration"); + _output.WriteLine($"AfterSqlProjGeneration mentioned: {hasAfterTarget}"); + + // Check for specific messages we expect + var hasSqlMessage = buildResult.Output.Contains("SQL script generation", StringComparison.OrdinalIgnoreCase) || + buildResult.Output.Contains("SQL project will build", StringComparison.OrdinalIgnoreCase); + _output.WriteLine($"SQL generation message found: {hasSqlMessage}"); + + // Look for target execution order + if (hasDetectTarget && hasAfterTarget) + { + var detectIndex = buildResult.Output.IndexOf("_EfcptDetectSqlProject", StringComparison.OrdinalIgnoreCase); + var afterIndex = buildResult.Output.IndexOf("AfterSqlProjGeneration", StringComparison.OrdinalIgnoreCase); + _output.WriteLine($"Target order - Detect at {detectIndex}, After at {afterIndex}"); + } + + // The build should succeed + buildResult.Success.Should().BeTrue($"Build should succeed for diagnostic purposes.\n{buildResult}"); + + // Key assertion: SQL detection should run + hasDetectTarget.Should().BeTrue("_EfcptDetectSqlProject target should execute"); + } + + [Fact] + public async Task Diagnostic_StandardProject_DoesNotTriggerSqlTargets() + { + // Arrange - Create standard .NET project (using existing API) + _builder.CreateSdkProject("DiagnosticStandardProj", "net8.0"); + + // Act - Build with detailed verbosity + var buildResult = await _builder.BuildAsync("-v:d"); + + // Output diagnostic info + _output.WriteLine("=== STANDARD PROJECT OUTPUT ==="); + + // Check that SQL targets are NOT mentioned + var hasDetectTarget = buildResult.Output.Contains("_EfcptDetectSqlProject"); + _output.WriteLine($"_EfcptDetectSqlProject mentioned: {hasDetectTarget}"); + + var hasAfterTarget = buildResult.Output.Contains("AfterSqlProjGeneration"); + _output.WriteLine($"AfterSqlProjGeneration mentioned: {hasAfterTarget}"); + + // Build should succeed + buildResult.Success.Should().BeTrue(); + } + + [Fact] + public async Task Diagnostic_CheckPackageContent() + { + // This test examines what's actually in the packed JD.Efcpt.Build package + _output.WriteLine($"Build package path: {SdkPackageTestFixture.BuildPackagePath}"); + _output.WriteLine($"Build package version: {SdkPackageTestFixture.BuildVersion}"); + + // Extract and check the targets file + var tempDir = Path.Combine(Path.GetTempPath(), $"pkg_inspect_{Guid.NewGuid():N}"); + Directory.CreateDirectory(tempDir); + + try + { + // Unzip the package + System.IO.Compression.ZipFile.ExtractToDirectory(SdkPackageTestFixture.BuildPackagePath, tempDir); + + var targetsFile = Path.Combine(tempDir, "buildTransitive", "JD.Efcpt.Build.targets"); + if (File.Exists(targetsFile)) + { + var content = File.ReadAllText(targetsFile); + + // Check for our critical fix + var hasCorrectSeparator = content.Contains("BeforeTargets=\"BeforeBuild;BeforeRebuild\""); + var hasWrongSeparator = content.Contains("BeforeTargets=\"BeforeBuild\\BeforeRebuild\""); + + _output.WriteLine($"Targets file exists: true"); + _output.WriteLine($"Has correct semicolon separator: {hasCorrectSeparator}"); + _output.WriteLine($"Has wrong backslash separator: {hasWrongSeparator}"); + + // Extract the specific line + var lines = content.Split('\n'); + var detectLine = lines.FirstOrDefault(l => l.Contains("_EfcptDetectSqlProject")); + if (detectLine != null) + { + _output.WriteLine($"_EfcptDetectSqlProject line: {detectLine.Trim()}"); + } + + hasCorrectSeparator.Should().BeTrue("Package should contain fixed target separator"); + hasWrongSeparator.Should().BeFalse("Package should not contain broken separator"); + } + else + { + _output.WriteLine("WARNING: Targets file not found in package!"); + } + } + finally + { + Directory.Delete(tempDir, true); + } + } +} diff --git a/tests/JD.Efcpt.Sdk.IntegrationTests/TEMPLATE_TESTS.md b/tests/JD.Efcpt.Sdk.IntegrationTests/TEMPLATE_TESTS.md deleted file mode 100644 index c68572c..0000000 --- a/tests/JD.Efcpt.Sdk.IntegrationTests/TEMPLATE_TESTS.md +++ /dev/null @@ -1,131 +0,0 @@ -# Template Integration Tests - -This document describes the integration tests for the JD.Efcpt.Build.Templates package. - -## Overview - -The `TemplateTests` class provides comprehensive integration tests for the `dotnet new efcptbuild` template functionality. These tests validate that: - -1. The template installs successfully -2. Projects created from the template have the correct structure -3. Generated projects use the SDK approach (``) -4. Project name substitution works correctly in all template files -5. Generated projects build successfully - -## Test Infrastructure - -### TemplateTestFixture - -The `TemplateTestFixture` class handles: -- Packing the JD.Efcpt.Build.Templates package -- Packing the JD.Efcpt.Sdk and JD.Efcpt.Build packages (required for building generated projects) -- Providing helper methods for template installation, creation, and uninstallation -- Managing package cleanup - -### Test Approach - -Tests use a local NuGet package store approach: -1. Packages are built and placed in a temporary directory -2. Each test creates an isolated test directory -3. Template is installed using `dotnet new install` -4. Projects are created using `dotnet new efcptbuild` -5. Projects reference the local package store via nuget.config - -## Test Cases - -### Template_InstallsSuccessfully -Verifies that the template package installs without errors and registers the `efcptbuild` short name. - -### Template_CreatesProjectWithCorrectStructure -Validates that all expected files are created: -- `{ProjectName}.csproj` -- `efcpt-config.json` -- `README.md` - -### Template_CreatesProjectUsingSdkApproach -Ensures the generated project uses `` and doesn't include a PackageReference to JD.Efcpt.Build. - -### Template_ConfigFileContainsCorrectProjectName -Verifies that the project name is correctly substituted in efcpt-config.json namespaces. - -### Template_CreatedProjectBuildsSuccessfully -End-to-end test that: -1. Creates a project from the template -2. Adds a reference to a test database project -3. Configures local package sources -4. Restores and builds the project -5. Verifies that EF Core models are generated - -### Template_ReadmeContainsSdkInformation -Validates that the README mentions JD.Efcpt.Sdk and explains the SDK approach. - -### Template_UninstallsSuccessfully -Ensures the template can be cleanly uninstalled. - -## Running the Tests - -### Run all template tests: -```bash -dotnet test --filter "FullyQualifiedName~TemplateTests" -``` - -### Run a specific test: -```bash -dotnet test --filter "FullyQualifiedName~Template_InstallsSuccessfully" -``` - -### Run with verbose output: -```bash -dotnet test --filter "FullyQualifiedName~TemplateTests" -v detailed -``` - -## Test Performance - -Template tests are grouped in a dedicated collection to run sequentially. This is necessary because: -- Template installation/uninstallation affects global dotnet new state -- Multiple parallel installations could interfere with each other -- Package building is done once and shared across all tests - -Typical execution time: 30-60 seconds for the full suite (depending on build times). - -## Troubleshooting - -### Tests fail with "Package not found" -Ensure the Template, SDK, and Build projects build successfully before running tests. - -### Tests timeout -Increase the timeout in the fixture's `PackTemplatePackageAsync` method if needed for slower environments. - -### Template already installed -Tests handle cleanup automatically, but if tests are interrupted, you may need to manually uninstall: -```bash -dotnet new uninstall JD.Efcpt.Build.Templates -``` - -## Adding New Tests - -When adding new template tests: - -1. Add the test method to `TemplateTests.cs` -2. Use the `_fixture` to install/create from the template -3. Use FluentAssertions for readable assertions -4. Ensure proper cleanup in test Dispose if needed -5. Follow the naming convention: `Template_{TestName}` - -Example: -```csharp -[Fact] -public async Task Template_NewFeature_WorksAsExpected() -{ - // Arrange - await _fixture.InstallTemplateAsync(_testDirectory); - var projectName = "TestProject"; - - // Act - var result = await _fixture.CreateProjectFromTemplateAsync(_testDirectory, projectName); - - // Assert - result.Success.Should().BeTrue(); - // Additional assertions... -} -``` diff --git a/tests/JD.Efcpt.Sdk.IntegrationTests/TemplateTestFixture.cs b/tests/JD.Efcpt.Sdk.IntegrationTests/TemplateTestFixture.cs index 38a929a..35bcc45 100644 --- a/tests/JD.Efcpt.Sdk.IntegrationTests/TemplateTestFixture.cs +++ b/tests/JD.Efcpt.Sdk.IntegrationTests/TemplateTestFixture.cs @@ -17,10 +17,10 @@ public class TemplateTestFixture : IDisposable private static readonly object _packLock = new(); private static int _instanceCount = 0; - public string TemplatePackagePath => GetTemplatePackagePath(); - public string PackageOutputPath => GetPackageOutputPath(); - public string SdkVersion => AssemblyFixture.SdkVersion; - public string BuildVersion => AssemblyFixture.BuildVersion; + public static string TemplatePackagePath => GetTemplatePackagePath(); + public static string PackageOutputPath => GetPackageOutputPath(); + public static string SdkVersion => AssemblyFixture.SdkVersion; + public static string BuildVersion => AssemblyFixture.BuildVersion; private static readonly string RepoRoot = TestUtilities.FindRepoRoot(); @@ -40,7 +40,7 @@ public TemplateTestFixture() EnsureTemplateInstalled(); } - public string GetTestFixturesPath() => AssemblyFixture.TestFixturesPath; + public static string GetTestFixturesPath() => AssemblyFixture.TestFixturesPath; private static string GetTemplatePackagePath() { @@ -231,7 +231,7 @@ private void EnsureTemplateInstalled() /// /// Uninstalls the template package using dotnet new uninstall. /// - public async Task UninstallTemplateAsync(string workingDirectory) + public static async Task UninstallTemplateAsync(string workingDirectory) { return await RunDotnetNewCommandAsync(workingDirectory, "uninstall JD.Efcpt.Build.Templates"); } @@ -242,7 +242,7 @@ private void EnsureTemplateInstalled() /// Directory to create the project in /// Name of the project to create /// Optional target framework (net8.0, net9.0, or net10.0). Defaults to net8.0 if not specified. - public async Task CreateProjectFromTemplateAsync( + public static async Task CreateProjectFromTemplateAsync( string workingDirectory, string projectName, string? framework = null) diff --git a/tests/JD.Efcpt.Sdk.IntegrationTests/TemplateTests.cs b/tests/JD.Efcpt.Sdk.IntegrationTests/TemplateTests.cs index 0285ff4..654a83f 100644 --- a/tests/JD.Efcpt.Sdk.IntegrationTests/TemplateTests.cs +++ b/tests/JD.Efcpt.Sdk.IntegrationTests/TemplateTests.cs @@ -8,7 +8,7 @@ namespace JD.Efcpt.Sdk.IntegrationTests; /// Tests validate that the template creates projects with the expected structure and that they build correctly. /// [Collection("Template Tests")] -public class TemplateTests : IDisposable +public partial class TemplateTests : IDisposable { private readonly TemplateTestFixture _fixture; private readonly string _testDirectory; @@ -51,7 +51,7 @@ public async Task Template_CreatesProjectWithCorrectStructure() var projectName = "TestEfcptProject"; // Act - var createResult = await _fixture.CreateProjectFromTemplateAsync(_testDirectory, projectName); + var createResult = await TemplateTestFixture.CreateProjectFromTemplateAsync(_testDirectory, projectName); // Assert createResult.Success.Should().BeTrue($"Project creation should succeed.\n{createResult}"); @@ -70,7 +70,7 @@ public async Task Template_CreatesProjectUsingSdkApproach() { // Arrange - template is already installed by fixture var projectName = "TestSdkProject"; - await _fixture.CreateProjectFromTemplateAsync(_testDirectory, projectName); + await TemplateTestFixture.CreateProjectFromTemplateAsync(_testDirectory, projectName); // Act var projectFile = Path.Combine(_testDirectory, projectName, $"{projectName}.csproj"); @@ -90,7 +90,7 @@ public async Task Template_ConfigFileContainsCorrectProjectName() { // Arrange - template is already installed by fixture var projectName = "MyCustomProject"; - await _fixture.CreateProjectFromTemplateAsync(_testDirectory, projectName); + await TemplateTestFixture.CreateProjectFromTemplateAsync(_testDirectory, projectName); // Act var configFile = Path.Combine(_testDirectory, projectName, "efcpt-config.json"); @@ -108,10 +108,10 @@ public async Task Template_CreatedProjectBuildsSuccessfully() { // Arrange - template is already installed by fixture var projectName = "BuildableProject"; - await _fixture.CreateProjectFromTemplateAsync(_testDirectory, projectName); + await TemplateTestFixture.CreateProjectFromTemplateAsync(_testDirectory, projectName); // Copy database project to test directory - var dbProjectSource = Path.Combine(_fixture.GetTestFixturesPath(), "DatabaseProject"); + var dbProjectSource = Path.Combine(TemplateTestFixture.GetTestFixturesPath(), "DatabaseProject"); var dbProjectDest = Path.Combine(_testDirectory, "DatabaseProject"); CopyDirectory(dbProjectSource, dbProjectDest); @@ -140,7 +140,7 @@ public async Task Template_CreatedProjectBuildsSuccessfully() - + "; @@ -149,7 +149,7 @@ public async Task Template_CreatedProjectBuildsSuccessfully() // Create global.json var globalJson = $@"{{ ""msbuild-sdks"": {{ - ""JD.Efcpt.Sdk"": ""{_fixture.SdkVersion}"" + ""JD.Efcpt.Sdk"": ""{TemplateTestFixture.SdkVersion}"" }} }}"; await File.WriteAllTextAsync(Path.Combine(_testDirectory, "global.json"), globalJson); @@ -177,7 +177,7 @@ public async Task Template_ReadmeContainsSdkInformation() { // Arrange - template is already installed by fixture var projectName = "ReadmeTestProject"; - await _fixture.CreateProjectFromTemplateAsync(_testDirectory, projectName); + await TemplateTestFixture.CreateProjectFromTemplateAsync(_testDirectory, projectName); // Act var readmePath = Path.Combine(_testDirectory, projectName, "README.md"); @@ -197,7 +197,7 @@ public async Task Template_UninstallsSuccessfully() await _fixture.InstallTemplateAsync(_testDirectory); // Act - var result = await _fixture.UninstallTemplateAsync(_testDirectory); + var result = await TemplateTestFixture.UninstallTemplateAsync(_testDirectory); // Assert result.Success.Should().BeTrue($"Template uninstallation should succeed.\n{result}"); @@ -219,7 +219,7 @@ public async Task Template_CreatesProjectWithCorrectTargetFramework(string frame var projectName = $"TestFramework_{framework.Replace(".", "")}"; // Act - var createResult = await _fixture.CreateProjectFromTemplateAsync(_testDirectory, projectName, framework); + var createResult = await TemplateTestFixture.CreateProjectFromTemplateAsync(_testDirectory, projectName, framework); createResult.Success.Should().BeTrue($"Project creation for {framework} should succeed.\n{createResult}"); var projectFile = Path.Combine(_testDirectory, projectName, $"{projectName}.csproj"); @@ -240,7 +240,7 @@ public async Task Template_HasCorrectEFCoreVersion(string framework, string expe var projectName = $"TestEFCore_{framework.Replace(".", "")}"; // Act - var createResult = await _fixture.CreateProjectFromTemplateAsync(_testDirectory, projectName, framework); + var createResult = await TemplateTestFixture.CreateProjectFromTemplateAsync(_testDirectory, projectName, framework); createResult.Success.Should().BeTrue($"Project creation for {framework} should succeed.\n{createResult}"); var projectFile = Path.Combine(_testDirectory, projectName, $"{projectName}.csproj"); @@ -260,11 +260,11 @@ public async Task Template_FrameworkVariant_BuildsSuccessfully(string framework, { // Arrange var projectName = $"BuildTest_{framework.Replace(".", "")}"; - var createResult = await _fixture.CreateProjectFromTemplateAsync(_testDirectory, projectName, framework); + var createResult = await TemplateTestFixture.CreateProjectFromTemplateAsync(_testDirectory, projectName, framework); createResult.Success.Should().BeTrue($"Project creation for {framework} should succeed.\n{createResult}"); // Copy database project to test directory - var dbProjectSource = Path.Combine(_fixture.GetTestFixturesPath(), "DatabaseProject"); + var dbProjectSource = Path.Combine(TemplateTestFixture.GetTestFixturesPath(), "DatabaseProject"); var dbProjectDest = Path.Combine(_testDirectory, "DatabaseProject"); if (!Directory.Exists(dbProjectDest)) { @@ -276,10 +276,7 @@ public async Task Template_FrameworkVariant_BuildsSuccessfully(string framework, var projectContent = await File.ReadAllTextAsync(projectFile); // Replace floating version with specific version - projectContent = System.Text.RegularExpressions.Regex.Replace( - projectContent, - @"Version=""[0-9]+\.\*""", - $@"Version=""{efCoreVersion}"""); + projectContent = MyRegex().Replace(projectContent, $@"Version=""{efCoreVersion}"""); // Add ProjectReference to database project var projectReferenceBlock = @" @@ -299,7 +296,7 @@ public async Task Template_FrameworkVariant_BuildsSuccessfully(string framework, - + "; @@ -312,7 +309,7 @@ public async Task Template_FrameworkVariant_BuildsSuccessfully(string framework, // Create global.json var globalJson = $@"{{ ""msbuild-sdks"": {{ - ""JD.Efcpt.Sdk"": ""{_fixture.SdkVersion}"" + ""JD.Efcpt.Sdk"": ""{TemplateTestFixture.SdkVersion}"" }} }}"; var globalJsonPath = Path.Combine(_testDirectory, "global.json"); @@ -357,7 +354,7 @@ public async Task Template_FrameworkVariant_UsesJDEfcptSdk(string framework) var projectName = $"SdkCheck_{framework.Replace(".", "")}"; // Act - var createResult = await _fixture.CreateProjectFromTemplateAsync(_testDirectory, projectName, framework); + var createResult = await TemplateTestFixture.CreateProjectFromTemplateAsync(_testDirectory, projectName, framework); createResult.Success.Should().BeTrue($"Project creation for {framework} should succeed.\n{createResult}"); var projectFile = Path.Combine(_testDirectory, projectName, $"{projectName}.csproj"); @@ -380,7 +377,7 @@ public async Task Template_FrameworkVariant_HasConfigFile(string framework) var projectName = $"ConfigCheck_{framework.Replace(".", "")}"; // Act - var createResult = await _fixture.CreateProjectFromTemplateAsync(_testDirectory, projectName, framework); + var createResult = await TemplateTestFixture.CreateProjectFromTemplateAsync(_testDirectory, projectName, framework); createResult.Success.Should().BeTrue($"Project creation for {framework} should succeed.\n{createResult}"); var configFile = Path.Combine(_testDirectory, projectName, "efcpt-config.json"); @@ -487,4 +484,7 @@ private static async Task CreateToolManifestAndRestoreAsync(string testDirectory process.ExitCode ); } + + [System.Text.RegularExpressions.GeneratedRegex(@"Version=""[0-9]+\.\*""")] + private static partial System.Text.RegularExpressions.Regex MyRegex(); } diff --git a/tests/JD.Efcpt.Sdk.IntegrationTests/TestProjectBuilder.cs b/tests/JD.Efcpt.Sdk.IntegrationTests/TestProjectBuilder.cs index e261d26..37f2f7c 100644 --- a/tests/JD.Efcpt.Sdk.IntegrationTests/TestProjectBuilder.cs +++ b/tests/JD.Efcpt.Sdk.IntegrationTests/TestProjectBuilder.cs @@ -20,10 +20,10 @@ public class TestProjectBuilder : IDisposable public TestProjectBuilder(SdkPackageTestFixture fixture) { - _packageSource = fixture.PackageOutputPath; - _sdkVersion = fixture.SdkVersion; - _buildVersion = fixture.BuildVersion; - _sharedDatabaseProjectPath = fixture.SharedDatabaseProjectPath; + _packageSource = SdkPackageTestFixture.PackageOutputPath; + _sdkVersion = SdkPackageTestFixture.SdkVersion; + _buildVersion = SdkPackageTestFixture.BuildVersion; + _sharedDatabaseProjectPath = SdkPackageTestFixture.SharedDatabaseProjectPath; _testDirectory = Path.Combine(Path.GetTempPath(), "SdkTests", Guid.NewGuid().ToString("N")); Directory.CreateDirectory(_testDirectory); } @@ -139,7 +139,7 @@ public void CreateBuildPackageProject(string projectName, string targetFramework /// This method is kept for backwards compatibility but does nothing. /// The database project is set up once by AssemblyFixture and referenced via absolute path. /// - public void CopyDatabaseProject(string fixturesPath) + public static void CopyDatabaseProject(string fixturesPath) { // No-op: The database project is now shared across all tests. } @@ -175,6 +175,7 @@ public void CreateSqlProject(string projectName, string targetFramework, string {targetFramework} Sql160 + true {connectionString} true @@ -294,7 +295,7 @@ public async Task BuildWithMSBuildExeAsync(string? additionalArgs = return null; } - private async Task RunProcessAsync(string fileName, string args, string workingDirectory, int timeoutMs = 300000) + private static async Task RunProcessAsync(string fileName, string args, string workingDirectory, int timeoutMs = 300000) { var psi = new ProcessStartInfo { @@ -401,7 +402,7 @@ public string ReadGeneratedFile(string relativePath) return File.ReadAllText(Path.Combine(GeneratedDirectory, relativePath)); } - private async Task RunDotnetAsync(string args, string workingDirectory, int timeoutMs = 300000) + private static async Task RunDotnetAsync(string args, string workingDirectory, int timeoutMs = 300000) { var psi = new ProcessStartInfo { diff --git a/tests/JD.Efcpt.Sdk.IntegrationTests/packages.lock.json b/tests/JD.Efcpt.Sdk.IntegrationTests/packages.lock.json new file mode 100644 index 0000000..7fac831 --- /dev/null +++ b/tests/JD.Efcpt.Sdk.IntegrationTests/packages.lock.json @@ -0,0 +1,391 @@ +{ + "version": 1, + "dependencies": { + "net10.0": { + "coverlet.collector": { + "type": "Direct", + "requested": "[6.0.4, )", + "resolved": "6.0.4", + "contentHash": "lkhqpF8Pu2Y7IiN7OntbsTtdbpR1syMsm2F3IgX6ootA4ffRqWL5jF7XipHuZQTdVuWG/gVAAcf8mjk8Tz0xPg==" + }, + "FluentAssertions": { + "type": "Direct", + "requested": "[8.0.1, )", + "resolved": "8.0.1", + "contentHash": "IW5CdXiD4BIijMkJsEajhkQr7HSgzoxZBHp77b4tm8isCKGaDH2AGugW6DLS0/EPhO/MCZ2JOGg6ObdlKISJMg==" + }, + "Microsoft.Data.SqlClient": { + "type": "Direct", + "requested": "[6.0.0, )", + "resolved": "6.0.0", + "contentHash": "r/ttLk2Uh+PVFXpZCRptpPZWoUzEkP6LWaQB1b1SaS9oMdtizYbkNGtBqeqtSnJZLEJDOWyXQFKNpEbJd8avpg==", + "dependencies": { + "Azure.Identity": "1.11.4", + "Microsoft.Bcl.Cryptography": "9.0.0", + "Microsoft.Data.SqlClient.SNI.runtime": "6.0.1", + "Microsoft.Extensions.Caching.Memory": "9.0.0", + "Microsoft.IdentityModel.JsonWebTokens": "7.5.0", + "Microsoft.IdentityModel.Protocols.OpenIdConnect": "7.5.0", + "Microsoft.SqlServer.Server": "1.0.0", + "System.Configuration.ConfigurationManager": "9.0.0", + "System.Security.Cryptography.Pkcs": "9.0.0" + } + }, + "Microsoft.NET.Test.Sdk": { + "type": "Direct", + "requested": "[18.0.1, )", + "resolved": "18.0.1", + "contentHash": "WNpu6vI2rA0pXY4r7NKxCN16XRWl5uHu6qjuyVLoDo6oYEggIQefrMjkRuibQHm/NslIUNCcKftvoWAN80MSAg==", + "dependencies": { + "Microsoft.CodeCoverage": "18.0.1", + "Microsoft.TestPlatform.TestHost": "18.0.1" + } + }, + "Testcontainers.MsSql": { + "type": "Direct", + "requested": "[4.4.0, )", + "resolved": "4.4.0", + "contentHash": "Ghh7rK17G7Lf6fhmfnen2Jo3X6x3xrXaiakeR4KkR1bHFACeYSlbBvQhuAz1Vx+aVkcCzoLpbxexVwqnQocvcw==", + "dependencies": { + "Testcontainers": "4.4.0" + } + }, + "xunit": { + "type": "Direct", + "requested": "[2.9.3, )", + "resolved": "2.9.3", + "contentHash": "TlXQBinK35LpOPKHAqbLY4xlEen9TBafjs0V5KnA4wZsoQLQJiirCR4CbIXvOH8NzkW4YeJKP5P/Bnrodm0h9Q==", + "dependencies": { + "xunit.analyzers": "1.18.0", + "xunit.assert": "2.9.3", + "xunit.core": "[2.9.3]" + } + }, + "xunit.runner.visualstudio": { + "type": "Direct", + "requested": "[3.1.5, )", + "resolved": "3.1.5", + "contentHash": "tKi7dSTwP4m5m9eXPM2Ime4Kn7xNf4x4zT9sdLO/G4hZVnQCRiMTWoSZqI/pYTVeI27oPPqHBKYI/DjJ9GsYgA==" + }, + "Xunit.SkippableFact": { + "type": "Direct", + "requested": "[1.5.23, )", + "resolved": "1.5.23", + "contentHash": "JlKobLTlsGcuJ8OtoodxL63bUagHSVBnF+oQ2GgnkwNqK+XYjeYyhQasULi5Ebx1MNDGNbOMplQYr89mR+nItQ==", + "dependencies": { + "Validation": "2.5.51", + "xunit.extensibility.execution": "2.4.0" + } + }, + "Azure.Core": { + "type": "Transitive", + "resolved": "1.38.0", + "contentHash": "IuEgCoVA0ef7E4pQtpC3+TkPbzaoQfa77HlfJDmfuaJUCVJmn7fT0izamZiryW5sYUFKizsftIxMkXKbgIcPMQ==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "1.1.1", + "System.ClientModel": "1.0.0", + "System.Memory.Data": "1.0.2" + } + }, + "Azure.Identity": { + "type": "Transitive", + "resolved": "1.11.4", + "contentHash": "Sf4BoE6Q3jTgFkgBkx7qztYOFELBCo+wQgpYDwal/qJ1unBH73ywPztIJKXBXORRzAeNijsuxhk94h0TIMvfYg==", + "dependencies": { + "Azure.Core": "1.38.0", + "Microsoft.Identity.Client": "4.61.3", + "Microsoft.Identity.Client.Extensions.Msal": "4.61.3", + "System.Security.Cryptography.ProtectedData": "4.7.0" + } + }, + "BouncyCastle.Cryptography": { + "type": "Transitive", + "resolved": "2.4.0", + "contentHash": "SwXsAV3sMvAU/Nn31pbjhWurYSjJ+/giI/0n6tCrYoupEK34iIHCuk3STAd9fx8yudM85KkLSVdn951vTng/vQ==" + }, + "Docker.DotNet.Enhanced": { + "type": "Transitive", + "resolved": "3.126.1", + "contentHash": "UPyLBLBaVE3s7OCWM0h5g9w6mUOag5sOIP5CldFQekIWo/gHixgZR+o5fG7eCFH4ZdKlvBGM4ALFuOyPoKoJ3A==" + }, + "Docker.DotNet.Enhanced.X509": { + "type": "Transitive", + "resolved": "3.126.1", + "contentHash": "XFHMC/iWHbloQgg9apZrxu010DmSamaAggu8nomCqTeotGyUGkv2Tt/aqk1ljC/4tjtTrb9LtFQwYpwZbMbiKg==", + "dependencies": { + "Docker.DotNet.Enhanced": "3.126.1" + } + }, + "Microsoft.Bcl.AsyncInterfaces": { + "type": "Transitive", + "resolved": "1.1.1", + "contentHash": "yuvf07qFWFqtK3P/MRkEKLhn5r2UbSpVueRziSqj0yJQIKFwG1pq9mOayK3zE5qZCTs0CbrwL9M6R8VwqyGy2w==" + }, + "Microsoft.Bcl.Cryptography": { + "type": "Transitive", + "resolved": "9.0.0", + "contentHash": "tjfuEv+QOznFL1bEPa7svmjpbNvDIrwdinMNy/HhrToQQpONW4hdp0Sans55Rcy9KB3z60duBeey89JY1VQOvg==" + }, + "Microsoft.CodeCoverage": { + "type": "Transitive", + "resolved": "18.0.1", + "contentHash": "O+utSr97NAJowIQT/OVp3Lh9QgW/wALVTP4RG1m2AfFP4IyJmJz0ZBmFJUsRQiAPgq6IRC0t8AAzsiPIsaUDEA==" + }, + "Microsoft.Data.SqlClient.SNI.runtime": { + "type": "Transitive", + "resolved": "6.0.1", + "contentHash": "M0kapuDf0brMsH9gkESGtBorrscL61DLg4ADgAQ/izUg0r/WCzCB7XSuPu+A/d109nF7ogizarHzELhw8GdoXw==" + }, + "Microsoft.Extensions.Caching.Abstractions": { + "type": "Transitive", + "resolved": "9.0.0", + "contentHash": "FPWZAa9c0H4dvOj351iR1jkUIs4u9ykL4Bm592yhjDyO5lCoWd+TMAHx2EMbarzUvCvgjWjJIoC6//Q9kH6YhA==", + "dependencies": { + "Microsoft.Extensions.Primitives": "9.0.0" + } + }, + "Microsoft.Extensions.Caching.Memory": { + "type": "Transitive", + "resolved": "9.0.0", + "contentHash": "zbnPX/JQ0pETRSUG9fNPBvpIq42Aufvs15gGYyNIMhCun9yhmWihz0WgsI7bSDPjxWTKBf8oX/zv6v2uZ3W9OQ==", + "dependencies": { + "Microsoft.Extensions.Caching.Abstractions": "9.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.0", + "Microsoft.Extensions.Logging.Abstractions": "9.0.0", + "Microsoft.Extensions.Options": "9.0.0", + "Microsoft.Extensions.Primitives": "9.0.0" + } + }, + "Microsoft.Extensions.DependencyInjection.Abstractions": { + "type": "Transitive", + "resolved": "9.0.0", + "contentHash": "+6f2qv2a3dLwd5w6JanPIPs47CxRbnk+ZocMJUhv9NxP88VlOcJYZs9jY+MYSjxvady08bUZn6qgiNh7DadGgg==" + }, + "Microsoft.Extensions.Logging.Abstractions": { + "type": "Transitive", + "resolved": "9.0.0", + "contentHash": "g0UfujELzlLbHoVG8kPKVBaW470Ewi+jnptGS9KUi6jcb+k2StujtK3m26DFSGGwQ/+bVgZfsWqNzlP6YOejvw==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.0" + } + }, + "Microsoft.Extensions.Options": { + "type": "Transitive", + "resolved": "9.0.0", + "contentHash": "y2146b3jrPI3Q0lokKXdKLpmXqakYbDIPDV6r3M8SqvSf45WwOTzkyfDpxnZXJsJQEpAsAqjUq5Pu8RCJMjubg==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.0", + "Microsoft.Extensions.Primitives": "9.0.0" + } + }, + "Microsoft.Extensions.Primitives": { + "type": "Transitive", + "resolved": "9.0.0", + "contentHash": "N3qEBzmLMYiASUlKxxFIISP4AiwuPTHF5uCh+2CWSwwzAJiIYx0kBJsS30cp1nvhSySFAVi30jecD307jV+8Kg==" + }, + "Microsoft.Identity.Client": { + "type": "Transitive", + "resolved": "4.61.3", + "contentHash": "naJo/Qm35Caaoxp5utcw+R8eU8ZtLz2ALh8S+gkekOYQ1oazfCQMWVT4NJ/FnHzdIJlm8dMz0oMpMGCabx5odA==", + "dependencies": { + "Microsoft.IdentityModel.Abstractions": "6.35.0" + } + }, + "Microsoft.Identity.Client.Extensions.Msal": { + "type": "Transitive", + "resolved": "4.61.3", + "contentHash": "PWnJcznrSGr25MN8ajlc2XIDW4zCFu0U6FkpaNLEWLgd1NgFCp5uDY3mqLDgM8zCN8hqj8yo5wHYfLB2HjcdGw==", + "dependencies": { + "Microsoft.Identity.Client": "4.61.3", + "System.Security.Cryptography.ProtectedData": "4.5.0" + } + }, + "Microsoft.IdentityModel.Abstractions": { + "type": "Transitive", + "resolved": "7.5.0", + "contentHash": "seOFPaBQh2K683eFujAuDsrO2XbOA+SvxRli+wu7kl+ZymuGQzjmmUKfyFHmDazpPOBnmOX1ZnjX7zFDZHyNIA==" + }, + "Microsoft.IdentityModel.JsonWebTokens": { + "type": "Transitive", + "resolved": "7.5.0", + "contentHash": "mfyiGptbcH+oYrzAtWWwuV+7MoM0G0si+9owaj6DGWInhq/N/KDj/pWHhq1ShdmBu332gjP+cppjgwBpsOj7Fg==", + "dependencies": { + "Microsoft.IdentityModel.Tokens": "7.5.0" + } + }, + "Microsoft.IdentityModel.Logging": { + "type": "Transitive", + "resolved": "7.5.0", + "contentHash": "3BInZEajJvnTDP/YRrmJ3Fyw8XAWWR9jG+3FkhhzRJJYItVL+BEH9qlgxSmtrxp7S7N6TOv+Y+X8BG61viiehQ==", + "dependencies": { + "Microsoft.IdentityModel.Abstractions": "7.5.0" + } + }, + "Microsoft.IdentityModel.Protocols": { + "type": "Transitive", + "resolved": "7.5.0", + "contentHash": "ugyb0Nm+I+UrHGYg28mL8oCV31xZrOEbs8fQkcShUoKvgk22HroD2odCnqEf56CoAFYTwoDExz8deXzrFC+TyA==", + "dependencies": { + "Microsoft.IdentityModel.Tokens": "7.5.0" + } + }, + "Microsoft.IdentityModel.Protocols.OpenIdConnect": { + "type": "Transitive", + "resolved": "7.5.0", + "contentHash": "/U3I/8uutTqZr2n/zt0q08bluYklq+5VWP7ZuOGpTUR1ln5bSbrexAzdSGzrhxTxNNbHMCU8Mn2bNQvcmehAxg==", + "dependencies": { + "Microsoft.IdentityModel.Protocols": "7.5.0", + "System.IdentityModel.Tokens.Jwt": "7.5.0" + } + }, + "Microsoft.IdentityModel.Tokens": { + "type": "Transitive", + "resolved": "7.5.0", + "contentHash": "owe33wqe0ZbwBxM3D90I0XotxNyTdl85jud03d+OrUOJNnTiqnYePwBk3WU9yW0Rk5CYX+sfSim7frmu6jeEzQ==", + "dependencies": { + "Microsoft.IdentityModel.Logging": "7.5.0" + } + }, + "Microsoft.SqlServer.Server": { + "type": "Transitive", + "resolved": "1.0.0", + "contentHash": "N4KeF3cpcm1PUHym1RmakkzfkEv3GRMyofVv40uXsQhCQeglr2OHNcUk2WOG51AKpGO8ynGpo9M/kFXSzghwug==" + }, + "Microsoft.TestPlatform.ObjectModel": { + "type": "Transitive", + "resolved": "18.0.1", + "contentHash": "qT/mwMcLF9BieRkzOBPL2qCopl8hQu6A1P7JWAoj/FMu5i9vds/7cjbJ/LLtaiwWevWLAeD5v5wjQJ/l6jvhWQ==" + }, + "Microsoft.TestPlatform.TestHost": { + "type": "Transitive", + "resolved": "18.0.1", + "contentHash": "uDJKAEjFTaa2wHdWlfo6ektyoh+WD4/Eesrwb4FpBFKsLGehhACVnwwTI4qD3FrIlIEPlxdXg3SyrYRIcO+RRQ==", + "dependencies": { + "Microsoft.TestPlatform.ObjectModel": "18.0.1", + "Newtonsoft.Json": "13.0.3" + } + }, + "Newtonsoft.Json": { + "type": "Transitive", + "resolved": "13.0.3", + "contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==" + }, + "SharpZipLib": { + "type": "Transitive", + "resolved": "1.4.2", + "contentHash": "yjj+3zgz8zgXpiiC3ZdF/iyTBbz2fFvMxZFEBPUcwZjIvXOf37Ylm+K58hqMfIBt5JgU/Z2uoUS67JmTLe973A==" + }, + "SSH.NET": { + "type": "Transitive", + "resolved": "2024.2.0", + "contentHash": "9r+4UF2P51lTztpd+H7SJywk7WgmlWB//Cm2o96c6uGVZU5r58ys2/cD9pCgTk0zCdSkfflWL1WtqQ9I4IVO9Q==", + "dependencies": { + "BouncyCastle.Cryptography": "2.4.0" + } + }, + "System.ClientModel": { + "type": "Transitive", + "resolved": "1.0.0", + "contentHash": "I3CVkvxeqFYjIVEP59DnjbeoGNfo/+SZrCLpRz2v/g0gpCHaEMPtWSY0s9k/7jR1rAsLNg2z2u1JRB76tPjnIw==", + "dependencies": { + "System.Memory.Data": "1.0.2" + } + }, + "System.Configuration.ConfigurationManager": { + "type": "Transitive", + "resolved": "9.0.0", + "contentHash": "PdkuMrwDhXoKFo/JxISIi9E8L+QGn9Iquj2OKDWHB6Y/HnUOuBouF7uS3R4Hw3FoNmwwMo6hWgazQdyHIIs27A==", + "dependencies": { + "System.Diagnostics.EventLog": "9.0.0", + "System.Security.Cryptography.ProtectedData": "9.0.0" + } + }, + "System.Diagnostics.EventLog": { + "type": "Transitive", + "resolved": "9.0.0", + "contentHash": "qd01+AqPhbAG14KtdtIqFk+cxHQFZ/oqRSCoxU1F+Q6Kv0cl726sl7RzU9yLFGd4BUOKdN4XojXF0pQf/R6YeA==" + }, + "System.IdentityModel.Tokens.Jwt": { + "type": "Transitive", + "resolved": "7.5.0", + "contentHash": "D0TtrWOfoPdyYSlvOGaU9F1QR+qrbgJ/4eiEsQkIz7YQKIKkGXQldXukn6cYG9OahSq5UVMvyAIObECpH6Wglg==", + "dependencies": { + "Microsoft.IdentityModel.JsonWebTokens": "7.5.0", + "Microsoft.IdentityModel.Tokens": "7.5.0" + } + }, + "System.Memory.Data": { + "type": "Transitive", + "resolved": "1.0.2", + "contentHash": "JGkzeqgBsiZwKJZ1IxPNsDFZDhUvuEdX8L8BDC8N3KOj+6zMcNU28CNN59TpZE/VJYy9cP+5M+sbxtWJx3/xtw==" + }, + "System.Security.Cryptography.Pkcs": { + "type": "Transitive", + "resolved": "9.0.0", + "contentHash": "8tluJF8w9si+2yoHeL8rgVJS6lKvWomTDC8px65Z8MCzzdME5eaPtEQf4OfVGrAxB5fW93ncucy1+221O9EQaw==" + }, + "System.Security.Cryptography.ProtectedData": { + "type": "Transitive", + "resolved": "9.0.0", + "contentHash": "CJW+x/F6fmRQ7N6K8paasTw9PDZp4t7G76UjGNlSDgoHPF0h08vTzLYbLZpOLEJSg35d5wy2jCXGo84EN05DpQ==" + }, + "Testcontainers": { + "type": "Transitive", + "resolved": "4.4.0", + "contentHash": "P4+fXNjMtLW1CRjBQ3SUQWxz98mio+79OL6B+4DmzMaafW1rEVZ/eFHFG9TrxMWeg+cgftkzV7oPcGNZQ12Q9w==", + "dependencies": { + "Docker.DotNet.Enhanced": "3.126.1", + "Docker.DotNet.Enhanced.X509": "3.126.1", + "Microsoft.Extensions.Logging.Abstractions": "8.0.3", + "SSH.NET": "2024.2.0", + "SharpZipLib": "1.4.2" + } + }, + "Validation": { + "type": "Transitive", + "resolved": "2.5.51", + "contentHash": "g/Aug7PVWaenlJ0QUyt/mEetngkQNsMCuNeRVXbcJED1nZS7JcK+GTU4kz3jcQ7bFuKfi8PF4ExXH7XSFNuSLQ==" + }, + "xunit.abstractions": { + "type": "Transitive", + "resolved": "2.0.3", + "contentHash": "pot1I4YOxlWjIb5jmwvvQNbTrZ3lJQ+jUGkGjWE3hEFM0l5gOnBWS+H3qsex68s5cO52g+44vpGzhAt+42vwKg==" + }, + "xunit.analyzers": { + "type": "Transitive", + "resolved": "1.18.0", + "contentHash": "OtFMHN8yqIcYP9wcVIgJrq01AfTxijjAqVDy/WeQVSyrDC1RzBWeQPztL49DN2syXRah8TYnfvk035s7L95EZQ==" + }, + "xunit.assert": { + "type": "Transitive", + "resolved": "2.9.3", + "contentHash": "/Kq28fCE7MjOV42YLVRAJzRF0WmEqsmflm0cfpMjGtzQ2lR5mYVj1/i0Y8uDAOLczkL3/jArrwehfMD0YogMAA==" + }, + "xunit.core": { + "type": "Transitive", + "resolved": "2.9.3", + "contentHash": "BiAEvqGvyme19wE0wTKdADH+NloYqikiU0mcnmiNyXaF9HyHmE6sr/3DC5vnBkgsWaE6yPyWszKSPSApWdRVeQ==", + "dependencies": { + "xunit.extensibility.core": "[2.9.3]", + "xunit.extensibility.execution": "[2.9.3]" + } + }, + "xunit.extensibility.core": { + "type": "Transitive", + "resolved": "2.9.3", + "contentHash": "kf3si0YTn2a8J8eZNb+zFpwfoyvIrQ7ivNk5ZYA5yuYk1bEtMe4DxJ2CF/qsRgmEnDr7MnW1mxylBaHTZ4qErA==", + "dependencies": { + "xunit.abstractions": "2.0.3" + } + }, + "xunit.extensibility.execution": { + "type": "Transitive", + "resolved": "2.9.3", + "contentHash": "yMb6vMESlSrE3Wfj7V6cjQ3S4TXdXpRqYeNEI3zsX31uTsGMJjEw6oD5F5u1cHnMptjhEECnmZSsPxB6ChZHDQ==", + "dependencies": { + "xunit.extensibility.core": "[2.9.3]" + } + } + } + } +} \ No newline at end of file diff --git a/tests/TestAssets/SampleApp/Sample.App.csproj b/tests/TestAssets/SampleApp/Sample.App.csproj index 5110d8c..fa83388 100644 --- a/tests/TestAssets/SampleApp/Sample.App.csproj +++ b/tests/TestAssets/SampleApp/Sample.App.csproj @@ -7,7 +7,7 @@ $(MSBuildThisFileDirectory)..\..\..\src\JD.Efcpt.Build\ - + true @@ -30,12 +30,12 @@ - + diff --git a/tests/TestAssets/SplitOutputs/Sample.Data/Sample.Data.csproj b/tests/TestAssets/SplitOutputs/Sample.Data/Sample.Data.csproj index b91d133..23e7b88 100644 --- a/tests/TestAssets/SplitOutputs/Sample.Data/Sample.Data.csproj +++ b/tests/TestAssets/SplitOutputs/Sample.Data/Sample.Data.csproj @@ -8,7 +8,7 @@ $(MSBuildThisFileDirectory)..\..\..\..\src\JD.Efcpt.Build\ - + true @@ -45,5 +45,5 @@ - + diff --git a/tests/TestAssets/SplitOutputs/Sample.Models/Sample.Models.csproj b/tests/TestAssets/SplitOutputs/Sample.Models/Sample.Models.csproj index 74f6bfc..a06286c 100644 --- a/tests/TestAssets/SplitOutputs/Sample.Models/Sample.Models.csproj +++ b/tests/TestAssets/SplitOutputs/Sample.Models/Sample.Models.csproj @@ -9,7 +9,7 @@ - + @@ -21,5 +21,5 @@ - +