Skip to main content

Lint Check Workflow (lint-check.yaml)

The Lint Check Workflow provides comprehensive code quality validation for both Node.js and Deno services. It features intelligent change detection, advanced ESLint configuration with ignore pattern matching, Deno formatting and linting, and detailed PR reporting with actionable feedback.

🕵️‍♂️ Overview

  • File: .github/workflows/lint-check.yaml
  • Purpose: Code quality and formatting validation
  • Triggers: Pull requests and manual dispatch
  • Services: Node.js (ESLint) and Deno (native tools)
  • Features: Smart file detection, detailed PR comments, artifact preservation

🔄 Trigger Events

on:
pull_request:
branches: ['**']
types: [opened, reopened, synchronize]
workflow_dispatch:

🔍 Advanced Change Detection

File Analysis Process

# Get merge base for accurate diff
git fetch origin ${{ github.base_ref }}
BASE_SHA=$(git merge-base origin/${{ github.base_ref }} HEAD)

# Get changed files excluding deletions
git diff --name-only --diff-filter=d $BASE_SHA HEAD > files.txt

Service Type Detection

# Identify Node.js changes (exclude ai-service)
if grep -qv '^ai-service/' files.txt; then
echo "node_changed=true" >> $GITHUB_OUTPUT
fi

# Identify Deno changes
if grep -q '^ai-service/' files.txt; then
echo "deno_changed=true" >> $GITHUB_OUTPUT
fi

🟢 Node.js Linting

Environment Setup

# Node.js 20 with caching
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'

# Install dependencies
npm i

Advanced ESLint Integration

Dynamic Ignore Pattern Matching

The workflow includes a sophisticated ESLint ignore matcher:

// scripts/eslint-ignore-matcher.js
const minimatch = require('minimatch');

function isFileIgnored(filePath, ignorePatterns) {
const normalizedPath = filePath.replace(/\\/g, '/');

return ignorePatterns.some(pattern => {
const isNegation = pattern.startsWith('!');
const actualPattern = isNegation ? pattern.slice(1) : pattern;

const matches = minimatch(normalizedPath, actualPattern, {
dot: true,
matchBase: !actualPattern.includes('/'),
});

return isNegation ? !matches : matches;
});
}

Ignore Pattern Processing

# Process files against .eslintignore
cat files.txt | node scripts/eslint-ignore-matcher.js > ignore_status.json

# Extract files to lint
jq -r '.[] | select(.ignored == false) | .file' ignore_status.json > files_to_lint.txt

# Extract ignored files for reporting
jq -r '.[] | select(.ignored == true) | .file' ignore_status.json > files_ignored.txt

ESLint Execution

# Run ESLint with JSON output
npx eslint \
--debug \
--format json \
--output-file eslint_report.json \
$(cat files_to_lint.txt)

Result Processing

# Clean and format ESLint output
jq '[.[] | select(.messages != null and .filePath != null) | . as $parent | {
filePath: .filePath,
messages: [.messages[] | select(.message != null and .line != null) | . + {filePath: $parent.filePath}]
}]' eslint_report.json > eslint_report_cleaned.json

🦕 Deno Linting

Environment Setup

# Deno 2.1.7
uses: denoland/setup-deno@v2
with:
deno-version: 2.1.7

Deno Format Check

cd ai-service
CHANGED_DENO_FILES=$(cat ../files.txt | grep -E '^ai-service/.*\.(ts|tsx)$' | sed 's/^ai-service\///')

if [ -n "$CHANGED_DENO_FILES" ]; then
if NO_COLOR=true deno fmt --check $CHANGED_DENO_FILES; then
echo "✅ Deno format check passed" >> ../lint_results.txt
else
echo "❌ Deno format check failed" >> ../lint_results.txt
fi
fi

Deno Lint Check

if NO_COLOR=true deno lint $CHANGED_DENO_FILES; then
echo "✅ Deno lint check passed" >> ../lint_results.txt
else
echo "❌ Deno lint check failed" >> ../lint_results.txt
fi

Deno Type Check

if NO_COLOR=true deno check $CHANGED_DENO_FILES; then
echo "✅ Deno type check passed" >> ../lint_results.txt
else
echo "❌ Deno type check failed" >> ../lint_results.txt
fi

📊 Result Analysis & Reporting

Error Categorization

# Extract ESLint errors (severity 2)
jq -r '.[] | .messages[] | select(.severity == 2) | "\(.filePath):\(.line) - \(.message) (\(.ruleId))"' eslint_report.json > eslint_errors.txt

# Extract ESLint warnings (severity 1)
jq -r '.[] | .messages[] | select(.severity == 1) | "\(.filePath):\(.line) - \(.message) (\(.ruleId))"' eslint_report.json > eslint_warnings.txt

Comprehensive Reporting

# Generate detailed lint report
{
echo "=== Run Information ==="
echo "Timestamp: $(date -u +'%Y-%m-%dT%H:%M:%SZ')"
echo "Runner: ${{ runner.os }}"
echo "Node Version: $(node --version)"
echo "Deno Version: $(deno --version)"

echo "=== Changed Files ==="
cat files.txt

echo "=== Service Detection ==="
echo "Node.js changes detected: ${{ steps.node-changes.outputs.node_changed }}"
echo "Deno changes detected: ${{ steps.deno-changes.outputs.deno_changed }}"

echo "=== ESLint Results ==="
if [ -s eslint_errors.txt ]; then
echo "Errors:"
cat eslint_errors.txt
else
echo "✅ No errors found!"
fi

if [ -s eslint_warnings.txt ]; then
echo "Warnings:"
cat eslint_warnings.txt
else
echo "✅ No warnings found!"
fi

echo "=== Deno Check Results ==="
cat lint_results.txt
} > lint_report.txt

📦 Artifact Management

Artifact Upload

- name: 📝 Upload Workflow Artifacts
uses: actions/upload-artifact@v4
with:
name: lint-check-artifacts
path: |
files.txt
lint_report.txt
eslint_report.json
deno-lint-results.txt
retention-days: 7

Artifact Contents

  • files.txt: List of all changed files
  • lint_report.txt: Comprehensive linting summary
  • eslint_report.json: Raw ESLint output in JSON format
  • deno-lint-results.txt: Deno-specific lint results

Failure Conditions

Blocking Errors

The workflow fails on:

# ESLint errors (severity 2) - blocking
if [ -f "eslint_errors.txt" ] && [ -s "eslint_errors.txt" ]; then
FAIL=true
echo "❌ ESLint errors found - failing the workflow"
fi

# Deno check failures - blocking
if grep -q "❌" lint_results.txt; then
FAIL=true
echo "❌ Deno checks failed - failing the workflow"
fi

Non-blocking Warnings

ESLint warnings (severity 1) do not fail the workflow but are reported:

# Warnings are reported but don't block merge
if [ -s eslint_warnings.txt ]; then
echo "⚠️ ESLint warnings found (non-blocking)"
fi

💬 Pull Request Integration

Automated PR Comments

// Status determination
let statusEmoji = '✅';
let statusMessage = 'All checks passed!';

if (hasEslintErrors || hasFailedDenoChecks) {
statusEmoji = '❌';
statusMessage = 'Some checks failed. Action required!';
} else if (hasEslintWarnings) {
statusEmoji = '⚠️';
statusMessage = 'Checks passed with warnings';
}

// Comment structure
const commentBody = `## 🕵️‍♂️ Lint Check Results

### ${statusEmoji} Status: ${statusMessage}

### 📊 Run Information
- **Run ID**: [\`${process.env.RUN_ID}\`](${context.serverUrl}/${context.repo.owner}/${
context.repo.repo
}/actions/runs/${process.env.RUN_ID})
- **Started**: ${process.env.TIMESTAMP}

### 🔍 Changed Files
${process.env.FILES}

### 🛠 Service Detection
- **Node.js Changes**: ${process.env.NODE_CHANGES === 'true' ? '✅' : 'No'}
- **Deno Changes**: ${process.env.DENO_CHANGES === 'true' ? '🦕' : 'No'}

${
hasEslintErrors
? `### ❌ Errors
\`\`\`
${fs.readFileSync('eslint_errors.txt', 'utf8')}
\`\`\`
`
: ''
}

${
hasEslintWarnings
? `### ⚠️ Warnings
<details>
<summary>Click to see warnings</summary>

\`\`\`
${fs.readFileSync('eslint_warnings.txt', 'utf8')}
\`\`\`
</details>
`
: ''
}

### 📝 Detailed Results
<details>
<summary>Click to view full results</summary>

\`\`\`
${results}
\`\`\`
</details>
`;

Comment Features

  • Status indicators: Clear visual status with emojis
  • Collapsible sections: Detailed information in expandable sections
  • Direct links: Links to workflow runs for debugging
  • File tracking: Shows exactly which files were analyzed
  • Service detection: Indicates which tools were used

🔧 Configuration

ESLint Configuration

The workflow respects standard ESLint configurations:

// .eslintrc.js or package.json
{
"extends": ["eslint:recommended"],
"rules": {
"no-unused-vars": "error",
"semi": ["error", "always"]
},
"ignorePatterns": [
"node_modules/",
"dist/",
"build/"
]
}

ESLint Ignore Patterns

# .eslintignore
node_modules/**
dist/**
build/**
coverage/**
**/*.min.js
*.config.js

Deno Configuration

// deno.json in ai-service/
{
"lint": {
"rules": {
"tags": ["recommended"]
}
},
"fmt": {
"useTabs": false,
"lineWidth": 80,
"indentWidth": 2
}
}

📋 Linting Configuration

Tool Versions

The workflow uses:

  • Node.js 20: Runtime environment for ESLint
  • Deno 2.1.7: Runtime for AI service linting
  • ESLint: Code quality checking with JSON output
  • Minimatch 5.1.0: Pattern matching for ignore files

Error Classification

  • ESLint errors (severity 2): Block workflow execution
  • ESLint warnings (severity 1): Reported but non-blocking
  • Deno format failures: Block workflow execution
  • Deno lint failures: Block workflow execution
  • Deno type check failures: Block workflow execution

💬

Documentation Assistant

Ask me anything about the docs

Hi! I'm your documentation assistant. Ask me anything about the docs!

I can help you with:
- Code examples
- Configuration details
- Troubleshooting
- Best practices

Try asking: How do I configure the API?
09:31 AM