This document describes the complete GitHub Actions workflow automation for the Node API Skeleton project.
- Overview
- Workflow Architecture
- Core Workflows
- Code Quality Workflows
- PR Automation Workflows
- Monitoring Workflows
- Dependency Management
- Custom Reusable Actions
- Configuration Files
- Best Practices
The project uses a modular GitHub Actions architecture following the Single Responsibility Principle. Each workflow has one clear purpose, enabling:
- Parallel execution for faster feedback
- Granular failure visibility - know exactly what failed
- Selective triggering - workflows only run when needed
- Easy maintenance - small, focused, understandable files
| Category | Workflows | Purpose |
|---|---|---|
| Core CI/CD | 3 | Build, test, lint, security |
| Code Quality | 2 | YAML validation, spell checking |
| PR Automation | 2 | Size labeling, title validation |
| Monitoring | 1 | Docker image size tracking |
| Maintenance | 3 | Stale items, TODO conversion, label sync |
| Total | 11 | Complete automation suite |
Separation of Concerns: Each workflow handles ONE specific aspect of CI/CD:
┌─────────────────────────────────────────┐
│ Pull Request Event │
└─────────────────┬───────────────────────┘
│
┌─────────────┼─────────────┬─────────────┐
│ │ │ │
▼ ▼ ▼ ▼
┌────────┐ ┌──────────┐ ┌─────────┐ ┌─────────┐
│ CI │ │ Lint │ │ Dep │ │ PR │
│ Build │ │ ESLint │ │ Review │ │ Title │
│ Test │ │ Prettier │ │ Security│ │ Lint │
└────────┘ └──────────┘ └─────────┘ └─────────┘
│ │ │ │
└───────────┴─────────────┴─────────────┘
│
✅ All checks pass
│
Ready to merge
- ✅ Fast feedback - Parallel execution instead of sequential
- ✅ Clear failures - "Lint PR Title failed" vs digging through monolithic logs
- ✅ Efficient - Only run workflows for changed file types
- ✅ Scalable - Add new workflows without modifying existing ones
Purpose: Build, test, and validate code across multiple platforms
Triggers:
- Push to
main,feat/**branches - Pull requests to
main
Strategy: Matrix testing across 3 operating systems
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
node-version: [24.x]Jobs:
- Checkout - Clone repository
- Setup Node.js - Uses custom reusable action
- Build - Compile TypeScript with SWC
- Test - Run all tests (unit + integration + e2e)
- Coverage - Generate coverage report (Ubuntu only)
Coverage Thresholds: 80% for branches, functions, lines, statements
Location: .github/workflows/ci.yml
Purpose: Enforce code quality standards
Triggers:
- Push to
main,feat/**branches - Pull requests to
main
Jobs:
- ESLint - Check code linting (
npm run lint) - Prettier - Verify code formatting (
npm run format:check)
Configuration:
- ESLint:
eslint.config.js - Prettier:
.prettierrc - Pre-commit hooks:
.lintstagedrc
Location: .github/workflows/lint.yml
Purpose: Security scanning for vulnerable dependencies
Triggers:
- Pull request events (opened, synchronize, reopened)
Features:
- ✅ Scans PR changes for known vulnerabilities
- ✅ Blocks PRs with high/critical severity issues
- ✅ Posts summary comment directly in PR
- ✅ Checks licensing compliance
Example Output:
🛡️ Dependency Review Summary
✅ No vulnerabilities found
📦 2 dependencies added
🔄 1 dependency updated
Location: .github/workflows/dependency-review.yml
Purpose: Validate YAML syntax across all configuration files
Triggers:
- Push events affecting
*.yml,*.yaml,.github/workflows/**
Tool: yamllint
Validated Files:
- GitHub workflow files
- Docker Compose files
- Configuration files (
.yamllint.yml,dependabot.yml)
Configuration: .yamllint.yml
rules:
line-length:
max: 120
indentation:
spaces: 2Location: .github/workflows/lint-yaml.yml
Purpose: Catch spelling mistakes in code and documentation
Triggers:
- Push to
main,feat/**branches - Pull requests to
main
Tool: crate-ci/typos
Scanned Paths:
./src- Source code./docs- Documentation./test- Test filesREADME.md,CLAUDE.md
Location: .github/workflows/typos.yml
Purpose: Enforce Conventional Commits format for PR titles
Triggers:
- Pull request events (opened, edited, synchronize, reopened)
Format: type(scope): description
Valid Types:
feat- New featurefix- Bug fixdocs- Documentationstyle- Code style (formatting, missing semicolons)refactor- Code refactoringtest- Adding/updating testschore- Maintenance tasksperf- Performance improvementsci- CI/CD changes
Examples:
✅ feat(api): add user authentication endpoint
✅ fix(docker): resolve memory leak in container
✅ docs(readme): update installation instructions
❌ Added new feature (missing type/scope)
❌ fix: bug (too vague)
Error Handling:
- Posts sticky comment with error details
- Links to Conventional Commits specification
- Auto-deletes comment when fixed
Location: .github/workflows/lint-pr-title.yml
Purpose: Auto-label PRs by lines changed, encourage smaller PRs
Triggers:
- Pull request events (opened, synchronize, reopened)
Size Categories:
| Label | Lines Changed | Emoji |
|---|---|---|
🤩 size/xs |
0-10 | Extra Small |
🥳 size/s |
11-100 | Small |
😎 size/m |
101-500 | Medium |
😖 size/l |
501-1000 | Large |
🤯 size/xl |
1001+ | Extra Large |
Features:
⚠️ Warning posted when PR > 1000 lines- Ignores lock files and documentation from count
- Removes old size label when PR is updated
Ignored Files:
package-lock.json
*.lock
docs/*
CHANGELOG.md
Location: .github/workflows/pr-size-labeler.yml
Purpose: Track Docker image size changes in PRs
Triggers:
- Pull requests to
mainbranch
Process:
- Build base - Builds image from target branch
- Build PR - Builds image from PR branch
- Compare - Posts size comparison comment
Example Output:
🐳 Docker Image Size Comparison
| Branch | Size |
|--------|------|
| Base (main) | 245 MB |
| PR (feat/add-auth) | 312 MB |
---
💡 Tip: Keep image size small using multi-stage builds and .dockerignore
Benefits:
- Catch image bloat early
- Visibility into optimization opportunities
- Encourages multi-stage build practices
Location: .github/workflows/docker-size.yml
Purpose: Automated dependency updates
Update Schedule: Daily
Monitored Ecosystems:
package-ecosystem: "npm"
schedule:
interval: "daily"
commit-message:
prefix: "fix" # Production deps
prefix-development: "chore" # Dev deps
labels:
- "📦 Dependencies"package-ecosystem: "github-actions"
schedule:
interval: "daily"
labels:
- "📦 Dependencies"
- "🚀 CI/CD"Features:
- ✅ Automatic PR creation for updates
- ✅ Grouped by ecosystem
- ✅ Conventional commit messages
- ✅ Semantic versioning strategy
- ✅ Auto-labeling for easy filtering
Location: .github/dependabot.yml
Purpose: Manage inactive issues and pull requests
Schedule: Daily at 1:30 AM UTC
Configuration:
- Stale after: 30 days of inactivity
- Close after: 5 additional days
- Exempt labels:
pinned,security,work-in-progress
Messages:
Stale message (day 30):
"This issue is stale because it has been open 30 days with no activity.
Remove the stale label or comment, or this will be closed in 5 days."
Close message (day 35):
"This issue was closed because it has been inactive for 5 days since
being marked as stale."
Location: .github/workflows/stale-issues-and-prs.yml
Purpose: Convert code TODOs to GitHub issues automatically
Triggers:
- Push to
mainbranch - Manual trigger (workflow_dispatch)
Supported Identifiers:
// TODO:→ Label:todo// FIXME:→ Label:bug// HACK:→ Label:tech-debt
Example:
// TODO: Add authentication middleware
export const greetingRoutes = () => {
// ...
}Generated Issue:
## ✅ Codebase TODO
**File**: src/@contexts/greetings/infrastructure/http/v1/routes/greeting.routes.ts
**Line**: 12
### Description
Add authentication middleware
### Code Snippet
```typescript
export const greetingRoutes = () => {
// ...
}This issue was automatically created from a TODO comment in the code.
**Features**:
- ✅ Auto-assigns to committer
- ✅ Links to exact file and line number
- ✅ Includes code snippet for context
- ✅ Prevents duplicates
**Ignored Paths**:
.github/workflows/todo-to-issue.yml node_modules/** dist/** build/** coverage/**
**Location**: `.github/workflows/todo-to-issue.yml`
---
### 11. Sync Labels (`sync-labels.yml`)
**Purpose**: Automatically synchronize repository labels from configuration file
**Triggers**:
- Push to `main` branch affecting `.github/labels.yml`
- Manual trigger (workflow_dispatch)
**Tool**: [micnncim/action-label-syncer](https://github.com/micnncim/action-label-syncer)
**Features**:
- ✅ Creates labels defined in `labels.yml`
- ✅ Updates existing labels (color, description)
- ✅ Removes labels not in configuration (`prune: true`)
- ✅ Labels as code - version controlled
**Configuration File**: `.github/labels.yml` (44 labels)
**How It Works**:
1. Reads label definitions from `.github/labels.yml`
2. Compares with current repository labels
3. Creates new labels
4. Updates modified labels
5. Deletes labels not in file (if prune enabled)
**Benefits**:
- Consistent labels across repositories
- No manual label management
- Changes tracked in git history
- Easy to replicate label structure
**Example Usage**:
```yaml
# .github/labels.yml
- name: "🐛 bug"
color: "d73a4a"
description: "Something isn't working"
Manual Trigger: Can be triggered manually from GitHub Actions tab
Location: .github/workflows/sync-labels.yml
Purpose: DRY principle - centralize Node.js setup across all workflows
Location: .github/actions/setup-node/action.yml
Steps:
- Setup Node.js 24.x with npm caching
- Install dependencies (
npm ci) - Verify installation (log versions)
Benefits:
- ✅ Change Node version once, applies everywhere
- ✅ Consistent caching strategy
- ✅ Faster workflow authoring
- ✅ Version in one place
Usage in workflows:
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup-node
- run: npm run build
- run: npm run testUsed by: ci.yml, lint.yml
Purpose: Define all repository labels as code
Categories:
-
Bug & Issue Types (5 labels)
- 🐛 bug, ✨ enhancement, 📝 documentation, 🚀 performance, 🔒 security
-
Priority Levels (4 labels)
- 🔥 priority: critical, ⚡ priority: high, ➡️ priority: medium, ⬇️ priority: low
-
Workflow Status (6 labels)
- 🚧 work-in-progress, 👀 needs review, 🔄 needs changes, ✅ ready to merge, ⏸️ on hold, stale
-
Dependencies & DevOps (3 labels)
- 📦 Dependencies, 🚀 CI/CD, 🐳 docker
-
PR Size (5 labels)
- 🤩 size/xs, 🥳 size/s, 😎 size/m, 😖 size/l, 🤯 size/xl
-
Architecture & Code Quality (5 labels)
- ♻️ refactor, 🧪 test, 🏗️ architecture, 🎨 style, 🔧 config
-
Conventional Commit Types (3 labels)
- feat, fix, chore
-
Special Labels (8 labels)
- pinned, good first issue, help wanted, question, duplicate, invalid, wontfix, todo, tech-debt
Total: 44 labels
Location: .github/labels.yml
Sync Tool: micnncim/action-label-syncer (optional)
Purpose: Configure YAML validation rules
Key Rules:
line-length:
max: 120
level: warning
indentation:
spaces: 2
truthy:
allowed-values: ['true', 'false', 'on', 'off']
document-start: disableIgnored Paths:
node_modules/
.git/
dist/
build/
coverage/
Location: .yamllint.yml
Use emojis + clear descriptive names:
name: "🐢 Continuous Integration" # CI
name: "🔦 Lint" # Code quality
name: "🛡️ Dependency Review" # Security
name: "📝 Lint PR Title" # PR automationBe specific - only run when needed:
# Run lint only on code changes
on:
push:
paths:
- 'src/**'
- 'test/**'
# Run YAML lint only on YAML changes
on:
push:
paths:
- '**.yml'
- '**.yaml'Use Node.js caching via custom action:
- uses: ./.github/actions/setup-node
# ✅ Automatic npm caching includedMinimal Permissions: Only grant what's needed
permissions:
contents: read
pull-requests: writeUse Secrets: Never hardcode tokens
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}Sticky Comments: Reuse same comment instead of spam
- uses: marocchino/sticky-pull-request-comment@v2
with:
header: pr-title-lint-error # Unique identifier
message: |
Error details...Delete on Success:
- if: success()
uses: marocchino/sticky-pull-request-comment@v2
with:
header: pr-title-lint-error
delete: trueTest across platforms when needed:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]Conditional Steps:
- if: matrix.os == 'ubuntu-latest'
run: npm run test:coverageAllow manual workflow execution:
on:
schedule:
- cron: "30 1 * * *"
workflow_dispatch: # ✅ Adds "Run workflow" button in GitHub UIView all workflows: https://github.com/Proskynete/node-api-skeleton/actions
Required status checks for PR merging:
- ✅ Continuous Integration (build + test on all platforms)
- ✅ Lint & Format Check
- ✅ Dependency Review
- ✅ Lint PR Title
Add to README.md:
[](https://github.com/Proskynete/node-api-skeleton/actions/workflows/ci.yml)
[](https://github.com/Proskynete/node-api-skeleton/actions/workflows/lint.yml)Check:
- File is in
.github/workflows/directory - YAML syntax is valid (use
yamllint) - Trigger conditions match (branch names, paths)
Error: Unable to resolve action ./.github/actions/setup-node
Fix:
steps:
- uses: actions/checkout@v4 # ✅ Must checkout FIRST
- uses: ./.github/actions/setup-nodeError: Resource not accessible by integration
Fix: Add permissions to workflow
permissions:
contents: read
pull-requests: writeIssue: Path separators differ
Fix: Use cross-platform tools
- run: npm run build # ✅ Works on all platforms
# vs
- run: ./scripts/build.sh # ❌ Unix only- Create file in
.github/workflows/ - Follow naming convention:
name-with-dashes.yml - Add emoji + descriptive name
- Use custom action for Node.js setup
- Add minimal permissions
- Test with manual trigger first
Single source of truth: .github/actions/setup-node/action.yml
- uses: actions/setup-node@v4
with:
node-version: '24.x' # ✅ Change here onlyAll workflows automatically inherit the new version.
GitHub Actions minutes:
- Free tier: 2,000 minutes/month (public repos)
- Private repos: Varies by plan
Optimization:
- Use
pathsfilters to skip unnecessary runs - Cache dependencies with custom action
- Use conditional steps (
if:) for expensive operations
- yamllint
- crate-ci/typos
- amannn/action-semantic-pull-request
- codelytv/pr-size-labeler
- actions/dependency-review-action
- actions/stale
- alstr/todo-to-issue-action
Last Updated: December 2024 Version: 2.1.0 Workflows: 11 active workflows