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 <[email protected]>
This commit is contained in:
google-labs-jules[bot]andPR0M3TH3AN committed 2026-01-27 16:05:53 +00:00
1 parent 3b213a7643
commit 1726d27c77
2 files changed
+144 -2

No files matched your search

@@ -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"
+69 -2
View File
@@ -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);
}