Skip to content

Change badge styles in README.md #223

Change badge styles in README.md

Change badge styles in README.md #223

name: Prettier Code Format Check
on:
push:
branches: [main, develop]
paths:
- "**/*.js"
- "**/*.ts"
- "**/*.jsx"
- "**/*.tsx"
- "**/*.css"
- "**/*.json"
- "**/*.md"
- "**/*.yml"
- "**/*.yaml"
- ".prettierrc"
- ".prettierignore"
- "package.json"
- "package-lock.json"
- "pnpm-lock.yaml"
- "yarn.lock"
- ".github/workflows/prettier-code-format-check.yml"
pull_request:
branches: [main, develop]
paths:
- "**/*.js"
- "**/*.ts"
- "**/*.jsx"
- "**/*.tsx"
- "**/*.css"
- "**/*.json"
- "**/*.md"
- "**/*.yml"
- "**/*.yaml"
- ".prettierrc"
- ".prettierignore"
- "package.json"
- "package-lock.json"
- "pnpm-lock.yaml"
- "yarn.lock"
- ".github/workflows/prettier-code-format-check.yml"
workflow_dispatch:
concurrency:
group: prettier-check-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
prettier:
name: "💅 Prettier Code Format Validation"
runs-on: ubuntu-latest
timeout-minutes: 15
env:
# "true" => report-only (never fail CI)
# "false" => enforce formatting (fail CI on issues)
ALLOW_WARNINGS: "true"
# If Prettier is missing from devDependencies, CI can install a pinned version temporarily.
BOOTSTRAP_PRETTIER_IF_MISSING: "true"
PRETTIER_VERSION: "3.3.3"
PRETTIER_REPORT: "prettier-report.txt"
PRETTIER_SUMMARY: "prettier-summary.md"
NPM_DEBUG_LOG: "npm-debug.log"
steps:
- name: "📦 Checkout Repository"
uses: actions/checkout@v4
- name: "🧾 Detect Package Manager + Tooling"
id: pm
shell: bash
run: |
set -euo pipefail
if [[ -f pnpm-lock.yaml ]]; then
echo "manager=pnpm" >> "$GITHUB_OUTPUT"
elif [[ -f yarn.lock ]]; then
echo "manager=yarn" >> "$GITHUB_OUTPUT"
elif [[ -f package-lock.json ]]; then
echo "manager=npm" >> "$GITHUB_OUTPUT"
else
echo "manager=npm" >> "$GITHUB_OUTPUT"
fi
if [[ -f package.json ]]; then
echo "has_package_json=true" >> "$GITHUB_OUTPUT"
else
echo "has_package_json=false" >> "$GITHUB_OUTPUT"
fi
- name: "⚙️ Setup Node.js (LTS) + Cache"
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "${{ steps.pm.outputs.manager }}"
- name: "📥 Install Dependencies (only if package.json exists)"
id: install
if: "${{ steps.pm.outputs.has_package_json == 'true' }}"
shell: bash
run: |
set -euo pipefail
mgr="${{ steps.pm.outputs.manager }}"
if [[ "$mgr" == "pnpm" ]]; then
corepack enable
pnpm --version
pnpm install --frozen-lockfile
elif [[ "$mgr" == "yarn" ]]; then
corepack enable
yarn --version
# Yarn Berry uses --immutable; Yarn classic ignores it but won't break
yarn install --immutable || yarn install
else
if [[ -f package-lock.json ]]; then
npm ci
else
echo "::warning::No lockfile found. Using 'npm install' (non-deterministic)."
npm install
fi
fi
- name: "🧰 Ensure Prettier Available"
id: ensure_prettier
shell: bash
run: |
set -euo pipefail
if [[ -x "node_modules/.bin/prettier" ]]; then
echo "prettier_present=true" >> "$GITHUB_OUTPUT"
echo "prettier_source=project" >> "$GITHUB_OUTPUT"
exit 0
fi
if [[ "${BOOTSTRAP_PRETTIER_IF_MISSING}" != "true" ]]; then
echo "prettier_present=false" >> "$GITHUB_OUTPUT"
echo "prettier_source=missing" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "::notice::Prettier not found in node_modules. Bootstrapping Prettier v${PRETTIER_VERSION} for CI-only run."
# CI-only install (runner workspace only; no commits)
npm install --no-save "prettier@${PRETTIER_VERSION}"
if [[ -x "node_modules/.bin/prettier" ]]; then
echo "prettier_present=true" >> "$GITHUB_OUTPUT"
echo "prettier_source=ci-bootstrap" >> "$GITHUB_OUTPUT"
else
echo "prettier_present=false" >> "$GITHUB_OUTPUT"
echo "prettier_source=bootstrap-failed" >> "$GITHUB_OUTPUT"
fi
- name: "🧾 Build file list (tracked files only)"
id: files
shell: bash
run: |
set -euo pipefail
git ls-files -z \
'*.js' '*.ts' '*.jsx' '*.tsx' \
'*.css' '*.json' '*.md' \
'*.yml' '*.yaml' \
> prettier-files.txt || true
if [[ ! -s prettier-files.txt ]]; then
echo "count=0" >> "$GITHUB_OUTPUT"
exit 0
fi
# Count NUL-separated entries safely
count="$(tr -cd '\0' < prettier-files.txt | wc -c | tr -d ' ')"
echo "count=${count}" >> "$GITHUB_OUTPUT"
- name: "🔍 Run Prettier Check (tracked files)"
id: run_prettier
shell: bash
run: |
set -euo pipefail
report="${PRETTIER_REPORT}"
: > "$report"
prettier_present="${{ steps.ensure_prettier.outputs.prettier_present }}"
files_count="${{ steps.files.outputs.count }}"
if [[ "${prettier_present}" != "true" ]]; then
echo "Prettier not available in this run." > "$report"
echo "exit_code=2" >> "$GITHUB_OUTPUT"
exit 0
fi
if [[ "${files_count}" == "0" ]]; then
echo "No tracked files matched the Prettier file patterns." > "$report"
echo "exit_code=0" >> "$GITHUB_OUTPUT"
exit 0
fi
# Run local prettier directly (avoid npx ambiguity)
set +e
cat prettier-files.txt | xargs -0 node_modules/.bin/prettier --ignore-unknown --check > "$report" 2>&1
ec="$?"
set -e
echo "exit_code=$ec" >> "$GITHUB_OUTPUT"
echo "Prettier exit code: $ec"
- name: "🧾 Capture npm debug log (if any)"
if: always()
shell: bash
run: |
set -euo pipefail
if compgen -G "/home/runner/.npm/_logs/*-debug-0.log" > /dev/null; then
latest="$(ls -t /home/runner/.npm/_logs/*-debug-0.log | head -n 1)"
cp "$latest" "${NPM_DEBUG_LOG}" || true
else
echo "No npm debug log found." > "${NPM_DEBUG_LOG}"
fi
- name: "📄 Generate Job Summary"
if: always()
shell: bash
run: |
set -euo pipefail
exit_code="${{ steps.run_prettier.outputs.exit_code }}"
prettier_present="${{ steps.ensure_prettier.outputs.prettier_present }}"
prettier_source="${{ steps.ensure_prettier.outputs.prettier_source }}"
mgr="${{ steps.pm.outputs.manager }}"
has_pkg="${{ steps.pm.outputs.has_package_json }}"
files_count="${{ steps.files.outputs.count }}"
{
echo "### 💅 Prettier Format Summary"
echo
echo "- **Workflow:** \`${GITHUB_WORKFLOW}\`"
echo "- **Event:** \`${GITHUB_EVENT_NAME}\`"
echo "- **Ref:** \`${GITHUB_REF}\`"
echo "- **Commit:** \`${GITHUB_SHA}\`"
echo "- **Package manager:** \`${mgr}\`"
echo "- **package.json:** \`${has_pkg}\`"
echo "- **Files checked (tracked):** \`${files_count}\`"
echo "- **Exit code:** \`${exit_code}\`"
echo "- **ALLOW_WARNINGS:** \`${ALLOW_WARNINGS}\`"
echo "- **Prettier available:** \`${prettier_present}\`"
echo "- **Prettier source:** \`${prettier_source}\`"
echo
if [[ "${prettier_present}" != "true" ]]; then
echo "❗ Prettier was not available, so formatting was not checked."
echo
echo "**Fix (recommended):** add Prettier to devDependencies:"
echo
echo '```bash'
echo 'npm i -D prettier'
echo '```'
elif [[ "$exit_code" != "0" ]]; then
echo "⚠️ Formatting issues detected."
echo
echo "**Top 120 lines:**"
echo
echo '```text'
head -n 120 "${PRETTIER_REPORT}" || true
echo '```'
echo
echo "_Output truncated. Download artifacts for the full report._"
echo
echo "**Fix locally:**"
echo
echo '```bash'
echo 'npx prettier --write .'
echo '```'
else
echo "✅ No formatting issues found."
fi
} | tee "${PRETTIER_SUMMARY}" >> "$GITHUB_STEP_SUMMARY"
- name: "📦 Upload Artifacts"
if: always()
uses: actions/upload-artifact@v4
with:
name: prettier-format-report
path: |
${{ env.PRETTIER_REPORT }}
${{ env.PRETTIER_SUMMARY }}
${{ env.NPM_DEBUG_LOG }}
prettier-files.txt
retention-days: 30
- name: "✅ Policy Gate"
if: always()
shell: bash
run: |
set -euo pipefail
if [[ "${ALLOW_WARNINGS}" == "true" ]]; then
echo "ALLOW_WARNINGS=true -> report-only mode. Passing."
exit 0
fi
prettier_present="${{ steps.ensure_prettier.outputs.prettier_present }}"
exit_code="${{ steps.run_prettier.outputs.exit_code }}"
if [[ "${prettier_present}" != "true" ]]; then
echo "❌ Enforced mode requires Prettier available in node_modules."
echo " Add it: npm i -D prettier"
exit 1
fi
if [[ "$exit_code" != "0" ]]; then
echo "❌ Failing due to Prettier formatting violations."
exit 1
fi
echo "✅ Prettier passed."