Files
Dan Moseley 042a9d2b2c Reorganize plugins into domain-specific groupings (#274)
* Reorganize plugins per agreed structure (#271)

Split the dotnet plugin into domain-specific plugins per discussion
in #271:

- dotnet: narrowed to common everyday C#/.NET coding tasks
- dotnet-diag: perf investigations, debugging, incident analysis
- dotnet-data: data access and Entity Framework
- dotnet-aspnet, dotnet-wpf, dotnet-winforms, dotnet-maui: scaffolded
  empty to convey intent for future framework-specific skills

Moved skills, tests, and CODEOWNERS entries accordingly.
No file content was changed; all skill/test moves are pure renames.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Improve dotnet-diag and dotnet-winforms descriptions

- dotnet-diag: add '.NET' qualifier to clarify scope
- dotnet-winforms: use official 'Windows Forms (WinForms)' name

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add .NET qualifier to dotnet-data description

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Remove empty plugins; list them in CONTRIBUTING.md as future options

Remove the four empty placeholder plugins (dotnet-aspnet, dotnet-wpf,
dotnet-winforms, dotnet-maui) that had only plugin.json and no skills.

Add a 'Plugin organization' section to CONTRIBUTING.md that describes the
domain-specific plugin groupings introduced in this PR and lists the four
removed plugin names as reserved candidates for future contributions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Create dotnet-upgrade plugin with migration/upgrade skills

Move migrate-nullable-references, thread-abort-migration, and
dotnet-aot-compat from dotnet to the new dotnet-upgrade plugin.

Update CODEOWNERS paths (same owners), CONTRIBUTING.md plugin table,
and fix the thread-abort-migration SKILL.md link in CONTRIBUTING.md.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-06 21:01:52 -08:00

273 lines
9.8 KiB
YAML

scenarios:
- name: "Worker thread with abort-based cancellation"
prompt: |
Migrate this .NET Framework code to .NET 8. Provide complete migration guidance with code and pitfalls.
```csharp
public class BackgroundProcessor
{
private Thread _workerThread;
private volatile bool _running;
public void Start()
{
_running = true;
_workerThread = new Thread(ProcessLoop);
_workerThread.IsBackground = true;
_workerThread.Start();
}
private void ProcessLoop()
{
while (_running)
{
try
{
var item = GetNextItem(); // may block
ProcessItem(item);
}
catch (ThreadAbortException)
{
// Clean up partial work
RollbackCurrentTransaction();
Thread.ResetAbort(); // prevent rethrow so finally runs cleanly
}
finally
{
FlushBuffers();
}
}
}
public void Stop()
{
_running = false;
if (_workerThread != null && _workerThread.IsAlive)
{
Thread.Sleep(2000); // give it time
if (_workerThread.IsAlive)
_workerThread.Abort(); // force stop
}
}
}
```
assertions:
- type: output_contains
value: "CancellationToken"
- type: output_contains
value: "OperationCanceledException"
- type: exit_success
rubric:
- "Replaces Thread.Abort with CancellationTokenSource.Cancel"
- "Migrates the ThreadAbortException catch block cleanup logic to a proper OperationCanceledException handler or finally block"
- "Addresses Thread.ResetAbort removal and explains why it is no longer needed"
- "Warns about passing CancellationToken through the full call chain including to GetNextItem"
- "Mentions that CancellationToken must be actively checked — it will not interrupt blocking calls like the original Thread.Abort did"
timeout: 120
- name: "Timeout enforcement via Thread.Abort"
prompt: |
Migrate this .NET Framework code to .NET 8. Provide complete migration guidance with code and pitfalls.
```csharp
public class TimedExecutor
{
public T ExecuteWithTimeout<T>(Func<T> work, TimeSpan timeout)
{
T result = default;
Exception error = null;
var thread = new Thread(() =>
{
try { result = work(); }
catch (ThreadAbortException) { Thread.ResetAbort(); }
catch (Exception ex) { error = ex; }
});
thread.Start();
if (!thread.Join(timeout))
{
thread.Abort();
throw new TimeoutException($"Operation exceeded {timeout.TotalSeconds}s timeout");
}
if (error != null)
throw new AggregateException(error);
return result;
}
}
```
assertions:
- type: output_contains
value: "CancellationTokenSource"
- type: output_contains
value: "CancelAfter"
- type: exit_success
rubric:
- "Replaces the Thread+Abort timeout pattern with CancellationTokenSource.CancelAfter or Task.WhenAny with Task.Delay"
- "Warns that the Func<T> work delegate must accept and check a CancellationToken for cancellation to actually work"
- "Mentions that if the work delegate cannot be modified (uncooperative code), the only safe option is process isolation with Process.Kill"
- "Does NOT suggest that wrapping in a Task and abandoning the thread is safe — the thread continues running"
- "Handles the case where the original code caught ThreadAbortException and called ResetAbort"
timeout: 120
- name: "Blocking WaitHandle with Thread.Interrupt"
prompt: |
Migrate this .NET Framework code to .NET 8. Provide complete migration guidance with code and pitfalls.
```csharp
public class EventProcessor
{
private readonly ManualResetEvent _newEvent = new ManualResetEvent(false);
private readonly Queue<string> _queue = new Queue<string>();
private Thread _thread;
private readonly object _lock = new object();
public void Start()
{
_thread = new Thread(RunLoop);
_thread.Start();
}
private void RunLoop()
{
while (true)
{
_newEvent.WaitOne(); // blocks until signaled
_newEvent.Reset();
string item;
lock (_lock) { item = _queue.Dequeue(); }
Handle(item);
}
}
public void Enqueue(string item)
{
lock (_lock) { _queue.Enqueue(item); }
_newEvent.Set();
}
public void Stop()
{
_thread.Interrupt(); // wake from WaitOne
_thread.Join(5000);
if (_thread.IsAlive)
_thread.Abort();
}
}
```
assertions:
- type: output_contains
value: "CancellationToken"
- type: output_contains
value: "WaitHandle"
- type: exit_success
rubric:
- "Replaces Thread.Interrupt with CancellationToken signaling"
- "Shows how to combine WaitHandle.WaitAny with CancellationToken.WaitHandle to make the WaitOne call cancellable"
- "Removes Thread.Abort fallback and explains why it cannot be used"
- "Suggests using a modern alternative like Channel<T> or BlockingCollection<T> with cancellation support"
- "Warns that Thread.Interrupt only works on threads in WaitSleepJoin state and is not a reliable cancellation mechanism"
timeout: 120
- name: "ASP.NET Response.End and Response.Redirect with Thread.Abort"
prompt: |
Migrate this .NET Framework ASP.NET code to ASP.NET Core (.NET 8). Provide complete migration guidance with code and pitfalls.
```csharp
public class ReportController : Controller
{
protected void btnExport_Click(object sender, EventArgs e)
{
var data = GenerateReport();
Response.Clear();
Response.ContentType = "text/csv";
Response.AddHeader("Content-Disposition", "attachment; filename=report.csv");
Response.Write(data);
Response.End(); // throws ThreadAbortException internally
}
protected void btnRedirect_Click(object sender, EventArgs e)
{
if (!User.Identity.IsAuthenticated)
{
Response.Redirect("/login", true); // true = endResponse, calls Thread.Abort
return;
}
try
{
ProcessRequest();
Response.Redirect("/success", true);
}
catch (ThreadAbortException)
{
// Expected from Response.Redirect — swallow it
}
catch (Exception ex)
{
LogError(ex);
Response.Redirect("/error", true);
}
}
}
```
assertions:
- type: output_contains
value: "Redirect("
- type: output_not_matches
pattern: "Thread\\.Abort\\s*\\("
- type: exit_success
rubric:
- "Explains that Response.End and Response.Redirect(url, true) internally call Thread.Abort in ASP.NET Framework"
- "Replaces Response.End with returning a FileResult or writing to the response body and returning"
- "Replaces Response.Redirect(url, true) with a redirect result or Response.Redirect(url) without the endResponse parameter"
- "Removes the catch (ThreadAbortException) block and explains it is no longer needed"
- "Mentions HttpContext.RequestAborted as the cancellation mechanism in ASP.NET Core for long-running request work"
timeout: 120
- name: "Thread.Join and Thread.Sleep only — should not migrate"
prompt: |
I'm migrating this .NET Framework code to .NET 8 and need to ensure all Thread.Abort
usage is addressed. Check this code and provide your Thread.Abort migration guidance.
```csharp
public class SimpleWorker
{
public void RunBatch(List<WorkItem> items)
{
var threads = new List<Thread>();
foreach (var item in items)
{
var t = new Thread(() => Process(item));
t.Start();
threads.Add(t);
}
foreach (var t in threads)
t.Join();
}
private void Process(WorkItem item)
{
// simulate work
Thread.Sleep(100);
item.Result = ComputeResult(item.Input);
}
}
```
assertions:
- type: output_matches
pattern: "(no|not|don't|doesn't|without).{0,50}(migration|migrat|changes needed|changes required)|(already (compatible|works|supported))"
- type: exit_success
rubric:
- "Correctly identifies that this code does NOT use Thread.Abort, Thread.Interrupt, or ThreadAbortException"
- "Does NOT fabricate Thread.Abort migration concerns that do not exist in the code"
- "May suggest modernization to Task.Run or Parallel.ForEach, but does NOT frame it as a Thread.Abort migration"
- "Does NOT over-migrate — any suggestions should be optional improvements, not required fixes"
timeout: 120