Skip to content

Commit 45ec305

Browse files
sharpninjaclaude
andcommitted
Add requirements workspace assignment + fix director/desktop build
Adds AssignFunctional/Technical/TestingRequirementToWorkspace commands with handlers, API client methods, and FR/TR detail viewmodels wiring. Director RequirementsScreen gains workspace picker dialog for assigning requirements via WorkspaceListViewModel. Build fixes: restore RequirementsHandlers.cs + MainScreen.cs that were truncated in prior WIP; unescape quotes in RequirementsApiClientAdapter xml doc and RequirementsScreen mapping formatter; wrap SetSource in ObservableCollection and replace Button.OnAccept() with shared Confirm local. Desktop MainWindow.axaml ToggleButton replaces WPF-style Checked/Unchecked events with Avalonia IsCheckedChanged. Nuke build targets and schema updated for the new deploy workflow. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent c109af5 commit 45ec305

18 files changed

Lines changed: 649 additions & 197 deletions

.nuke/build.schema.json

Lines changed: 80 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -123,129 +123,170 @@
123123
{
124124
"properties": {
125125
"AndroidEmulatorSerial": {
126-
"type": "string"
126+
"type": "string",
127+
"description": "Serial number of Android emulator"
127128
},
128129
"AndroidPhoneSerial": {
129-
"type": "string"
130+
"type": "string",
131+
"description": "Serial number of physical Android phone"
130132
},
131133
"Clean": {
132-
"type": "boolean"
134+
"type": "boolean",
135+
"description": "Clean artifacts before building"
133136
},
134137
"Configuration": {
135-
"type": "string"
138+
"type": "string",
139+
"description": "Build configuration (Debug/Release)"
136140
},
137141
"DeploySelection": {
138-
"type": "string"
142+
"type": "string",
143+
"description": "Comma-separated list of components to deploy (All, Director, WebUi, AndroidPhone, AndroidEmulator, DesktopMsix, DesktopDeb)"
139144
},
140145
"DeviceSerial": {
141-
"type": "string"
146+
"type": "string",
147+
"description": "Android device serial number for deployment and diagnostics"
142148
},
143149
"ExpectedRepoUrl": {
144-
"type": "string"
150+
"type": "string",
151+
"description": "Expected F-Droid repository URL for verification"
145152
},
146153
"ExpectedVersion": {
147-
"type": "string"
154+
"type": "string",
155+
"description": "Expected version for validation steps"
148156
},
149157
"ExtensionDevelopmentPath": {
150-
"type": "string"
158+
"type": "string",
159+
"description": "Path to the extension under development for VS Code launch"
151160
},
152161
"ExtensionsDir": {
153-
"type": "string"
162+
"type": "string",
163+
"description": "Custom extensions directory for VS Code/Cursor"
154164
},
155165
"Force": {
156-
"type": "boolean"
166+
"type": "boolean",
167+
"description": "Force operation even when safety checks would block it"
157168
},
158169
"IncludeBugreport": {
159-
"type": "boolean"
170+
"type": "boolean",
171+
"description": "Include full bugreport when collecting Android crash data"
160172
},
161173
"IncludeCursor": {
162-
"type": "boolean"
174+
"type": "boolean",
175+
"description": "Include installation for Cursor editor"
163176
},
164177
"IncludeVsCode": {
165-
"type": "boolean"
178+
"type": "boolean",
179+
"description": "Include installation for VS Code"
166180
},
167181
"Install": {
168-
"type": "boolean"
182+
"type": "boolean",
183+
"description": "Install package/extension after building"
169184
},
170185
"InstallDir": {
171-
"type": "string"
186+
"type": "string",
187+
"description": "Custom directory for installing VS extensions"
172188
},
173189
"JsonOutputPath": {
174-
"type": "string"
190+
"type": "string",
191+
"description": "Path where JSON output should be written"
175192
},
176193
"KillExisting": {
177-
"type": "boolean"
194+
"type": "boolean",
195+
"description": "Kill existing running instances before starting new ones"
178196
},
179197
"NoBuild": {
180-
"type": "boolean"
198+
"type": "boolean",
199+
"description": "Skip build step when possible"
181200
},
182201
"NoCert": {
183-
"type": "boolean"
202+
"type": "boolean",
203+
"description": "Skip code signing during packaging"
184204
},
185205
"NupkgDir": {
186-
"type": "string"
206+
"type": "string",
207+
"description": "Directory for output NuGet packages"
187208
},
188209
"OutputDir": {
189-
"type": "string"
210+
"type": "string",
211+
"description": "Root directory for build artifacts"
190212
},
191213
"OutputRoot": {
192-
"type": "string"
214+
"type": "string",
215+
"description": "Root directory for specialized output (e.g. crash artifacts)"
193216
},
194217
"PackageName": {
195-
"type": "string"
218+
"type": "string",
219+
"description": "Android package name for diagnostics collection"
196220
},
197221
"PackageVersion": {
198-
"type": "string"
222+
"type": "string",
223+
"description": "Override version for packages and artifacts"
199224
},
200225
"Phase": {
201-
"type": "string"
226+
"type": "string",
227+
"description": "Phase for Android crash collection workflow (Prepare/Collect)"
202228
},
203229
"Port": {
204230
"type": "integer",
231+
"description": "Port number for Web UI",
205232
"format": "int32"
206233
},
207234
"ProjectPath": {
208-
"type": "string"
235+
"type": "string",
236+
"description": "Path to project used for tool packing/updating"
209237
},
210238
"Rid": {
211-
"type": "string"
239+
"type": "string",
240+
"description": "Runtime Identifier (win-x64, linux-x64, etc.)"
212241
},
213242
"SkipInstall": {
214-
"type": "boolean"
243+
"type": "boolean",
244+
"description": "Skip automatic installation of VSIX/extension"
215245
},
216246
"SkipProcessStop": {
217-
"type": "boolean"
247+
"type": "boolean",
248+
"description": "Do not stop running processes before updating tools"
218249
},
219250
"SkipVersionBump": {
220-
"type": "boolean"
251+
"type": "boolean",
252+
"description": "Skip automatic GitVersion patch bump"
221253
},
222254
"TimeoutSeconds": {
223255
"type": "integer",
256+
"description": "Timeout in seconds for startup/health checks",
224257
"format": "int32"
225258
},
226259
"ToolCommand": {
227-
"type": "string"
260+
"type": "string",
261+
"description": "Command name for the installed dotnet tool"
228262
},
229263
"ToolId": {
230-
"type": "string"
264+
"type": "string",
265+
"description": "NuGet tool package ID (e.g. SharpNinja.McpServer.Director)"
231266
},
232267
"VsCodePath": {
233-
"type": "string"
268+
"type": "string",
269+
"description": "Path to VS Code (Code.exe) executable"
234270
},
235271
"VsixEntry": {
236-
"type": "string"
272+
"type": "string",
273+
"description": "Specific file entry to extract/read from a VSIX archive"
237274
},
238275
"VsixPath": {
239-
"type": "string"
276+
"type": "string",
277+
"description": "Path to a specific VSIX file to use"
240278
},
241279
"WhatIf": {
242-
"type": "boolean"
280+
"type": "boolean",
281+
"description": "Show what would be done without executing destructive actions"
243282
},
244283
"WorkspaceFolder": {
245-
"type": "string"
284+
"type": "string",
285+
"description": "Workspace folder to open when launching VS Code with extension"
246286
},
247287
"WslDistro": {
248-
"type": "string"
288+
"type": "string",
289+
"description": "WSL distribution name for Linux packaging"
249290
}
250291
}
251292
},

build/Build.BuildAndDeployTargets.cs

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
using System.Text.Json;
66
using System.Text.RegularExpressions;
77
using System.Xml.Linq;
8-
using static Nuke.Common.Logger;
8+
using Serilog;
99

1010
partial class Build
1111
{
@@ -26,7 +26,7 @@ private bool ShouldExecuteAction(string description)
2626
return true;
2727
}
2828

29-
Warn($"[WhatIf] {description}");
29+
Log.Warning($"[WhatIf] {description}");
3030
return false;
3131
}
3232

@@ -73,17 +73,17 @@ private List<string> ParseDeploySelections()
7373

7474
private void ShowDeploySummary(List<DeploymentResult> results)
7575
{
76-
Info("Deployment summary");
76+
Log.Information("Deployment summary");
7777
foreach (var result in results)
7878
{
79-
Info($"{result.Target}: {result.Status} - {result.Message}");
79+
Log.Information($"{result.Target}: {result.Status} - {result.Message}");
8080
}
8181

8282
var successCount = results.Count(x => x.Status == "Success");
8383
var whatIfCount = results.Count(x => x.Status == "WhatIf");
8484
var skippedCount = results.Count(x => x.Status == "Skipped");
8585
var failedCount = results.Count(x => x.Status == "Failed");
86-
Info($"Success={successCount} WhatIf={whatIfCount} Skipped={skippedCount} Failed={failedCount}");
86+
Log.Information($"Success={successCount} WhatIf={whatIfCount} Skipped={skippedCount} Failed={failedCount}");
8787
}
8888

8989
private string ExecuteDotnetToolPipeline(
@@ -364,7 +364,7 @@ private void DeployAndroidCore(string deviceSerial)
364364
var devices = InvokeProcess(ResolveAdbPath(), new List<string> { "devices", "-l" }, RepoRootPath, true);
365365
foreach (var line in devices.StandardOutputLines)
366366
{
367-
Info(line);
367+
Log.Information(line);
368368
}
369369

370370
InvokeDotNet(
@@ -560,7 +560,7 @@ [Desktop Entry]
560560
InvokeWslCommand(distro, $"cp {QuoteBashLiteral(wslTempDebPath)} {QuoteBashLiteral(wslDebPath)}");
561561
if (installAfterBuild)
562562
{
563-
Info($"Launching interactive WSL sudo in distro '{distro}'. Enter your password if prompted.");
563+
Log.Information($"Launching interactive WSL sudo in distro '{distro}'. Enter your password if prompted.");
564564
InvokeInteractiveWslCommand(distro, $"sudo dpkg -i {QuoteBashLiteral(wslTempDebPath)}");
565565
}
566566

@@ -572,7 +572,7 @@ [Desktop Entry]
572572
InvokeProcess("dpkg-deb", new List<string> { "--build", "--root-owner-group", debStagingDirectory, debFilePath }, RepoRootPath, true);
573573
if (installAfterBuild)
574574
{
575-
Info("Launching interactive sudo for desktop DEB install. Enter your password if prompted.");
575+
Log.Information("Launching interactive sudo for desktop DEB install. Enter your password if prompted.");
576576
InvokeInteractiveProcess("sudo", new List<string> { "dpkg", "-i", debFilePath }, RepoRootPath, true);
577577
}
578578
}
@@ -778,7 +778,7 @@ private void RunUpdateDotnetToolTarget()
778778
installAfterPack: true,
779779
skipVersionBumpValue: SkipVersionBump,
780780
skipProcessStopValue: SkipProcessStop);
781-
Info($"Dotnet tool pipeline complete: {packagePath}");
781+
Log.Information($"Dotnet tool pipeline complete: {packagePath}");
782782
}
783783

784784
private void RunPackDirectorToolTarget()
@@ -791,7 +791,7 @@ private void RunPackDirectorToolTarget()
791791
installAfterPack: false,
792792
skipVersionBumpValue: true,
793793
skipProcessStopValue: true);
794-
Info($"Director package ready: {packagePath}");
794+
Log.Information($"Director package ready: {packagePath}");
795795
}
796796

797797
private void RunUpdateDirectorToolTarget()
@@ -802,7 +802,7 @@ private void RunUpdateDirectorToolTarget()
802802
throw new InvalidOperationException(result.Message);
803803
}
804804

805-
Info(result.Message);
805+
Log.Information(result.Message);
806806
}
807807

808808
private void RunPublishWebZipTarget()
@@ -814,7 +814,7 @@ private void RunPublishWebZipTarget()
814814

815815
if (!ShouldExecuteAction($"Publish McpServer.Web {version.SemVer}"))
816816
{
817-
Info($"Would publish McpServer.Web to {zipPath}");
817+
Log.Information($"Would publish McpServer.Web to {zipPath}");
818818
return;
819819
}
820820

@@ -842,7 +842,7 @@ private void RunPublishWebZipTarget()
842842
}
843843

844844
ZipFile.CreateFromDirectory(publishDirectory, zipPath, CompressionLevel.Optimal, false);
845-
Info($"Web publish ready: {zipPath}");
845+
Log.Information($"Web publish ready: {zipPath}");
846846
}
847847

848848
private void RunUpdateWebUiToolTarget()
@@ -853,13 +853,13 @@ private void RunUpdateWebUiToolTarget()
853853
throw new InvalidOperationException(result.Message);
854854
}
855855

856-
Info(result.Message);
856+
Log.Information(result.Message);
857857
}
858858

859859
private void RunBuildAndroidPackageTarget()
860860
{
861861
var apkPath = BuildAndroidPackageCore();
862-
Info($"Android package ready: {apkPath}");
862+
Log.Information($"Android package ready: {apkPath}");
863863
}
864864

865865
private void RunDeployAndroidTarget()
@@ -870,19 +870,19 @@ private void RunDeployAndroidTarget()
870870
? AndroidPhoneSerial
871871
: "ZD222QH58Q";
872872
DeployAndroidCore(targetSerial);
873-
Info($"Android deployment completed for {targetSerial}");
873+
Log.Information($"Android deployment completed for {targetSerial}");
874874
}
875875

876876
private void RunBuildDesktopMsixTarget()
877877
{
878878
var msixPath = BuildDesktopMsixCore(installAfterBuild: Install);
879-
Info($"Desktop MSIX ready: {msixPath}");
879+
Log.Information($"Desktop MSIX ready: {msixPath}");
880880
}
881881

882882
private void RunBuildDesktopDebTarget()
883883
{
884884
var debPath = BuildDesktopDebCore(installAfterBuild: Install);
885-
Info($"Desktop DEB ready: {debPath}");
885+
Log.Information($"Desktop DEB ready: {debPath}");
886886
}
887887

888888
private void RunDeployAllTarget()

build/Build.Common.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
using System.Text.Json;
88
using System.Text.RegularExpressions;
99
using System.Xml.Linq;
10-
using static Nuke.Common.Logger;
10+
using Serilog;
1111

1212
partial class Build
1313
{

build/Build.MsixPackaging.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
using System.Runtime.Versioning;
88
using System.Xml;
99
using System.Xml.Linq;
10-
using static Nuke.Common.Logger;
10+
using Serilog;
1111

1212
partial class Build
1313
{
@@ -353,11 +353,11 @@ private string BuildDesktopMsixWithElevation()
353353
{
354354
if (CommandExists("gsudo"))
355355
{
356-
Warn("[WhatIf] Elevate the MSIX certificate trust step through gsudo, then install the package in the invoking user context.");
356+
Log.Warning("[WhatIf] Elevate the MSIX certificate trust step through gsudo, then install the package in the invoking user context.");
357357
}
358358
else
359359
{
360-
Warn("[WhatIf] MSIX certificate trust would require elevation, and gsudo was not found in PATH.");
360+
Log.Warning("[WhatIf] MSIX certificate trust would require elevation, and gsudo was not found in PATH.");
361361
}
362362

363363
return BuildDesktopMsixCoreNative(installAfterBuild: false);

0 commit comments

Comments
 (0)