From 1726d27c775e8c700da7e579c8a24eb9741e190d Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Tue, 27 Jan 2026 16:05:53 +0000 Subject: [PATCH] feat: Automate Daily Design System Audit - Added .github/workflows/daily-design-system-audit.yml - Updated scripts/daily-design-system-audit.mjs with auto-fix support - Implemented hex color and simple palette token replacements Co-authored-by: PR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> --- .../workflows/daily-design-system-audit.yml | 75 +++++++++++++++++++ scripts/daily-design-system-audit.mjs | 71 +++++++++++++++++- 2 files changed, 144 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/daily-design-system-audit.yml diff --git a/.github/workflows/daily-design-system-audit.yml b/.github/workflows/daily-design-system-audit.yml new file mode 100644 index 00000000..c16cffa3 --- /dev/null +++ b/.github/workflows/daily-design-system-audit.yml @@ -0,0 +1,75 @@ +name: Daily Design System Audit + +on: + schedule: + - cron: '0 9 * * *' # Run daily at 09:00 UTC + workflow_dispatch: + +permissions: + contents: write + issues: write + pull-requests: write + +jobs: + audit: + name: Audit Design System + runs-on: ubuntu-latest + steps: + - name: Checkout unstable branch + uses: actions/checkout@v4 + with: + ref: unstable + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + + - name: Verify gh CLI availability + run: gh --version + + - name: Install dependencies + run: npm ci + + - name: Run Design System Audit (with fix) + id: audit + run: node scripts/daily-design-system-audit.mjs --fix + continue-on-error: true + + - name: Check for changes + id: git-check + run: | + if [ -n "$(git status --porcelain)" ]; then + echo "changes=true" >> $GITHUB_OUTPUT + else + echo "changes=false" >> $GITHUB_OUTPUT + fi + + - name: Create Pull Request + if: steps.git-check.outputs.changes == 'true' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git checkout -b "ds-audit/$(date +%Y-%m-%d)" + git add . + git commit -m "chore: Apply daily design system remediation" + git push origin HEAD + gh pr create \ + --title "Daily Design System Remediation" \ + --body-file REMEDIATION_REPORT.md \ + --base unstable \ + --head "ds-audit/$(date +%Y-%m-%d)" \ + --label "design-system" + + - name: Create Issue on Failure (No Fixes) + if: steps.audit.outcome == 'failure' && steps.git-check.outputs.changes == 'false' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh issue create \ + --title "⚠️ Design System Violations Detected" \ + --body-file REMEDIATION_REPORT.md \ + --label "design-system" diff --git a/scripts/daily-design-system-audit.mjs b/scripts/daily-design-system-audit.mjs index 280c66a4..602d7860 100644 --- a/scripts/daily-design-system-audit.mjs +++ b/scripts/daily-design-system-audit.mjs @@ -1,9 +1,10 @@ #!/usr/bin/env node import { spawnSync } from "node:child_process"; -import { writeFileSync } from "node:fs"; +import { writeFileSync, readFileSync } from "node:fs"; const REPORT_FILE = "REMEDIATION_REPORT.md"; +const SHOULD_FIX = process.argv.includes("--fix"); const CHECKS = [ { name: "CSS", command: "npm", args: ["run", "lint:css"] }, @@ -162,6 +163,67 @@ function generateReport(violations) { return report; } +function applyAutoFixes(violations) { + console.log("Attempting to apply auto-fixes..."); + let fixesApplied = 0; + + const violationsByFile = {}; + + for (const category in violations) { + for (const v of violations[category]) { + const filePath = v.file.startsWith("./") ? v.file.slice(2) : v.file; + if (!violationsByFile[filePath]) violationsByFile[filePath] = []; + violationsByFile[filePath].push({ ...v, category }); + } + } + + for (const file of Object.keys(violationsByFile)) { + try { + let content = readFileSync(file, "utf8"); + let originalContent = content; + + for (const v of violationsByFile[file]) { + if (v.category === "Hex Colors") { + content = content.replaceAll("#000000", "var(--color-black)"); + content = content.replaceAll("#ffffff", "var(--color-white)"); + } + if (v.category === "Tailwind Palette") { + // Simple semantic mappings + if (v.value.includes("red-500")) { + const newValue = v.value.replace("red-500", "status-danger"); + content = content.replaceAll(v.value, newValue); + } + if (v.value.includes("green-500")) { + const newValue = v.value.replace("green-500", "status-success"); + content = content.replaceAll(v.value, newValue); + } + if (v.value.includes("blue-500")) { + const newValue = v.value.replace("blue-500", "status-info"); + content = content.replaceAll(v.value, newValue); + } + if (v.value.includes("yellow-500")) { + const newValue = v.value.replace("yellow-500", "status-warning"); + content = content.replaceAll(v.value, newValue); + } + } + } + + if (content !== originalContent) { + writeFileSync(file, content); + fixesApplied++; + console.log(`Fixed violations in ${file}`); + } + } catch (e) { + console.error(`Failed to fix ${file}: ${e.message}`); + } + } + + if (fixesApplied === 0) { + console.log("No auto-fixes available for current violations."); + } + return fixesApplied > 0; +} + async function main() { for (const check of CHECKS) { const { success, output } = runCheck(check); @@ -171,11 +233,16 @@ async function main() { } } + const totalViolations = Object.values(VIOLATIONS).reduce((acc, list) => acc + list.length, 0); + + if (totalViolations > 0 && SHOULD_FIX) { + applyAutoFixes(VIOLATIONS); + } + const report = generateReport(VIOLATIONS); writeFileSync(REPORT_FILE, report); console.log(`Report generated at ${REPORT_FILE}`); - const totalViolations = Object.values(VIOLATIONS).reduce((acc, list) => acc + list.length, 0); process.exit(totalViolations > 0 ? 1 : 0); }