Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ docs/api
docs/_site
coverage.cobertura.xml
pkg/
artifacts/
artifacts/
*.bak
14 changes: 14 additions & 0 deletions src/JD.Efcpt.Build.Tasks/packages.lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,15 @@
"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, )",
Expand Down Expand Up @@ -494,6 +503,11 @@
"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",
Expand Down
126 changes: 126 additions & 0 deletions src/JD.Efcpt.Build.Templates/JD.Efcpt.Build.Templates.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,130 @@
<Compile Remove="**\*" />
</ItemGroup>

<!--
Unified Template Replacement Strategy
=====================================
All template content uses dotnet template engine's symbol system for replacements:

1. Framework: Replaced at template instantiation time via "Framework" parameter symbol
2. EFCoreVersion: Replaced at template instantiation time via "EFCoreVersion" generated symbol
3. SdkVersion: Replaced at template instantiation time via "SdkVersion" parameter symbol

At pack time, we only update the defaultValue for SdkVersion in template.json to match the
package version being built. This ensures users get the correct SDK version by default.

The template csproj file uses SDKVERSION_PLACEHOLDER which gets replaced by the template
engine when users run `dotnet new efcptbuild`, just like net8.0 and 8.0.* placeholders.
-->
<UsingTask TaskName="ReplaceFileContent" TaskFactory="RoslynCodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll">
<ParameterGroup>
<FilePath ParameterType="System.String" Required="true" />
<OldValue ParameterType="System.String" Required="true" />
<NewValue ParameterType="System.String" Required="true" />
<UseRegex ParameterType="System.Boolean" Required="false" />
</ParameterGroup>
<Task>
<Using Namespace="System.IO" />
<Using Namespace="System.Text.RegularExpressions" />
<Code Type="Fragment" Language="cs">
<![CDATA[
var content = File.ReadAllText(FilePath);
string newContent;

if (UseRegex)
{
var regex = new Regex(OldValue);
if (!regex.IsMatch(content))
{
Log.LogWarning($"ReplaceFileContent: Regex pattern '{OldValue}' did not match any content in file '{FilePath}'. No replacement performed.");
return true;
}
newContent = regex.Replace(content, NewValue);
}
else
{
if (!content.Contains(OldValue))
{
Log.LogWarning($"ReplaceFileContent: OldValue '{OldValue}' was not found in file '{FilePath}'. No replacement performed.");
return true;
}
newContent = content.Replace(OldValue, NewValue);
}

File.WriteAllText(FilePath, newContent);
Log.LogMessage(Microsoft.Build.Framework.MessageImportance.High, $"Successfully replaced content in '{FilePath}'");
]]>
</Code>
</Task>
</UsingTask>

<!-- Cleanup target: Ensures any leftover backup files from failed previous packs are restored -->
<Target Name="EnsureTemplateFilesRestored" BeforeTargets="ReplaceTemplateSdkVersion">
<PropertyGroup>
<_TemplateJsonPath>$(MSBuildProjectDirectory)/templates/efcptbuild/.template.config/template.json</_TemplateJsonPath>
<_TemplateJsonBackupPath>$(MSBuildProjectDirectory)/templates/efcptbuild/.template.config/template.json.bak</_TemplateJsonBackupPath>
</PropertyGroup>

<!-- Restore from backup if one exists from a previous failed pack -->
<Move SourceFiles="$(_TemplateJsonBackupPath)" DestinationFiles="$(_TemplateJsonPath)" Condition="Exists('$(_TemplateJsonBackupPath)')" />

<Message Importance="high" Text="Ensured original template.json is restored before replacing SDK version." Condition="Exists('$(_TemplateJsonPath)')" />
</Target>

<Target Name="ReplaceTemplateSdkVersion" BeforeTargets="GenerateNuspec">
<PropertyGroup>
<_TemplateJsonPath>$(MSBuildProjectDirectory)/templates/efcptbuild/.template.config/template.json</_TemplateJsonPath>
<_TemplateJsonBackupPath>$(MSBuildProjectDirectory)/templates/efcptbuild/.template.config/template.json.bak</_TemplateJsonBackupPath>
</PropertyGroup>

<!-- Backup template.json -->
<Copy SourceFiles="$(_TemplateJsonPath)" DestinationFiles="$(_TemplateJsonBackupPath)" />

<!--
Replace the defaultValue in template.json with the actual package version.
The template engine will use this as the default when SdkVersion parameter is not specified.
This unifies all replacements to use the template.json symbol system, just like Framework and EFCoreVersion.

Uses regex to be tolerant of whitespace variations in JSON formatting.
-->
<ReplaceFileContent
FilePath="$(_TemplateJsonPath)"
OldValue="&quot;defaultValue&quot;\s*:\s*&quot;1\.0\.0&quot;"
NewValue="&quot;defaultValue&quot;: &quot;$(PackageVersion)&quot;"
UseRegex="true" />

<Message Importance="high" Text="Replaced SDK version defaultValue with $(PackageVersion) in template.json" />
</Target>

<!-- Restore original template.json after pack -->
<Target Name="RestoreTemplateFiles" AfterTargets="Pack">
<PropertyGroup>
<_TemplateJsonPath>$(MSBuildProjectDirectory)/templates/efcptbuild/.template.config/template.json</_TemplateJsonPath>
<_TemplateJsonBackupPath>$(MSBuildProjectDirectory)/templates/efcptbuild/.template.config/template.json.bak</_TemplateJsonBackupPath>
</PropertyGroup>

<!-- Check if backup exists before attempting restore -->
<Error Text="Cannot restore template.json - backup file was not found at '$(_TemplateJsonBackupPath)'" Condition="!Exists('$(_TemplateJsonBackupPath)')" />

<!-- Restore from backup -->
<Move SourceFiles="$(_TemplateJsonBackupPath)" DestinationFiles="$(_TemplateJsonPath)" Condition="Exists('$(_TemplateJsonBackupPath)')" />

<!-- Verify restoration succeeded -->
<Error Text="Failed to restore template.json - restored file was not found at '$(_TemplateJsonPath)'" Condition="!Exists('$(_TemplateJsonPath)')" />

<Message Importance="high" Text="Restored original template.json from backup" />
</Target>

Comment thread
JerrettDavis marked this conversation as resolved.
<!-- Ensure any leftover backup from a previous failed pack is restored before modifying template.json again -->
<Target Name="EnsureTemplateFilesRestored" BeforeTargets="ReplaceTemplateSdkVersion">
<PropertyGroup>
<_TemplateJsonPath>$(MSBuildProjectDirectory)/templates/efcptbuild/.template.config/template.json</_TemplateJsonPath>
<_TemplateJsonBackupPath>$(MSBuildProjectDirectory)/templates/efcptbuild/.template.config/template.json.bak</_TemplateJsonBackupPath>
</PropertyGroup>

<!-- If a backup exists, restore it to ensure a clean state from any previous failed or interrupted pack -->
<Move SourceFiles="$(_TemplateJsonBackupPath)" DestinationFiles="$(_TemplateJsonPath)" Condition="Exists('$(_TemplateJsonBackupPath)')" />

<Message Importance="high" Text="Ensured original template.json is restored before replacing SDK version." Condition="Exists('$(_TemplateJsonPath)')" />
</Target>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,12 @@
"IsNet8OrNet9": {
"type": "computed",
"value": "(Framework == \"net8.0\" || Framework == \"net9.0\")"
},
"SdkVersion": {
"type": "parameter",
"datatype": "string",
"replaces": "SDKVERSION_PLACEHOLDER",
"defaultValue": "1.0.0"
}
},
"primaryOutputs": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

No JD.Efcpt.Build PackageReference needed - the SDK handles everything!
-->
<Project Sdk="JD.Efcpt.Sdk">
<Project Sdk="JD.Efcpt.Sdk/SDKVERSION_PLACEHOLDER">
Comment thread
JerrettDavis marked this conversation as resolved.
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
Expand Down
8 changes: 4 additions & 4 deletions tests/JD.Efcpt.Sdk.IntegrationTests/TemplateTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ public async Task Template_CreatesProjectUsingSdkApproach()
var projectContent = await File.ReadAllTextAsync(projectFile);

// Assert
projectContent.Should().Contain("<Project Sdk=\"JD.Efcpt.Sdk\">",
"Project should use JD.Efcpt.Sdk");
projectContent.Should().Match("*<Project Sdk=\"JD.Efcpt.Sdk/*\">*",
"Project should use JD.Efcpt.Sdk with version");
projectContent.Should().NotMatch("*<PackageReference*Include=\"JD.Efcpt.Build\"*",
"Project should not reference JD.Efcpt.Build package directly");
projectContent.Should().Contain("Microsoft.EntityFrameworkCore",
Expand Down Expand Up @@ -364,8 +364,8 @@ public async Task Template_FrameworkVariant_UsesJDEfcptSdk(string framework)
var projectContent = await File.ReadAllTextAsync(projectFile);

// Assert
projectContent.Should().Contain("<Project Sdk=\"JD.Efcpt.Sdk\">",
$"{framework} project should use JD.Efcpt.Sdk");
projectContent.Should().Match("*<Project Sdk=\"JD.Efcpt.Sdk/*\">*",
$"{framework} project should use JD.Efcpt.Sdk with version");
projectContent.Should().NotContain("PackageReference Include=\"JD.Efcpt.Build\"",
$"{framework} project should not have JD.Efcpt.Build package reference");
}
Expand Down
Loading