Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
294b6b3bfc | ||
|
|
7f9742bcaa | ||
|
|
5aad24522c |
@@ -344,7 +344,7 @@ jobs:
|
|||||||
mkdir -p ~/.ssh
|
mkdir -p ~/.ssh
|
||||||
echo "${{ secrets.ALPHA_SSH_KEY }}" > ~/.ssh/id_ed25519
|
echo "${{ secrets.ALPHA_SSH_KEY }}" > ~/.ssh/id_ed25519
|
||||||
chmod 600 ~/.ssh/id_ed25519
|
chmod 600 ~/.ssh/id_ed25519
|
||||||
ssh-keyscan -H alpha.mintel.me >> ~/.ssh/known_hosts 2>/dev/null
|
ssh-keyscan -H infra.mintel.me >> ~/.ssh/known_hosts 2>/dev/null
|
||||||
|
|
||||||
# Transfer and Restart
|
# Transfer and Restart
|
||||||
if [[ "$TARGET" == "production" ]]; then
|
if [[ "$TARGET" == "production" ]]; then
|
||||||
@@ -356,17 +356,17 @@ jobs:
|
|||||||
else
|
else
|
||||||
SITE_DIR="/home/deploy/sites/branch.klz-cables.com/${SLUG:-unknown}"
|
SITE_DIR="/home/deploy/sites/branch.klz-cables.com/${SLUG:-unknown}"
|
||||||
fi
|
fi
|
||||||
ssh root@alpha.mintel.me "mkdir -p $SITE_DIR"
|
ssh root@infra.mintel.me "mkdir -p $SITE_DIR"
|
||||||
|
|
||||||
scp .env.deploy root@alpha.mintel.me:$SITE_DIR/$ENV_FILE
|
scp .env.deploy root@infra.mintel.me:$SITE_DIR/$ENV_FILE
|
||||||
scp docker-compose.yml root@alpha.mintel.me:$SITE_DIR/docker-compose.yml
|
scp docker-compose.yml root@infra.mintel.me:$SITE_DIR/docker-compose.yml
|
||||||
|
|
||||||
ssh root@alpha.mintel.me "cd $SITE_DIR && echo '${{ secrets.REGISTRY_PASS }}' | docker login registry.infra.mintel.me -u '${{ secrets.REGISTRY_USER }}' --password-stdin"
|
ssh root@infra.mintel.me "cd $SITE_DIR && echo '${{ secrets.REGISTRY_PASS }}' | docker login registry.infra.mintel.me -u '${{ secrets.REGISTRY_USER }}' --password-stdin"
|
||||||
ssh root@alpha.mintel.me "cd $SITE_DIR && docker compose -p '${{ needs.prepare.outputs.project_name }}' --env-file '$ENV_FILE' pull"
|
ssh root@infra.mintel.me "cd $SITE_DIR && docker compose -p '${{ needs.prepare.outputs.project_name }}' --env-file '$ENV_FILE' pull"
|
||||||
ssh root@alpha.mintel.me "cd $SITE_DIR && docker compose -p '${{ needs.prepare.outputs.project_name }}' --env-file '$ENV_FILE' up -d --remove-orphans"
|
ssh root@infra.mintel.me "cd $SITE_DIR && docker compose -p '${{ needs.prepare.outputs.project_name }}' --env-file '$ENV_FILE' up -d --remove-orphans"
|
||||||
|
|
||||||
ssh root@alpha.mintel.me "docker network prune -f"
|
ssh root@infra.mintel.me "docker network prune -f"
|
||||||
ssh root@alpha.mintel.me "docker system prune -f --filter 'until=24h'"
|
ssh root@infra.mintel.me "docker system prune -f --filter 'until=24h'"
|
||||||
|
|
||||||
- name: 🧹 Post-Deploy Cleanup (Runner)
|
- name: 🧹 Post-Deploy Cleanup (Runner)
|
||||||
if: always()
|
if: always()
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# Incident Ledger
|
||||||
|
|
||||||
|
One appended line per real incident. Never rewritten.
|
||||||
|
|
||||||
|
| Date | Area | Mechanism | Root cause | Remedy | Tier |
|
||||||
|
| :--------- | :------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--- |
|
||||||
|
| 2026-10-09 | Products / Niederspannungskabel | Five aluminium low-voltage products (NAYY, NAYCWY, NAY2Y, NA2XY, NA2X2Y) silently invisible on the site: dropped from category listing, 404 on detail pages, absent from sitemap | Commit 76cbdaa3 (2026-08-07, release 2.3.33 "NA Kabel Leiterklassen Fix") flattened frontmatter indentation of exactly these five files while removing RE/SE conductor shapes; broken YAML made the product loader return null and the site dropped them without any error | Restored valid frontmatter from 76cbdaa3~1 (content verified identical modulo indentation, whitespace-only diff), kept current markdown body incl. the RE/SE fix; regression spec tests/products-content.test.ts guards parseability and catalog visibility | M |
|
||||||
+1
-1
@@ -116,7 +116,7 @@
|
|||||||
"prepare": "husky",
|
"prepare": "husky",
|
||||||
"preinstall": "npx only-allow pnpm"
|
"preinstall": "npx only-allow pnpm"
|
||||||
},
|
},
|
||||||
"version": "2.3.37",
|
"version": "2.3.38",
|
||||||
"pnpm": {
|
"pnpm": {
|
||||||
"onlyBuiltDependencies": [
|
"onlyBuiltDependencies": [
|
||||||
"@parcel/watcher",
|
"@parcel/watcher",
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ fi
|
|||||||
# ── Configuration ──────────────────────────────────────────────────────────
|
# ── Configuration ──────────────────────────────────────────────────────────
|
||||||
SOURCE_ENV="${1:-}" # local | testing | staging | prod
|
SOURCE_ENV="${1:-}" # local | testing | staging | prod
|
||||||
TARGET_ENV="${2:-}" # testing | staging | prod
|
TARGET_ENV="${2:-}" # testing | staging | prod
|
||||||
SSH_HOST="root@alpha.mintel.me"
|
SSH_HOST="root@infra.mintel.me"
|
||||||
LOCAL_MEDIA_DIR="./public/media"
|
LOCAL_MEDIA_DIR="./public/media"
|
||||||
|
|
||||||
DRY_RUN=""
|
DRY_RUN=""
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import matter from 'gray-matter';
|
||||||
|
import { getAllProducts } from '../lib/products';
|
||||||
|
|
||||||
|
const productsDir = path.join(process.cwd(), 'content', 'products');
|
||||||
|
const productFiles = fs.readdirSync(productsDir).filter((f) => f.endsWith('.mdx'));
|
||||||
|
|
||||||
|
interface CatalogEntry {
|
||||||
|
slug: string;
|
||||||
|
parseable: boolean;
|
||||||
|
error?: string;
|
||||||
|
declaresImages: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Single parse pass at module load, mirroring the production loader's first
|
||||||
|
// touch of each file (gray-matter caches per input string, so re-parsing the
|
||||||
|
// same file inside individual tests would not re-throw parse errors).
|
||||||
|
const catalog: CatalogEntry[] = productFiles.map((file) => {
|
||||||
|
const raw = fs.readFileSync(path.join(productsDir, file), 'utf-8');
|
||||||
|
try {
|
||||||
|
const { data } = matter(raw);
|
||||||
|
return {
|
||||||
|
slug: file.replace('.mdx', ''),
|
||||||
|
parseable: true,
|
||||||
|
declaresImages: Array.isArray(data.images) && data.images.length > 0,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
slug: file.replace('.mdx', ''),
|
||||||
|
parseable: false,
|
||||||
|
error: `${file}: ${(error as Error).message.split('\n')[0]}`,
|
||||||
|
// An unparseable file cannot declare anything and must never silently
|
||||||
|
// shrink the expected catalog — require it to be listed.
|
||||||
|
declaresImages: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const ALUMINIUM_LOW_VOLTAGE_SLUGS = ['nayy', 'naycwy', 'nay2y', 'na2xy', 'na2x2y'];
|
||||||
|
|
||||||
|
describe('Product catalog content contract', () => {
|
||||||
|
it('every product file has parseable frontmatter', () => {
|
||||||
|
expect(catalog.filter((entry) => !entry.parseable).map((e) => e.error)).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('exposes every product that declares images in the catalog listing', async () => {
|
||||||
|
const expected = catalog
|
||||||
|
.filter((entry) => entry.declaresImages)
|
||||||
|
.map((e) => e.slug)
|
||||||
|
.sort();
|
||||||
|
const actual = (await getAllProducts('de')).map((p) => p.slug).sort();
|
||||||
|
expect(actual).toEqual(expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('lists all aluminium low-voltage cable types (NAYY, NAYCWY, NAY2Y, NA2XY, NA2X2Y)', async () => {
|
||||||
|
const slugs = (await getAllProducts('de')).map((p) => p.slug);
|
||||||
|
for (const slug of ALUMINIUM_LOW_VOLTAGE_SLUGS) {
|
||||||
|
expect(slugs).toContain(slug);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('categorizes the aluminium low-voltage types as Niederspannungskabel', async () => {
|
||||||
|
const products = await getAllProducts('de');
|
||||||
|
for (const slug of ALUMINIUM_LOW_VOLTAGE_SLUGS) {
|
||||||
|
const product = products.find((p) => p.slug === slug);
|
||||||
|
expect(product?.frontmatter.categories[0]).toBe('Niederspannungskabel');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user