From a950ecefae7235895af3b5944dcb08909f514809 Mon Sep 17 00:00:00 2001 From: Tori Whaley Date: Thu, 8 Jan 2026 14:44:08 -0500 Subject: [PATCH 1/3] scripts automation (check links + images) --- .github/workflows/validate-docs.yml | 75 ++++++++ scripts/check-image-locations.js | 274 ++++++++++++++++++++++++++++ scripts/check-links.js | 2 +- 3 files changed, 350 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/validate-docs.yml create mode 100755 scripts/check-image-locations.js diff --git a/.github/workflows/validate-docs.yml b/.github/workflows/validate-docs.yml new file mode 100644 index 00000000..6da35eee --- /dev/null +++ b/.github/workflows/validate-docs.yml @@ -0,0 +1,75 @@ +name: Validate Documentation + +on: + pull_request: + branches: + - main + paths: + - '**.mdx' + - '**.md' + - 'images/**' + - 'scripts/**' + - '.github/workflows/validate-docs.yml' + +jobs: + validate: + name: Check Links and Images + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '18' + + - name: Check for broken links + id: check-links + run: | + echo "::group::Checking for broken links" + node scripts/check-links.js + echo "::endgroup::" + continue-on-error: true + + - name: Check image locations + id: check-images + run: | + echo "::group::Checking image locations" + node scripts/check-image-locations.js + echo "::endgroup::" + continue-on-error: true + + - name: Report results + if: steps.check-links.outcome == 'failure' || steps.check-images.outcome == 'failure' + run: | + echo "## Documentation Validation Failed āŒ" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + if [ "${{ steps.check-links.outcome }}" == "failure" ]; then + echo "### Broken Links Found šŸ”—" >> $GITHUB_STEP_SUMMARY + echo "Please fix the broken links identified above." >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + fi + + if [ "${{ steps.check-images.outcome }}" == "failure" ]; then + echo "### Image Location Issues Found šŸ–¼ļø" >> $GITHUB_STEP_SUMMARY + echo "Images must mirror the page structure. See [CONTRIBUTING.md](../CONTRIBUTING.md#image-guidelines) for guidelines." >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + fi + + echo "---" >> $GITHUB_STEP_SUMMARY + echo "šŸ’” **Quick Reference:**" >> $GITHUB_STEP_SUMMARY + echo "- A page at \`guides/dashboard.mdx\` should use images from \`images/guides/dashboard/\`" >> $GITHUB_STEP_SUMMARY + echo "- Shared images can be placed in parent directories" >> $GITHUB_STEP_SUMMARY + echo "- All internal links must point to existing files" >> $GITHUB_STEP_SUMMARY + + exit 1 + + - name: Success message + if: steps.check-links.outcome == 'success' && steps.check-images.outcome == 'success' + run: | + echo "## Documentation Validation Passed āœ…" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "All links are valid and images are in the correct locations!" >> $GITHUB_STEP_SUMMARY diff --git a/scripts/check-image-locations.js b/scripts/check-image-locations.js new file mode 100755 index 00000000..c26a71b7 --- /dev/null +++ b/scripts/check-image-locations.js @@ -0,0 +1,274 @@ +#!/usr/bin/env node + +/** + * Validates that images are placed in the correct directory structure + * Images should mirror the page structure as defined in CONTRIBUTING.md + * + * Rules: + * - A page at guides/dashboard.mdx should use images from images/guides/dashboard/ + * - Shared images can be in parent folders + * - All images must exist + * + * Run: node scripts/check-image-locations.js + */ + +const fs = require('fs'); +const path = require('path'); + +// Regex patterns for finding image references +const MARKDOWN_IMAGE_REGEX = /!\[([^\]]*)\]\(([^)]+)\)/g; +const JSX_IMG_SRC_REGEX = /]+src=["']([^"']+)["']/g; +const FRAME_IMG_REGEX = /]*>[\s\S]*?]+src=["']([^"']+)["']/g; + +const VALID_IMAGE_EXTENSIONS = ['.png', '.jpg', '.jpeg', '.gif', '.svg', '.webp']; + +function findMDXFiles(dir, fileList = []) { + const files = fs.readdirSync(dir); + + files.forEach(file => { + const filePath = path.join(dir, file); + const stat = fs.statSync(filePath); + + if (stat.isDirectory() && !file.startsWith('.') && file !== 'node_modules') { + findMDXFiles(filePath, fileList); + } else if (file.endsWith('.mdx') || file.endsWith('.md')) { + fileList.push(filePath); + } + }); + + return fileList; +} + +function extractImageReferences(content, filePath) { + const images = []; + + // Extract markdown images: ![alt](path) + let match; + while ((match = MARKDOWN_IMAGE_REGEX.exec(content)) !== null) { + const imagePath = match[2]; + if (!imagePath.startsWith('http://') && !imagePath.startsWith('https://')) { + images.push({ + alt: match[1], + path: imagePath, + type: 'markdown', + line: content.substring(0, match.index).split('\n').length + }); + } + } + + // Extract JSX image src + while ((match = JSX_IMG_SRC_REGEX.exec(content)) !== null) { + const imagePath = match[1]; + if (!imagePath.startsWith('http://') && !imagePath.startsWith('https://')) { + images.push({ + path: imagePath, + type: 'jsx', + line: content.substring(0, match.index).split('\n').length + }); + } + } + + return images; +} + +function getExpectedImageDirectory(mdxFilePath) { + // Get path relative to project root + const relativePath = path.relative(process.cwd(), mdxFilePath); + + // Remove file extension + const withoutExt = relativePath.replace(/\.(mdx|md)$/, ''); + + // Convert to expected image path + // e.g., guides/dashboard.mdx -> images/guides/dashboard/ + // e.g., get-started/setup.mdx -> images/get-started/setup/ + return path.join('images', withoutExt); +} + +function validateImageLocation(imagePath, mdxFilePath) { + const issues = []; + + // Resolve absolute path for image + let absoluteImagePath; + if (imagePath.startsWith('/')) { + // Absolute path from project root + absoluteImagePath = path.join(process.cwd(), imagePath.substring(1)); + } else { + // Relative path from MDX file + absoluteImagePath = path.join(path.dirname(mdxFilePath), imagePath); + } + + // Check if image exists + if (!fs.existsSync(absoluteImagePath)) { + issues.push({ + type: 'missing', + message: 'Image file does not exist', + imagePath: imagePath, + absolutePath: absoluteImagePath + }); + return issues; // No point checking location if file doesn't exist + } + + // Check if it's actually an image file + const ext = path.extname(absoluteImagePath).toLowerCase(); + if (!VALID_IMAGE_EXTENSIONS.includes(ext)) { + issues.push({ + type: 'invalid-type', + message: `Invalid file extension: ${ext}. Expected: ${VALID_IMAGE_EXTENSIONS.join(', ')}`, + imagePath: imagePath + }); + } + + // Get expected directory + const expectedDir = getExpectedImageDirectory(mdxFilePath); + + // Get actual directory of the image (relative to project root) + let imageDir; + if (imagePath.startsWith('/')) { + imageDir = path.dirname(imagePath.substring(1)); + } else { + // Convert to absolute then back to relative from project root + const relativeImagePath = path.relative(process.cwd(), absoluteImagePath); + imageDir = path.dirname(relativeImagePath); + } + + // Check if image is in the expected directory or a valid parent directory + const isInExpectedDir = imageDir === expectedDir; + const isInParentDir = expectedDir.startsWith(imageDir + path.sep) || expectedDir === imageDir; + + // Special case: logo and favicon can be in root + const isSpecialFile = imagePath.includes('/logo/') || + imagePath.includes('favicon') || + imagePath.includes('/snippets/'); + + if (!isInExpectedDir && !isInParentDir && !isSpecialFile) { + // Check if it's in a valid parent directory (shared images) + const expectedParts = expectedDir.split(path.sep); + const imageParts = imageDir.split(path.sep); + + // Allow if image is in a parent directory of the expected path + const isValidParent = expectedParts.length > imageParts.length && + expectedParts.slice(0, imageParts.length).join(path.sep) === imageDir; + + if (!isValidParent) { + issues.push({ + type: 'wrong-location', + message: 'Image is not in the correct directory', + imagePath: imagePath, + expectedDir: expectedDir, + actualDir: imageDir, + suggestion: `Move to ${expectedDir}/ or a shared parent directory` + }); + } + } + + return issues; +} + +function getRelativePath(filePath) { + return path.relative(process.cwd(), filePath).replace(/\\/g, '/'); +} + +async function main() { + console.log('šŸ–¼ļø Checking image locations in documentation...\n'); + + const mdxFiles = findMDXFiles('.'); + const excludedPaths = ['node_modules', '.git', 'snippets', 'CONTRIBUTING.md']; + const filteredFiles = mdxFiles.filter(file => + !excludedPaths.some(excluded => file.includes(excluded)) + ); + + console.log(`šŸ“„ Found ${filteredFiles.length} documentation files\n`); + + const allIssues = []; + let totalImages = 0; + let missingImages = 0; + let misplacedImages = 0; + let invalidTypes = 0; + + // Check images in each file + for (const file of filteredFiles) { + const content = fs.readFileSync(file, 'utf8'); + const images = extractImageReferences(content, file); + const relativePath = getRelativePath(file); + + for (const image of images) { + totalImages++; + + const issues = validateImageLocation(image.path, file); + + if (issues.length > 0) { + issues.forEach(issue => { + allIssues.push({ + file: relativePath, + line: image.line, + ...issue + }); + + if (issue.type === 'missing') missingImages++; + if (issue.type === 'wrong-location') misplacedImages++; + if (issue.type === 'invalid-type') invalidTypes++; + }); + } + } + } + + // Display results + if (allIssues.length === 0) { + console.log('āœ… All images are in the correct locations!\n'); + } else { + console.log(`āŒ Found ${allIssues.length} image issues:\n`); + + // Group by issue type + const missingIssues = allIssues.filter(i => i.type === 'missing'); + const locationIssues = allIssues.filter(i => i.type === 'wrong-location'); + const typeIssues = allIssues.filter(i => i.type === 'invalid-type'); + + if (missingIssues.length > 0) { + console.log(`šŸ“ Missing Images (${missingIssues.length}):\n`); + missingIssues.forEach(({ file, line, imagePath, message }) => { + console.log(` šŸ“„ ${file}:${line}`); + console.log(` šŸ”— ${imagePath}`); + console.log(` āŒ ${message}\n`); + }); + } + + if (locationIssues.length > 0) { + console.log(`šŸ“ Misplaced Images (${locationIssues.length}):\n`); + locationIssues.forEach(({ file, line, imagePath, expectedDir, actualDir, suggestion }) => { + console.log(` šŸ“„ ${file}:${line}`); + console.log(` šŸ”— ${imagePath}`); + console.log(` āŒ Expected in: ${expectedDir}/`); + console.log(` šŸ“ Actually in: ${actualDir}/`); + console.log(` šŸ’” ${suggestion}\n`); + }); + } + + if (typeIssues.length > 0) { + console.log(`āš ļø Invalid File Types (${typeIssues.length}):\n`); + typeIssues.forEach(({ file, line, imagePath, message }) => { + console.log(` šŸ“„ ${file}:${line}`); + console.log(` šŸ”— ${imagePath}`); + console.log(` āŒ ${message}\n`); + }); + } + } + + // Summary + console.log('─'.repeat(60)); + console.log(`Total images checked: ${totalImages}`); + console.log(`Missing images: ${missingImages}`); + console.log(`Misplaced images: ${misplacedImages}`); + console.log(`Invalid file types: ${invalidTypes}`); + console.log('─'.repeat(60)); + + console.log('\nšŸ’” Image Placement Rules:'); + console.log(' • Images should mirror page structure'); + console.log(' • guides/dashboard.mdx → images/guides/dashboard/'); + console.log(' • Shared images can be in parent directories'); + console.log(' • See CONTRIBUTING.md for full guidelines\n'); + + // Exit with error if issues found + process.exit(allIssues.length > 0 ? 1 : 0); +} + +main(); diff --git a/scripts/check-links.js b/scripts/check-links.js index ec0acee2..8b01657d 100644 --- a/scripts/check-links.js +++ b/scripts/check-links.js @@ -208,7 +208,7 @@ async function main() { console.log('šŸ” Checking for broken links in documentation...\n'); const mdxFiles = findMDXFiles('.'); - const excludedPaths = ['node_modules', '.git']; + const excludedPaths = ['node_modules', '.git', 'CONTRIBUTING.md']; const filteredFiles = mdxFiles.filter(file => !excludedPaths.some(excluded => file.includes(excluded)) ); From 98c8ec37de5697404b800667c71b7bcb64533686 Mon Sep 17 00:00:00 2001 From: Tori Whaley Date: Thu, 8 Jan 2026 14:51:43 -0500 Subject: [PATCH 2/3] last scripts check --- .github/workflows/validate-docs.yml | 51 +++++++++++++-------------- scripts/check-links.js | 53 ++++++++++++++++++++++++++++- 2 files changed, 78 insertions(+), 26 deletions(-) diff --git a/.github/workflows/validate-docs.yml b/.github/workflows/validate-docs.yml index 6da35eee..862a4ccb 100644 --- a/.github/workflows/validate-docs.yml +++ b/.github/workflows/validate-docs.yml @@ -42,34 +42,35 @@ jobs: continue-on-error: true - name: Report results - if: steps.check-links.outcome == 'failure' || steps.check-images.outcome == 'failure' + if: always() run: | - echo "## Documentation Validation Failed āŒ" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - - if [ "${{ steps.check-links.outcome }}" == "failure" ]; then - echo "### Broken Links Found šŸ”—" >> $GITHUB_STEP_SUMMARY - echo "Please fix the broken links identified above." >> $GITHUB_STEP_SUMMARY + if [ "${{ steps.check-links.outcome }}" == "failure" ] || [ "${{ steps.check-images.outcome }}" == "failure" ]; then + echo "## Documentation Validation Warnings āš ļø" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY - fi - - if [ "${{ steps.check-images.outcome }}" == "failure" ]; then - echo "### Image Location Issues Found šŸ–¼ļø" >> $GITHUB_STEP_SUMMARY - echo "Images must mirror the page structure. See [CONTRIBUTING.md](../CONTRIBUTING.md#image-guidelines) for guidelines." >> $GITHUB_STEP_SUMMARY + echo "The following issues were found. Please review and fix when possible:" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY - fi - echo "---" >> $GITHUB_STEP_SUMMARY - echo "šŸ’” **Quick Reference:**" >> $GITHUB_STEP_SUMMARY - echo "- A page at \`guides/dashboard.mdx\` should use images from \`images/guides/dashboard/\`" >> $GITHUB_STEP_SUMMARY - echo "- Shared images can be placed in parent directories" >> $GITHUB_STEP_SUMMARY - echo "- All internal links must point to existing files" >> $GITHUB_STEP_SUMMARY + if [ "${{ steps.check-links.outcome }}" == "failure" ]; then + echo "### Broken Links Found šŸ”—" >> $GITHUB_STEP_SUMMARY + echo "See the check-links step above for details." >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + fi - exit 1 + if [ "${{ steps.check-images.outcome }}" == "failure" ]; then + echo "### Image Location Issues Found šŸ–¼ļø" >> $GITHUB_STEP_SUMMARY + echo "Images should mirror the page structure. See the check-images step above for details." >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + fi - - name: Success message - if: steps.check-links.outcome == 'success' && steps.check-images.outcome == 'success' - run: | - echo "## Documentation Validation Passed āœ…" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "All links are valid and images are in the correct locations!" >> $GITHUB_STEP_SUMMARY + echo "---" >> $GITHUB_STEP_SUMMARY + echo "šŸ’” **Quick Reference:**" >> $GITHUB_STEP_SUMMARY + echo "- A page at \`guides/dashboard.mdx\` should use images from \`images/guides/dashboard/\`" >> $GITHUB_STEP_SUMMARY + echo "- Shared images can be placed in parent directories" >> $GITHUB_STEP_SUMMARY + echo "- All internal links must point to existing files" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "ā„¹ļø **Note:** These are informational warnings and will not block your PR from merging." >> $GITHUB_STEP_SUMMARY + else + echo "## Documentation Validation Passed āœ…" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "All links are valid and images are in the correct locations!" >> $GITHUB_STEP_SUMMARY + fi diff --git a/scripts/check-links.js b/scripts/check-links.js index 8b01657d..0718fcd0 100644 --- a/scripts/check-links.js +++ b/scripts/check-links.js @@ -204,6 +204,39 @@ function findOrphanedPages(allMdxFiles, docsJson) { return orphans; } +function extractRedirects(docsJson) { + if (!docsJson || !docsJson.redirects) return []; + return docsJson.redirects.map(r => ({ + source: r.source.startsWith('/') ? r.source.substring(1) : r.source, + destination: r.destination.startsWith('/') ? r.destination.substring(1) : r.destination + })); +} + +function validateRedirects(redirects) { + const issues = []; + + redirects.forEach(redirect => { + // Check if destination exists + const possiblePaths = [ + path.join(process.cwd(), redirect.destination), + path.join(process.cwd(), redirect.destination + '.mdx'), + path.join(process.cwd(), redirect.destination + '.md'), + ]; + + const exists = possiblePaths.some(p => fs.existsSync(p)); + + if (!exists) { + issues.push({ + source: redirect.source, + destination: redirect.destination, + issue: 'Redirect destination does not exist' + }); + } + }); + + return issues; +} + async function main() { console.log('šŸ” Checking for broken links in documentation...\n'); @@ -256,6 +289,11 @@ async function main() { const docsJson = loadDocsJson(); const orphanedPages = findOrphanedPages(filteredFiles, docsJson); + // Check redirects + console.log('šŸ” Checking redirects in docs.json...\n'); + const redirects = extractRedirects(docsJson); + const redirectIssues = validateRedirects(redirects); + // Display results if (brokenLinks.length === 0) { console.log('āœ… No broken internal links found!\n'); @@ -287,6 +325,18 @@ async function main() { console.log('\nšŸ’” These pages exist but are not linked in docs.json navigation.\n'); } + // Display redirect issues + if (redirectIssues.length === 0) { + console.log('āœ… All redirects are valid!\n'); + } else { + console.log(`āŒ Found ${redirectIssues.length} invalid redirects in docs.json:\n`); + redirectIssues.forEach(({ source, destination, issue }) => { + console.log(` šŸ”€ ${source} → ${destination}`); + console.log(` āŒ ${issue}\n`); + }); + console.log('šŸ’” When moving pages, ensure redirect destinations exist.\n'); + } + // Check external links if requested if (CHECK_EXTERNAL && externalLinks.length > 0) { console.log(`🌐 Checking ${externalLinks.length} external links...\n`); @@ -317,13 +367,14 @@ async function main() { console.log(`Total links checked: ${totalLinks}`); console.log(`Broken internal links: ${brokenLinks.length}`); console.log(`Orphaned pages: ${orphanedPages.length}`); + console.log(`Invalid redirects: ${redirectIssues.length}`); if (CHECK_EXTERNAL) { console.log(`External links checked: ${externalLinks.length}`); } console.log('─'.repeat(60)); // Exit with error if issues found - const hasIssues = brokenLinks.length > 0 || orphanedPages.length > 0; + const hasIssues = brokenLinks.length > 0 || orphanedPages.length > 0 || redirectIssues.length > 0; process.exit(hasIssues ? 1 : 0); } From 110af7dae652eb0e5e735425bfb622a53d416603 Mon Sep 17 00:00:00 2001 From: Tori Whaley Date: Thu, 8 Jan 2026 15:06:32 -0500 Subject: [PATCH 3/3] update warning messge --- .github/workflows/validate-docs.yml | 85 ++++++++++++++++++++--------- 1 file changed, 60 insertions(+), 25 deletions(-) diff --git a/.github/workflows/validate-docs.yml b/.github/workflows/validate-docs.yml index 862a4ccb..0538c9df 100644 --- a/.github/workflows/validate-docs.yml +++ b/.github/workflows/validate-docs.yml @@ -29,7 +29,8 @@ jobs: id: check-links run: | echo "::group::Checking for broken links" - node scripts/check-links.js + node scripts/check-links.js > /tmp/check-links-output.txt 2>&1 || echo "issues_found=true" >> $GITHUB_OUTPUT + cat /tmp/check-links-output.txt echo "::endgroup::" continue-on-error: true @@ -37,38 +38,72 @@ jobs: id: check-images run: | echo "::group::Checking image locations" - node scripts/check-image-locations.js + node scripts/check-image-locations.js > /tmp/check-images-output.txt 2>&1 || echo "issues_found=true" >> $GITHUB_OUTPUT + cat /tmp/check-images-output.txt echo "::endgroup::" continue-on-error: true + - name: Post PR comment + if: steps.check-links.outputs.issues_found == 'true' || steps.check-images.outputs.issues_found == 'true' + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + + let comment = '## šŸ“‹ Documentation Validation Report\n\n'; + comment += 'āš ļø Some issues were found in this PR. These are **informational warnings** and will not block merging.\n\n'; + + if ('${{ steps.check-links.outputs.issues_found }}' === 'true') { + const linksOutput = fs.readFileSync('/tmp/check-links-output.txt', 'utf8'); + const lines = linksOutput.split('\n'); + const brokenLinks = lines.filter(line => line.includes('Broken link:') || line.includes('šŸ“„')).slice(0, 10); + + comment += '### šŸ”— Links\n'; + if (brokenLinks.length > 0) { + comment += '
āŒ Found broken links (click to expand)\n\n'; + comment += '```\n' + brokenLinks.join('\n') + '\n```\n'; + comment += '
\n\n'; + } + } else { + comment += '### šŸ”— Links\nāœ… All links valid\n\n'; + } + + if ('${{ steps.check-images.outputs.issues_found }}' === 'true') { + const imagesOutput = fs.readFileSync('/tmp/check-images-output.txt', 'utf8'); + const lines = imagesOutput.split('\n'); + const imageIssues = lines.filter(line => line.includes('šŸ“„') || line.includes('Expected in:')).slice(0, 10); + + comment += '### šŸ–¼ļø Images\n'; + if (imageIssues.length > 0) { + comment += '
āŒ Found image location issues (click to expand)\n\n'; + comment += '```\n' + imageIssues.join('\n') + '\n```\n'; + comment += '
\n\n'; + } + } else { + comment += '### šŸ–¼ļø Images\nāœ… All images in correct locations\n\n'; + } + + comment += '---\n'; + comment += 'šŸ’” **Quick Reference:**\n'; + comment += '- A page at `guides/dashboard.mdx` should use images from `images/guides/dashboard/`\n'; + comment += '- Shared images can be placed in parent directories\n'; + comment += '- All internal links must point to existing files\n\n'; + comment += 'šŸ“– Run `node scripts/check-links.js` and `node scripts/check-image-locations.js` locally for full details.\n'; + + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: comment + }); + - name: Report results if: always() run: | - if [ "${{ steps.check-links.outcome }}" == "failure" ] || [ "${{ steps.check-images.outcome }}" == "failure" ]; then + if [ "${{ steps.check-links.outputs.issues_found }}" == "true" ] || [ "${{ steps.check-images.outputs.issues_found }}" == "true" ]; then echo "## Documentation Validation Warnings āš ļø" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY - echo "The following issues were found. Please review and fix when possible:" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - - if [ "${{ steps.check-links.outcome }}" == "failure" ]; then - echo "### Broken Links Found šŸ”—" >> $GITHUB_STEP_SUMMARY - echo "See the check-links step above for details." >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - fi - - if [ "${{ steps.check-images.outcome }}" == "failure" ]; then - echo "### Image Location Issues Found šŸ–¼ļø" >> $GITHUB_STEP_SUMMARY - echo "Images should mirror the page structure. See the check-images step above for details." >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - fi - - echo "---" >> $GITHUB_STEP_SUMMARY - echo "šŸ’” **Quick Reference:**" >> $GITHUB_STEP_SUMMARY - echo "- A page at \`guides/dashboard.mdx\` should use images from \`images/guides/dashboard/\`" >> $GITHUB_STEP_SUMMARY - echo "- Shared images can be placed in parent directories" >> $GITHUB_STEP_SUMMARY - echo "- All internal links must point to existing files" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "ā„¹ļø **Note:** These are informational warnings and will not block your PR from merging." >> $GITHUB_STEP_SUMMARY + echo "Issues found - see PR comment for details" >> $GITHUB_STEP_SUMMARY else echo "## Documentation Validation Passed āœ…" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY