diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..fec5731 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,15 @@ +# README screenshot + +The README embeds the root `screenshot.png`. Refresh it when requested or when visible main-window changes make the image stale (for example, picker layout, toolbar, comparison tree, or diff display). Screenshots intentionally omit the entire build-version label; build-label changes alone do not require a refresh. + +On Windows, with PowerShell 7.2 or newer, a desktop session, and an SDK compatible with `global.json` (a stable .NET 10.0 SDK at or above `10.0.402`), run from the repository root: + +```powershell +pwsh -NoProfile -File .\scripts\Update-ReadmeScreenshot.ps1 +``` + +The command builds the current code and captures the real form with fixed fictional data. It does not connect to Kusto or read/write saved user settings. Keep those guarantees: never substitute real credentials, connections, schemas, or a full-desktop capture. No manual app setup is needed. + +Inspect the generated image before including `screenshot.png` with the relevant UI changes. Confirm the build-version label is absent and both pickers, expanded comparison, checked `CurrentTime` function, and red/yellow diff are visible. If capture is unavailable or fails, report that limitation rather than fabricating an image or claiming it was refreshed. Do not edit the image by hand or add automatic CI updates. + +See `CONTRIBUTING.md` for prerequisites and capture details. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 02f26d1..57090c6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -35,6 +35,24 @@ The CI regression tests run offline; they do not validate live Kusto authenticat The main window shows a date-based build version in `Build YYYYMMDD` format (currently `Build 20261020`, for October 20, 2026). To update the displayed date, change `label2.Text` in `SyncKusto\MainForm.Designer.cs`. +### Refreshing the README screenshot + +On Windows, install PowerShell 7.2 or newer and an SDK compatible with `global.json`, then run: + +```powershell +pwsh -NoProfile -File .\scripts\Update-ReadmeScreenshot.ps1 +``` + +The script resolves the repository from its own location, so it also works when invoked by absolute path from another working directory. It performs a locked restore using your normal trusted NuGet configuration, builds the application and test project in Release, and runs only the explicitly selected screenshot fixture. Package restore may require network access; the capture itself is completely offline. + +The fixture opens the real main form without requesting activation, with in-memory settings and a fake presenter supplying a fictional modified `CurrentTime` function. It never uses live Kusto connections, credentials, saved settings, or schema files. Windows renders only that window, including its native rich-text diff; no desktop pixels or unrelated windows are captured. A Windows desktop session is required; this is not a browser or headless cross-platform renderer. + +Screenshots intentionally omit the entire build-version label, regardless of its value. This is limited to the capture fixture and does not change the production UI. Build-label changes alone do not require refreshing the screenshot. + +The command replaces root `screenshot.png` only after capture succeeds and the PNG passes content and size checks. Capture has a timeout, and failures leave the existing image unchanged. Normal test runs do not regenerate the image, and no CI or scheduled regeneration is configured. + +Inspect the result before including it with your changes: the build-version label should be absent, and the source and target pickers, expanded comparison, checked function, and red/yellow diff should be visible. The demo content and window dimensions are fixed, but native window chrome, fonts, and theme can vary between Windows environments; byte-identical output across machines is not guaranteed. Agents should follow the refresh guidance in `AGENTS.md`. + ### Dependency restore policy Local development and CI deliberately select sources differently: diff --git a/README.md b/README.md index c35fde7..b7a779d 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ The Sync Kusto tool was built to help create a maintainable development process ![Screenshot](/screenshot.png) +To regenerate this image automatically, see [Refreshing the README screenshot](CONTRIBUTING.md#refreshing-the-readme-screenshot). + ## Scope This tool is intended specifically for the developer desktop scenario. It will not help if you need to build an automated syncing process, generate change scripts, sync policies, etc. For all of that, we recommend using [Delta Kusto](https://github.com/microsoft/delta-kusto). diff --git a/SyncKusto.Tests/Screenshots/ReadmeScreenshotTests.cs b/SyncKusto.Tests/Screenshots/ReadmeScreenshotTests.cs new file mode 100644 index 0000000..66a49b7 --- /dev/null +++ b/SyncKusto.Tests/Screenshots/ReadmeScreenshotTests.cs @@ -0,0 +1,151 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Kusto.Data.Common; +using Moq; +using NUnit.Framework; +using SyncKusto.Abstractions; +using SyncKusto.Core.Abstractions; +using SyncKusto.Core.Models; +using SyncKusto.Core.Services; +using SyncKusto.ErrorHandling; +using SyncKusto.Kusto.Models; +using System.Drawing; +using System.Drawing.Imaging; +using System.Reflection; +using System.Runtime.InteropServices; +using static SyncKusto.Tests.Forms.FormsTestHelper; + +namespace SyncKusto.Tests.Screenshots; + +[TestFixture] +[Apartment(ApartmentState.STA)] +[NonParallelizable] +public class ReadmeScreenshotTests +{ + [Test] + [Explicit("Run scripts\\Update-ReadmeScreenshot.ps1 to refresh the README image.")] + public void Capture() + { + string? outputPath = Environment.GetEnvironmentVariable("SYNCKUSTO_SCREENSHOT_PATH"); + Assert.That(outputPath, Is.Not.Null.And.Not.Empty, "Use scripts\\Update-ReadmeScreenshot.ps1."); + Assert.That(Environment.UserInteractive, Is.True, "Screenshot capture requires a Windows desktop session."); + + Application.SetHighDpiMode(HighDpiMode.DpiUnaware); + Application.SetDefaultFont(new Font("Microsoft Sans Serif", 8.25f)); + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + + var source = new DatabaseSchema("demo-source", ""); + var target = new DatabaseSchema("demo-target", ""); + var current = CreateFunction("{\r\n print now(), Yesterday=ago(1d)\r\n}"); + source.Functions.Add(current.Name, current); + target.Functions.Add(current.Name, CreateFunction("{\r\n print now()\r\n}")); + var comparison = new ComparisonResult( + new SchemaDifferenceResult(Array.Empty(), + new[] { new FunctionSchemaDifference(new Modified(), new KustoFunctionSchema(current)) }), + source, target); + var presenter = new Mock(MockBehavior.Strict); + presenter.Setup(p => p.CompareAsync(It.IsAny(), It.IsAny(), + It.IsAny>(), default)).ReturnsAsync(comparison); + var settings = new InMemorySettingsProvider(); + var validation = new SchemaValidationService(settings); + var kustoValidation = new Mock(MockBehavior.Strict); + using var form = new CaptureForm(presenter.Object, settings, validation, kustoValidation.Object) + { + StartPosition = FormStartPosition.Manual, + Location = new Point(0, 0), + Size = new Size(655, 854), + ShowInTaskbar = false + }; + var sourcePicker = form.MainField("spcSource"); + Field(sourcePicker, "txtFilePath").Text = @"C:\Demo\Weather"; + var targetPicker = form.MainField("spcTarget"); + Field(targetPicker, "rbKusto").Checked = true; + Field(targetPicker, "cbCluster").Text = "https://demo.kusto.windows.net"; + Field(targetPicker, "cbDatabase").Text = "Weather"; + form.MainField