diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 027cf605..518fb8c6 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,11 +1,20 @@ name: Test on: + pull_request: + branches: [main] + push: + branches: [main] workflow_dispatch: workflow_call: +concurrency: + group: test-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref || github.run_id }} + cancel-in-progress: true + jobs: - test: + validate: + name: validate runs-on: ubuntu-latest permissions: contents: read diff --git a/api/src/storage/filesystem.ts b/api/src/storage/filesystem.ts index bcf00bc7..7d74c9dc 100644 --- a/api/src/storage/filesystem.ts +++ b/api/src/storage/filesystem.ts @@ -335,7 +335,7 @@ async function migrateLegacyLayout( try { parsed = yaml.load(yamlContent, { schema: yaml.JSON_SCHEMA }); } catch (e) { - throw new Error(`Invalid YAML: ${e instanceof Error ? e.message : e}`); + throw new Error(`Invalid YAML: ${e instanceof Error ? e.message : e}`, { cause: e }); } const layout = LayoutFileSchema.safeParse(parsed); @@ -467,7 +467,7 @@ export async function saveLayout( parsed = yaml.load(yamlContent, { schema: yaml.JSON_SCHEMA }); } catch (e) { const message = e instanceof Error ? e.message : String(e); - throw new Error(`Invalid YAML: ${message}`); + throw new Error(`Invalid YAML: ${message}`, { cause: e }); } // Validate layout schema diff --git a/docs/guides/TESTING.md b/docs/guides/TESTING.md index 29de960f..46a9bf80 100644 --- a/docs/guides/TESTING.md +++ b/docs/guides/TESTING.md @@ -104,6 +104,17 @@ Use it to: **Note:** Dev deployment only succeeds if lint and tests pass. +### Required CI Checks + +Branch protection should require the core CI validation check from `.github/workflows/test.yml`: + +- **Check name:** `Test / validate` + +This check runs on: + +- Pull requests targeting `main` (pre-merge gate) +- Pushes to `main` (post-merge validation) + ## Philosophy We follow the **Testing Trophy** approach: diff --git a/scripts/generate-netbox-homelab-candidates.ts b/scripts/generate-netbox-homelab-candidates.ts index 4ab9eec8..3da8929c 100644 --- a/scripts/generate-netbox-homelab-candidates.ts +++ b/scripts/generate-netbox-homelab-candidates.ts @@ -451,6 +451,7 @@ function getNetBoxGitInfo(netboxRoot: string): { const message = error instanceof Error ? error.message : String(error); throw new Error( `Failed to read git metadata from NetBox root "${netboxRoot}": ${message}`, + { cause: error }, ); } } @@ -472,7 +473,7 @@ function collectCandidates( if (!file.endsWith(".yaml")) continue; const yamlPath = join(vendorDir, file); - let parsed: NetBoxDoc | null = null; + let parsed: NetBoxDoc | null; try { parsed = yaml.load(readFileSync(yamlPath, "utf8")) as NetBoxDoc; } catch (error) { diff --git a/scripts/import-netbox-devices.ts b/scripts/import-netbox-devices.ts index 2a52a9dd..13e4b14f 100644 --- a/scripts/import-netbox-devices.ts +++ b/scripts/import-netbox-devices.ts @@ -317,8 +317,8 @@ async function importDevice( // e.g., device.slug = 'hpe-proliant-dl360-gen10' const imageSlug = device.slug; - let frontImage = false; - let rearImage = false; + let frontImage: boolean; + let rearImage: boolean; // Try to download front image (try .png first, then .jpg) const frontDest = join(destDir, `${imageSlug}.front.png`);