Skip to content

Commit 3cc9bec

Browse files
authored
feat(profiling): Add optional build profiling framework with versioned JSON output (#69)
1 parent 6010cd7 commit 3cc9bec

40 files changed

Lines changed: 4119 additions & 198 deletions

docs/user-guide/build-profiling.md

Lines changed: 409 additions & 0 deletions
Large diffs are not rendered by default.

src/JD.Efcpt.Build.Tasks/AddSqlFileWarnings.cs

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,22 @@ namespace JD.Efcpt.Build.Tasks;
1717
/// </remarks>
1818
public sealed class AddSqlFileWarnings : Task
1919
{
20+
/// <summary>
21+
/// Full path to the MSBuild project file (used for profiling).
22+
/// </summary>
23+
public string ProjectPath { get; set; } = "";
24+
2025
/// <summary>
2126
/// Directory containing SQL script files.
2227
/// </summary>
2328
[Required]
29+
[ProfileInput]
2430
public string ScriptsDirectory { get; set; } = "";
2531

2632
/// <summary>
2733
/// Database name for the warning header.
2834
/// </summary>
35+
[ProfileInput]
2936
public string DatabaseName { get; set; } = "";
3037

3138
/// <summary>
@@ -39,49 +46,42 @@ public sealed class AddSqlFileWarnings : Task
3946
[Output]
4047
public int FilesProcessed { get; set; }
4148

42-
/// <summary>
43-
/// Executes the task.
44-
/// </summary>
49+
/// <inheritdoc />
4550
public override bool Execute()
51+
=> TaskExecutionDecorator.ExecuteWithProfiling(
52+
this, ExecuteCore, ProfilingHelper.GetProfiler(ProjectPath));
53+
54+
private bool ExecuteCore(TaskExecutionContext ctx)
4655
{
47-
var log = new BuildLog(Log, LogVerbosity);
56+
var log = new BuildLog(ctx.Logger, LogVerbosity);
4857

49-
try
58+
log.Info("Adding auto-generation warnings to SQL files...");
59+
60+
if (!Directory.Exists(ScriptsDirectory))
5061
{
51-
log.Info("Adding auto-generation warnings to SQL files...");
62+
log.Warn($"Scripts directory not found: {ScriptsDirectory}");
63+
return true; // Not an error
64+
}
5265

53-
if (!Directory.Exists(ScriptsDirectory))
66+
// Find all SQL files
67+
var sqlFiles = Directory.GetFiles(ScriptsDirectory, "*.sql", SearchOption.AllDirectories);
68+
69+
FilesProcessed = 0;
70+
foreach (var sqlFile in sqlFiles)
71+
{
72+
try
5473
{
55-
log.Warn($"Scripts directory not found: {ScriptsDirectory}");
56-
return true; // Not an error
74+
AddWarningHeader(sqlFile, log);
75+
FilesProcessed++;
5776
}
58-
59-
// Find all SQL files
60-
var sqlFiles = Directory.GetFiles(ScriptsDirectory, "*.sql", SearchOption.AllDirectories);
61-
62-
FilesProcessed = 0;
63-
foreach (var sqlFile in sqlFiles)
77+
catch (Exception ex)
6478
{
65-
try
66-
{
67-
AddWarningHeader(sqlFile, log);
68-
FilesProcessed++;
69-
}
70-
catch (Exception ex)
71-
{
72-
log.Warn($"Failed to process {Path.GetFileName(sqlFile)}: {ex.Message}");
73-
}
79+
log.Warn($"Failed to process {Path.GetFileName(sqlFile)}: {ex.Message}");
7480
}
75-
76-
log.Info($"Processed {FilesProcessed} SQL files");
77-
return true;
78-
}
79-
catch (Exception ex)
80-
{
81-
log.Error("JD0025", $"Failed to add SQL file warnings: {ex.Message}");
82-
log.Detail($"Exception details: {ex}");
83-
return false;
8481
}
82+
83+
log.Info($"Processed {FilesProcessed} SQL files");
84+
return true;
8585
}
8686

8787
/// <summary>

src/JD.Efcpt.Build.Tasks/ApplyConfigOverrides.cs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,22 +31,30 @@ public sealed class ApplyConfigOverrides : Task
3131
{
3232
#region Control Properties
3333

34+
/// <summary>
35+
/// Full path to the MSBuild project file (used for profiling).
36+
/// </summary>
37+
public string ProjectPath { get; set; } = "";
38+
3439
/// <summary>
3540
/// Path to the staged efcpt-config.json file to modify.
3641
/// </summary>
3742
[Required]
43+
[ProfileInput]
3844
public string StagedConfigPath { get; set; } = "";
3945

4046
/// <summary>
4147
/// Whether to apply MSBuild property overrides to user-provided config files.
4248
/// </summary>
4349
/// <value>Default is "true". Set to "false" to skip overrides for user-provided configs.</value>
50+
[ProfileInput]
4451
public string ApplyOverrides { get; set; } = "true";
4552

4653
/// <summary>
4754
/// Indicates whether the config file is the library default (not user-provided).
4855
/// </summary>
4956
/// <value>When "true", overrides are always applied regardless of <see cref="ApplyOverrides"/>.</value>
57+
[ProfileInput]
5058
public string IsUsingDefaultConfig { get; set; } = "false";
5159

5260
/// <summary>
@@ -189,11 +197,8 @@ public sealed class ApplyConfigOverrides : Task
189197

190198
/// <inheritdoc />
191199
public override bool Execute()
192-
{
193-
var decorator = TaskExecutionDecorator.Create(ExecuteCore);
194-
var ctx = new TaskExecutionContext(Log, nameof(ApplyConfigOverrides));
195-
return decorator.Execute(in ctx);
196-
}
200+
=> TaskExecutionDecorator.ExecuteWithProfiling(
201+
this, ExecuteCore, ProfilingHelper.GetProfiler(ProjectPath));
197202

198203
private bool ExecuteCore(TaskExecutionContext ctx)
199204
{

src/JD.Efcpt.Build.Tasks/CheckSdkVersion.cs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
using System.Net.Http;
22
using System.Text.Json;
3+
using JD.Efcpt.Build.Tasks.Decorators;
34
using Microsoft.Build.Framework;
5+
using Task = Microsoft.Build.Utilities.Task;
46

57
namespace JD.Efcpt.Build.Tasks;
68

@@ -18,22 +20,29 @@ namespace JD.Efcpt.Build.Tasks;
1820
/// - Cache duration: 24 hours (configurable via CacheHours)
1921
/// </para>
2022
/// </remarks>
21-
public class CheckSdkVersion : Microsoft.Build.Utilities.Task
23+
public class CheckSdkVersion : Task
2224
{
2325
private static readonly HttpClient HttpClient = new()
2426
{
2527
Timeout = TimeSpan.FromSeconds(5)
2628
};
2729

30+
/// <summary>
31+
/// Full path to the MSBuild project file (used for profiling).
32+
/// </summary>
33+
public string ProjectPath { get; set; } = "";
34+
2835
/// <summary>
2936
/// The current SDK version being used.
3037
/// </summary>
3138
[Required]
39+
[ProfileInput]
3240
public string CurrentVersion { get; set; } = "";
3341

3442
/// <summary>
3543
/// The NuGet package ID to check.
3644
/// </summary>
45+
[ProfileInput]
3746
public string PackageId { get; set; } = "JD.Efcpt.Sdk";
3847

3948
/// <summary>
@@ -66,6 +75,10 @@ public class CheckSdkVersion : Microsoft.Build.Utilities.Task
6675

6776
/// <inheritdoc />
6877
public override bool Execute()
78+
=> TaskExecutionDecorator.ExecuteWithProfiling(
79+
this, ExecuteCore, ProfilingHelper.GetProfiler(ProjectPath));
80+
81+
private bool ExecuteCore(TaskExecutionContext ctx)
6982
{
7083
try
7184
{
@@ -93,7 +106,7 @@ public override bool Execute()
93106
catch (Exception ex)
94107
{
95108
// Don't fail the build for version check issues - just log and continue
96-
Log.LogMessage(MessageImportance.Low,
109+
ctx.Logger.LogMessage(MessageImportance.Low,
97110
$"EFCPT: Unable to check for SDK updates: {ex.Message}");
98111
return true;
99112
}

src/JD.Efcpt.Build.Tasks/ComputeFingerprint.cs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,37 +39,48 @@ namespace JD.Efcpt.Build.Tasks;
3939
/// </remarks>
4040
public sealed class ComputeFingerprint : Task
4141
{
42+
/// <summary>
43+
/// Full path to the MSBuild project file (used for profiling).
44+
/// </summary>
45+
public string ProjectPath { get; set; } = "";
46+
4247
/// <summary>
4348
/// Path to the DACPAC file to include in the fingerprint (used in .sqlproj mode).
4449
/// </summary>
50+
[ProfileInput]
4551
public string DacpacPath { get; set; } = "";
4652

4753
/// <summary>
4854
/// Schema fingerprint from QuerySchemaMetadata (used in connection string mode).
4955
/// </summary>
56+
[ProfileInput]
5057
public string SchemaFingerprint { get; set; } = "";
5158

5259
/// <summary>
5360
/// Indicates whether we're in connection string mode.
5461
/// </summary>
62+
[ProfileInput]
5563
public string UseConnectionStringMode { get; set; } = "false";
5664

5765
/// <summary>
5866
/// Path to the efcpt configuration JSON file to include in the fingerprint.
5967
/// </summary>
6068
[Required]
69+
[ProfileInput]
6170
public string ConfigPath { get; set; } = "";
6271

6372
/// <summary>
6473
/// Path to the efcpt renaming JSON file to include in the fingerprint.
6574
/// </summary>
6675
[Required]
76+
[ProfileInput]
6777
public string RenamingPath { get; set; } = "";
6878

6979
/// <summary>
7080
/// Root directory containing template files to include in the fingerprint.
7181
/// </summary>
7282
[Required]
83+
[ProfileInput]
7384
public string TemplateDir { get; set; } = "";
7485

7586
/// <summary>
@@ -86,21 +97,25 @@ public sealed class ComputeFingerprint : Task
8697
/// <summary>
8798
/// Version of the EF Core Power Tools CLI tool package being used.
8899
/// </summary>
100+
[ProfileInput]
89101
public string ToolVersion { get; set; } = "";
90102

91103
/// <summary>
92104
/// Directory containing generated files to optionally include in the fingerprint.
93105
/// </summary>
106+
[ProfileInput]
94107
public string GeneratedDir { get; set; } = "";
95108

96109
/// <summary>
97110
/// Indicates whether to detect changes to generated files (default: false to avoid overwriting manual edits).
98111
/// </summary>
112+
[ProfileInput]
99113
public string DetectGeneratedFileChanges { get; set; } = "false";
100114

101115
/// <summary>
102116
/// Serialized JSON string containing MSBuild config property overrides.
103117
/// </summary>
118+
[ProfileInput]
104119
public string ConfigPropertyOverrides { get; set; } = "";
105120

106121
/// <summary>
@@ -121,11 +136,8 @@ public sealed class ComputeFingerprint : Task
121136

122137
/// <inheritdoc />
123138
public override bool Execute()
124-
{
125-
var decorator = TaskExecutionDecorator.Create(ExecuteCore);
126-
var ctx = new TaskExecutionContext(Log, nameof(ComputeFingerprint));
127-
return decorator.Execute(in ctx);
128-
}
139+
=> TaskExecutionDecorator.ExecuteWithProfiling(
140+
this, ExecuteCore, ProfilingHelper.GetProfiler(ProjectPath));
129141

130142
private bool ExecuteCore(TaskExecutionContext ctx)
131143
{

0 commit comments

Comments
 (0)