mirror of
https://github.com/Dokploy/templates.git
synced 2026-07-08 23:45:24 +02:00
feat: per-template metadata — eliminate meta.json merge conflicts
- move each template's metadata to blueprints/<id>/meta.json (442 files, byte-identical roundtrip with the old root meta.json) - generate the served meta.json at build time into app/public/meta.json (gitignored); pnpm dev/build run the generator first - CI validates every blueprints/<id>/meta.json via generate-meta.js --check (required fields, id/folder match, logo exists, folder<->meta bidirectionality) and rejects any committed root meta.json - remove root meta.json, dedupe-and-sort-meta.js and build-scripts/process-meta.js (obsolete) - update CONTRIBUTING.md, AGENTS.md and README.md Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
81
.github/workflows/validate-meta.yml
vendored
81
.github/workflows/validate-meta.yml
vendored
@@ -1,12 +1,18 @@
|
||||
name: Validate and Process Meta.json
|
||||
name: Validate Template Metadata
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [canary]
|
||||
paths: ["meta.json"]
|
||||
paths:
|
||||
- "blueprints/**"
|
||||
- "build-scripts/generate-meta.js"
|
||||
- "meta.json"
|
||||
pull_request:
|
||||
branches: [canary]
|
||||
paths: ["meta.json"]
|
||||
paths:
|
||||
- "blueprints/**"
|
||||
- "build-scripts/generate-meta.js"
|
||||
- "meta.json"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
@@ -17,64 +23,19 @@ jobs:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Reject root meta.json
|
||||
run: |
|
||||
if [ -f "meta.json" ]; then
|
||||
echo "❌ The root meta.json is generated at build time and must not be committed."
|
||||
echo " Add your template's metadata to blueprints/<id>/meta.json instead."
|
||||
exit 1
|
||||
fi
|
||||
echo "✅ No root meta.json present"
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "18"
|
||||
node-version: "20"
|
||||
|
||||
- name: Validate meta.json structure
|
||||
run: |
|
||||
echo "🔍 Validating meta.json structure..."
|
||||
node -e "
|
||||
const fs = require('fs');
|
||||
const data = JSON.parse(fs.readFileSync('meta.json', 'utf8'));
|
||||
if (!Array.isArray(data)) throw new Error('meta.json must be an array');
|
||||
console.log('✅ meta.json structure is valid');
|
||||
console.log('📊 Found', data.length, 'entries');
|
||||
"
|
||||
|
||||
- name: Check for duplicates and sort order
|
||||
run: |
|
||||
echo "🔍 Checking for duplicates and sort order..."
|
||||
node build-scripts/process-meta.js --verbose --output /tmp/meta-test.json
|
||||
|
||||
- name: Compare with original
|
||||
run: |
|
||||
echo "🔍 Comparing processed file with original..."
|
||||
if ! diff -q meta.json /tmp/meta-test.json > /dev/null; then
|
||||
echo "⚠️ meta.json needs processing (duplicates found or not sorted)"
|
||||
echo "Original entries:"
|
||||
node -e "console.log(JSON.parse(require('fs').readFileSync('meta.json', 'utf8')).length)"
|
||||
echo "Processed entries:"
|
||||
node -e "console.log(JSON.parse(require('fs').readFileSync('/tmp/meta-test.json', 'utf8')).length)"
|
||||
echo ""
|
||||
echo "To fix this, run: npm run process-meta"
|
||||
exit 1
|
||||
else
|
||||
echo "✅ meta.json is properly deduplicated and sorted"
|
||||
fi
|
||||
|
||||
- name: Validate required fields
|
||||
run: |
|
||||
echo "🔍 Validating required fields..."
|
||||
node -e "
|
||||
const fs = require('fs');
|
||||
const data = JSON.parse(fs.readFileSync('meta.json', 'utf8'));
|
||||
const required = ['id', 'name', 'version', 'description', 'links', 'logo', 'tags'];
|
||||
let issues = 0;
|
||||
|
||||
data.forEach((item, index) => {
|
||||
const missing = required.filter(field => !item[field]);
|
||||
if (missing.length > 0) {
|
||||
console.log('❌ Entry', index, '(' + item.id + '):', 'Missing fields:', missing.join(', '));
|
||||
issues++;
|
||||
}
|
||||
});
|
||||
|
||||
if (issues > 0) {
|
||||
console.log('🚨 Found', issues, 'entries with missing required fields');
|
||||
process.exit(1);
|
||||
} else {
|
||||
console.log('✅ All entries have required fields');
|
||||
}
|
||||
"
|
||||
- name: Validate per-template metadata
|
||||
run: node build-scripts/generate-meta.js --check
|
||||
|
||||
135
.github/workflows/validate.yml
vendored
135
.github/workflows/validate.yml
vendored
@@ -49,133 +49,10 @@ jobs:
|
||||
echo "✅ Blueprint folders validated successfully."
|
||||
fi
|
||||
|
||||
- name: Validate meta.json structure and required fields
|
||||
run: |
|
||||
echo "🔍 Validating meta.json structure and required fields..."
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
|
||||
# First check if meta.json exists and is valid JSON
|
||||
if [ ! -f "meta.json" ]; then
|
||||
echo "❌ meta.json file not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! jq empty meta.json 2>/dev/null; then
|
||||
echo "❌ meta.json is not a valid JSON file"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ERROR=0
|
||||
ERRORS_FOUND=""
|
||||
|
||||
# Debug: Show total number of entries
|
||||
TOTAL_ENTRIES=$(jq '. | length' meta.json)
|
||||
echo "📊 Total entries in meta.json: $TOTAL_ENTRIES"
|
||||
|
||||
# Get all entries at once and process them
|
||||
TOTAL_INDEX=$(($TOTAL_ENTRIES - 1))
|
||||
|
||||
for i in $(seq 0 $TOTAL_INDEX); do
|
||||
entry=$(jq -c ".[$i]" meta.json)
|
||||
INDEX=$((i + 1))
|
||||
|
||||
echo "-------------------------------------------"
|
||||
echo "🔍 Checking entry #$INDEX..."
|
||||
|
||||
# Get the ID for better error reporting
|
||||
ID=$(echo "$entry" | jq -r '.id // "UNKNOWN"')
|
||||
echo "📝 Processing entry with ID: $ID"
|
||||
|
||||
# Validate required top-level fields
|
||||
for field in "id" "name" "version" "description" "logo" "links" "tags"; do
|
||||
if [ "$(echo "$entry" | jq "has(\"$field\")")" != "true" ]; then
|
||||
ERROR_MSG="❌ Entry #$INDEX (ID: $ID) is missing required field: $field"
|
||||
echo "$ERROR_MSG"
|
||||
ERRORS_FOUND="${ERRORS_FOUND}${ERROR_MSG}\n"
|
||||
ERROR=1
|
||||
fi
|
||||
done
|
||||
|
||||
# Validate links object required fields
|
||||
if [ "$(echo "$entry" | jq 'has("links")')" == "true" ]; then
|
||||
for link_field in "github" "website" "docs"; do
|
||||
if [ "$(echo "$entry" | jq ".links | has(\"$link_field\")")" != "true" ]; then
|
||||
ERROR_MSG="❌ Entry #$INDEX (ID: $ID): links object is missing required field: $link_field"
|
||||
echo "$ERROR_MSG"
|
||||
ERRORS_FOUND="${ERRORS_FOUND}${ERROR_MSG}\n"
|
||||
ERROR=1
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Validate tags array is not empty
|
||||
if [ "$(echo "$entry" | jq '.tags | length')" -eq 0 ]; then
|
||||
ERROR_MSG="❌ Entry #$INDEX (ID: $ID): tags array cannot be empty"
|
||||
echo "$ERROR_MSG"
|
||||
ERRORS_FOUND="${ERRORS_FOUND}${ERROR_MSG}\n"
|
||||
ERROR=1
|
||||
fi
|
||||
done
|
||||
|
||||
echo "-------------------------------------------"
|
||||
if [ $ERROR -eq 1 ]; then
|
||||
echo "❌ meta.json structure validation failed."
|
||||
echo -e "Summary of all errors found:${ERRORS_FOUND}"
|
||||
exit 1
|
||||
else
|
||||
echo "✅ meta.json structure validated successfully."
|
||||
fi
|
||||
|
||||
- name: Validate meta.json matches blueprint folders and logo files
|
||||
run: |
|
||||
echo "🔍 Validating meta.json against blueprint folders and logos..."
|
||||
|
||||
ERROR=0
|
||||
|
||||
# Read all blueprint folder names into an array
|
||||
FOLDERS=($(ls -1 blueprints))
|
||||
|
||||
# Extract ids and logos from meta.json
|
||||
IDS_AND_LOGOS=$(jq -c '.[] | {id, logo}' meta.json)
|
||||
|
||||
# Validate each id in meta.json exists as a folder
|
||||
for item in $IDS_AND_LOGOS; do
|
||||
ID=$(echo "$item" | jq -r '.id')
|
||||
LOGO=$(echo "$item" | jq -r '.logo')
|
||||
|
||||
# Check if folder exists
|
||||
if [ ! -d "blueprints/$ID" ]; then
|
||||
echo "❌ meta.json id \"$ID\" does not have a matching folder in blueprints/"
|
||||
ERROR=1
|
||||
continue
|
||||
fi
|
||||
|
||||
# Check if logo file exists inside its folder
|
||||
if [ ! -f "blueprints/$ID/$LOGO" ]; then
|
||||
echo "❌ Logo \"$LOGO\" defined for \"$ID\" does not exist in blueprints/$ID/"
|
||||
ERROR=1
|
||||
fi
|
||||
done
|
||||
|
||||
# Validate each folder has a matching id in meta.json
|
||||
META_IDS=$(jq -r '.[].id' meta.json)
|
||||
for FOLDER in "${FOLDERS[@]}"; do
|
||||
FOUND=0
|
||||
for ID in $META_IDS; do
|
||||
if [ "$FOLDER" == "$ID" ]; then
|
||||
FOUND=1
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$FOUND" -eq 0 ]; then
|
||||
echo "❌ Folder \"$FOLDER\" has no matching id in meta.json"
|
||||
ERROR=1
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $ERROR -eq 1 ]; then
|
||||
echo "❌ meta.json validation failed."
|
||||
exit 1
|
||||
else
|
||||
echo "✅ meta.json validated successfully."
|
||||
fi
|
||||
- name: Validate per-template metadata (blueprints/<id>/meta.json)
|
||||
run: node build-scripts/generate-meta.js --check
|
||||
|
||||
Reference in New Issue
Block a user