Преглед на файлове

Merge pull request #159 from Timmoth/housekeeping

Housekeeping
Tim Jones преди 1 месец
родител
ревизия
15aa348e7e

BIN
.DS_Store


+ 7 - 0
.gitignore

@@ -420,3 +420,10 @@ FodyWeavers.xsd
 **/config/
 !RackPeek.Web.Viewer/wwwroot/config/
 !RackPeek.Web.Viewer/wwwroot/config/**
+
+# IDE folders
+.idea/
+.run/
+
+# macOS
+.DS_Store

+ 0 - 13
.idea/.idea.RackPeek/.idea/.gitignore

@@ -1,13 +0,0 @@
-# Default ignored files
-/shelf/
-/workspace.xml
-# Rider ignored files
-/contentModel.xml
-/projectSettingsUpdater.xml
-/.idea.RackPeek.iml
-/modules.xml
-# Editor-based HTTP Client requests
-/httpRequests/
-# Datasource local storage ignored files
-/dataSources/
-/dataSources.local.xml

+ 0 - 8
.idea/.idea.RackPeek/.idea/indexLayout.xml

@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="UserContentModel">
-    <attachedFolders />
-    <explicitIncludes />
-    <explicitExcludes />
-  </component>
-</project>

+ 0 - 7
.idea/.idea.RackPeek/.idea/vcs.xml

@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="VcsDirectoryMappings">
-    <mapping directory="" vcs="Git" />
-    <mapping directory="$PROJECT_DIR$" vcs="Git" />
-  </component>
-</project>

+ 0 - 19
.run/RackPeek.Web.Viewer_ https.run.xml

@@ -1,19 +0,0 @@
-<component name="ProjectRunConfigurationManager">
-  <configuration default="false" name="RackPeek.Web.Viewer: https" type="LaunchSettings" factoryName=".NET Launch Settings Profile">
-    <option name="LAUNCH_PROFILE_PROJECT_FILE_PATH" value="$PROJECT_DIR$/RackPeek.Web.Viewer/RackPeek.Web.Viewer.csproj" />
-    <option name="LAUNCH_PROFILE_TFM" value="net10.0" />
-    <option name="LAUNCH_PROFILE_NAME" value="https" />
-    <option name="USE_EXTERNAL_CONSOLE" value="0" />
-    <option name="USE_MONO" value="0" />
-    <option name="RUNTIME_ARGUMENTS" value="" />
-    <browser name="98ca6316-2f89-46d9-a9e5-fa9e2b0625b3" />
-    <option name="GENERATE_APPLICATIONHOST_CONFIG" value="1" />
-    <option name="SHOW_IIS_EXPRESS_OUTPUT" value="0" />
-    <option name="SEND_DEBUG_REQUEST" value="1" />
-    <option name="ADDITIONAL_IIS_EXPRESS_ARGUMENTS" value="" />
-    <option name="RUNTIME_TYPE" value="coreclr" />
-    <method v="2">
-      <option name="Build" />
-    </method>
-  </configuration>
-</component>

+ 8 - 0
README.md

@@ -141,3 +141,11 @@ RackPeek is built to solve real problems we actively have. If a feature isn’t
 **Opinionated**  
 The project is optimized for home labs and self-hosted environments, not enterprise CMDBs or corporate documentation workflows.
 
+Here’s a clean section you can drop into your **README.md**.
+
+
+## Development Docs
+
+* [`contribution-guidelines.md`](docs/development/contribution-guidelines.md) – How to propose changes and submit PRs
+* [`dev-cheat-sheet.md`](docs/development/dev-cheat-sheet.md) – Build, release, Docker, and testing commands
+* [`testing-guidelines.md`](docs/development/testing-guidelines.md) – Testing principles and standards

BIN
RackPeek.Web/.DS_Store


BIN
RackPeek/.DS_Store


+ 56 - 0
docs/development/contribution-guidelines.md

@@ -0,0 +1,56 @@
+# Contribution Guidelines
+
+- Keep changes small.
+- Keep behaviour tested.
+- Discuss before building.
+
+## Checklist
+
+* [ ] Linked GitHub issue
+* [ ] Approach validated
+* [ ] Small, focused PR
+* [ ] All tests passing locally
+* [ ] Behaviour covered by tests
+* [ ] YAML migration defined (if needed)
+  
+## Before You Start
+
+* Search existing **GitHub Issues**
+* If none exists → create one (and seek feedback) before coding
+* Clearly state what you want to work on
+* Validate your approach with core maintainers
+* Prefer GitHub Issues over Discord for design discussion
+
+## Keep PRs Small
+
+* Small, focused PRs only
+* One concern per PR
+
+Large PRs slow review and increase load on the team
+
+## Open as Draft
+
+* Mark PR as **Draft** initially
+* Move to Ready only when:
+
+  * Tests pass locally
+  * Scope is complete
+  * No debug code remains
+
+
+## Testing Requirements
+
+Before removing Draft:
+
+* CLI tests pass
+* Web UI E2E tests pass
+* Behaviour is covered by tests
+
+## YAML Schema Changes
+
+If you modify persisted YAML:
+
+* Define a schema migration
+* Ensure backward compatibility (or clearly document breaking changes)
+* Add migration tests
+

+ 133 - 0
docs/development/dev-cheat-sheet.md

@@ -0,0 +1,133 @@
+
+# Dev Cheat Sheet
+
+
+## Build CLI (macOS ARM64)
+
+Publish a self-contained single binary:
+
+```bash
+dotnet publish -c Release -r osx-arm64 \
+  --self-contained true \
+  -p:PublishSingleFile=true
+```
+
+Install globally:
+
+```bash
+sudo mv bin/Release/net*/osx-arm64/publish/RackPeek /usr/local/bin/rpk
+sudo chmod +x /usr/local/bin/rpk
+```
+
+Verify:
+
+```bash
+rpk --help
+```
+
+---
+
+## Generate CLI Demo (VHS)
+
+Install tools:
+
+```bash
+brew install vhs
+brew install imagemagick
+brew install --cask google-chrome # if not already installed
+```
+
+Run tape:
+
+```bash
+cd vhs
+vhs ./rpk.tape
+```
+
+---
+
+## Capture Web UI Demo
+
+Make script executable:
+
+```bash
+chmod +x webui_capture.sh
+```
+
+Run:
+
+```bash
+./webui_capture.sh
+```
+
+> Requires Chrome + ImageMagick.
+
+---
+
+## Build & Push Multi-Arch Docker Image
+
+Manual release build:
+
+```bash
+docker buildx build \
+  --platform linux/amd64,linux/arm64 \
+  -f ./Dockerfile \
+  -t aptacode/rackpeek:v0.0.11 \
+  -t aptacode/rackpeek:latest \
+  --push ..
+```
+
+Notes:
+
+* Uses `buildx` for multi-arch
+* Pushes directly to registry
+* Update version tag before running
+
+---
+
+## Run E2E Tests (Playwright)
+
+Install tooling (first time only):
+
+```bash
+cd Tests.E2e
+dotnet tool install --global Microsoft.Playwright.CLI
+dotnet build
+playwright install
+```
+
+Build Web image (required before running tests):
+
+```bash
+docker build -t rackpeek:ci -f RackPeek.Web/Dockerfile .
+```
+
+---
+
+## Common Workflows
+
+### Rebuild everything quickly
+
+```bash
+docker build -t rackpeek:ci -f RackPeek.Web/Dockerfile .
+cd Tests.E2e && dotnet test
+```
+
+---
+
+## Debugging E2E Tests
+
+Temporarily set in `PlaywrightFixture.cs`:
+
+```csharp
+Headless = false,
+SlowMo = 500,
+```
+
+⚠ Revert to:
+
+```csharp
+Headless = true,
+```
+
+Before committing (CI requires headless mode).

+ 320 - 0
docs/development/testing-guidelines.md

@@ -0,0 +1,320 @@
+# Testing Principles
+
+We deliberately test at the **edges of the system** this gives us:
+
+* Freedom to refactor
+* Confidence to optimise
+* Stable, long-lived tests
+* Reduced coupling to implementation details
+
+We write **high-level, black-box integration tests** that focus only on observable outcomes (behaviour not implementation details).
+
+If a refactor breaks a test without changing observable behaviour, the test was too coupled.
+
+---
+
+## Test Projects
+
+We maintain two test suites:
+
+```
+./Tests        → CLI tests
+./Tests.E2e    → Blazor Web UI tests (Playwright)
+```
+
+All tests must pass before a PR can be merged into `main`.
+
+> If something is worth testing manually, it’s worth automating.
+
+When adding features:
+
+* Add tests with them
+* If tests are missing, add them
+* If behaviour changes, update tests intentionally
+
+When fixing bugs: 
+
+* Reproduce manually
+* Reproduce repeatably with a `failing` test
+* Make the test pass
+
+---
+
+# Web UI (E2E) Tests
+
+We use **Playwright** to test the Blazor Server app.
+
+These tests are:
+
+* Slow(ish)
+* Primarily happy-path + critical flows
+
+Avoid:
+
+* Testing styling details
+* Over-asserting UI minutiae
+
+---
+
+## Running E2E Tests
+
+You must build the Docker image before running:
+
+```bash
+cd RackPeek
+docker build -t rackpeek:ci -f RackPeek.Web/Dockerfile .
+
+cd Tests.E2e
+dotnet tool install --global Microsoft.Playwright.CLI
+dotnet build
+
+playwright install
+dotnet test
+```
+
+Rebuild the image whenever the Web project changes.
+
+---
+
+## Page Object Model (POM)
+
+Each page/component has a **POM (Page Object Model)** abstraction.
+
+The POM:
+
+* Encapsulates selectors
+* Encapsulates browser interactions
+* Exposes intent-level methods (`AddDesktopAsync`, `GotoHardwareAsync`)
+* Shields tests from UI churn
+
+Tests should read like workflows — not like browser scripts.
+
+Example:
+
+```csharp
+[Fact]
+public async Task User_Can_Add_And_Delete_Desktop()
+{
+    var (context, page) = await CreatePageAsync();
+    var resourceName = $"e2e-ap-{Guid.NewGuid():N}"[..16];
+
+    try
+    {
+        await page.GotoAsync(fixture.BaseUrl);
+
+        var layout = new MainLayoutPom(page);
+        await layout.AssertLoadedAsync();
+        await layout.GotoHardwareAsync();
+
+        var hardwarePage = new HardwareTreePom(page);
+        await hardwarePage.AssertLoadedAsync();
+        await hardwarePage.GotoDesktopsListAsync();
+
+        var listPage = new DesktopsListPom(page);
+        await listPage.AssertLoadedAsync();
+        await listPage.AddDesktopAsync(resourceName);
+        await listPage.AssertDesktopExists(resourceName);
+        await listPage.DeleteDesktopAsync(resourceName);
+        await listPage.AssertDesktopDoesNotExist(resourceName);
+    }
+    catch (Exception)
+    {
+        _output.WriteLine("TEST FAILED — Capturing diagnostics");
+        _output.WriteLine($"Current URL: {page.Url}");
+
+        var html = await page.ContentAsync();
+        _output.WriteLine("==== DOM SNAPSHOT START ====");
+        _output.WriteLine(html);
+        _output.WriteLine("==== DOM SNAPSHOT END ====");
+
+        throw;
+    }
+    finally
+    {
+        await context.CloseAsync();
+    }
+}
+```
+
+### Good E2E Test Traits
+
+* Single responsibility
+* Independent (no ordering dependencies)
+* Idempotent
+* Generates unique test data
+* Cleans up after itself
+* Fails with useful diagnostics
+
+---
+
+## Debugging E2E Tests
+
+You may temporarily modify:
+
+`Tests.E2e/infra/PlaywrightFixture.cs`
+
+To debug visually:
+
+```csharp
+Browser = await _playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions
+{
+    Headless = false,
+    SlowMo = 500,
+    Args = new[]
+    {
+        "--disable-dev-shm-usage",
+        "--no-sandbox"
+    }
+});
+```
+
+⚠ **Before committing**, revert to CI-safe settings:
+
+```csharp
+Browser = await _playwright.Chromium.LaunchAsync(new BrowserTypeLaunchOptions
+{
+    Headless = true,
+    Args = new[]
+    {
+        "--disable-dev-shm-usage",
+        "--no-sandbox"
+    }
+});
+```
+
+CI must always run headless.
+
+---
+
+# CLI Tests
+
+CLI tests are faster and more precise.
+
+They behave more like unit/integration hybrids (intragrationtests if you like):
+
+* Validate both happy + unhappy paths
+* Assert command output
+* Assert YAML written to disk
+* Avoid UI overhead
+
+Run them with:
+
+```bash
+cd Tests
+dotnet test
+```
+
+Example:
+
+```csharp
+[Fact]
+public async Task servers_tree_cli_workflow_test()
+{
+    await File.WriteAllTextAsync(Path.Combine(fs.Root, "config.yaml"), "");
+
+    var (output, yaml) = await ExecuteAsync("servers", "add", "node01");
+    Assert.Equal("Server 'node01' added.\n", output);
+    Assert.Contains("name: node01", yaml);
+
+    (output, yaml) = await ExecuteAsync("systems", "add", "host01");
+    Assert.Equal("System 'host01' added.\n", output);
+
+    (output, yaml) = await ExecuteAsync("systems", "add", "host02");
+    Assert.Equal("System 'host02' added.\n", output);
+
+    (output, yaml) = await ExecuteAsync("systems", "add", "host03");
+    Assert.Equal("System 'host03' added.\n", output);
+
+    (output, yaml) = await ExecuteAsync(
+        "systems", "set", "host01",
+        "--runs-on", "node01"
+    );
+    Assert.Equal("System 'host01' updated.\n", output);
+
+    (output, yaml) = await ExecuteAsync("services", "add", "immich");
+    Assert.Equal("Service 'immich' added.\n", output);
+
+    (output, yaml) = await ExecuteAsync("servers", "tree", "node01");
+    Assert.Equal("""
+                 node01
+                 ├── System: host01
+                 │   ├── Service: immich
+                 │   └── Service: paperless
+                 ├── System: host02
+                 └── System: host03
+
+                 """, output);
+}
+```
+
+---
+
+## CLI Testing Best Practices
+
+* Assert exact output where meaningful
+* Validate file side effects
+* Test invalid arguments and failure modes
+* Avoid brittle whitespace assertions unless intentional
+* Keep tests deterministic
+* Avoid shared filesystem state
+
+---
+
+# General Testing Standards
+
+### 1. Behaviour First
+
+Test what the user observes — not how we implement it.
+
+### 2. Prefer Integration Over Micro-Mocking
+
+We value confidence over isolation purity.
+
+### 3. Fast Feedback
+
+* CLI tests should be fast
+* E2E tests should be minimal but meaningful
+
+### 4. Tests Are Documentation
+
+A good test explains:
+
+* What the feature does
+* How it’s expected to behave
+* What regressions look like
+
+### 5. Stability > Coverage %
+
+High-value tests matter more than coverage numbers.
+
+### 6. No Flaky Tests
+
+If a test is flaky:
+
+* Fix it immediately
+* Or remove it
+* Flaky tests erode trust
+
+---
+
+# Definition of Done
+
+A feature is complete when:
+
+* Behaviour is implemented
+* Tests exist
+* Tests pass locally
+* Tests pass in CI
+* Edge cases are covered
+* No debug flags remain enabled
+
+---
+
+We optimise for:
+
+* Confidence
+* Refactorability
+* Clarity
+* Long-term maintainability
+
+Tests are a first-class citizen of this project.

+ 0 - 50
notes.md

@@ -1,50 +0,0 @@
-```
-dotnet publish -c Release -r osx-arm64 --self-contained true -p:PublishSingleFile=true
-sudo mv bin/Release/net*/osx-arm64/publish/RackPeek /usr/local/bin/rpk
-sudo chmod +x /usr/local/bin/rpk
-
-```
-
-```
-cd vhs
-brew install vhs
-vhs ./rpk.tape
-
-brew install imagemagick
-brew install --cask google-chrome # if chrome not installed
-chmod +x webui_capture.sh
-./webui_capture.sh
-
-```
-
-```
-
-
-
-```
-
-```bash
-# Manually build / push
-docker buildx build \
-  --platform linux/amd64,linux/arm64 \
-  -f ./Dockerfile \
-  -t aptacode/rackpeek:v0.0.11 \
-  -t aptacode/rackpeek:latest \
-  --push ..
-
-
-```
-
-
-e2e tests
-```bash
-cd Tests.E2e
-dotnet tool install --global Microsoft.Playwright.CLI
-dotnet build
-
-playwright install
-
-docker build -t rackpeek:ci -f RackPeek.Web/Dockerfile .
-
-
-```

BIN
vhs/.DS_Store