| name | build-pipeline-analyzer |
| description | Diagnoses GitHub Actions CI/CD failures for FanHub's Node.js workflows. Identifies test failures, build errors, Docker issues, and environment problems. |
Build Pipeline Analyzer Skill
This skill helps diagnose GitHub Actions workflow failures for FanHub's frontend and backend CI/CD pipelines.
FanHub CI/CD Pipeline Structure
Frontend Workflow
name: Frontend CI
steps:
1. Checkout code
2. Setup Node.js 18
3. npm ci (install dependencies)
4. npm run lint (ESLint)
5. npm test -- --coverage (Jest tests, 80% minimum)
6. npm run build (production build)
Backend Workflow
name: Backend CI
steps:
1. Checkout code
2. Setup Node.js 18
3. Setup PostgreSQL service
4. npm ci (install dependencies)
5. npm run lint (ESLint)
6. npm test -- --coverage (Jest + integration tests)
7. Docker build (multi-stage Dockerfile)
Environment: ubuntu-latest runners, Node 18 LTS
Common CI/CD Failure Patterns
1. Test Failures
1A. Test Timeout
Symptom:
FAIL src/components/CharacterCard.test.js
● CharacterCard › renders character name
Timeout - Async callback was not invoked within the 5000ms timeout
specified by jest.setTimeout.
npm ERR! Test failed. See above for more details.
Root Causes:
- Unmocked API call (waiting for real network request)
- Database connection not established (in integration tests)
- Infinite loop or unresolved Promise
- CI runner slower than local machine
Diagnostic Questions:
- Does test pass locally? (flaky vs. broken)
- Is there an API call without a mock?
- Is there an async operation without await?
- Is there a database dependency?
Fixes:
-
Increase timeout (if genuinely slow operation):
jest.setTimeout(10000);
-
Add missing mocks:
jest.mock('../api/characters', () => ({
getCharacter: jest.fn().mockResolvedValue({ name: 'Test' })
}));
-
Ensure async completion:
await waitFor(() => {
expect(screen.getByText('Character Name')).toBeInTheDocument();
});
-
Fix database setup (backend tests):
beforeEach(async () => {
await db.reset();
});
1B. Assertion Failure
Symptom:
FAIL src/api/characters.test.js
● GET /api/characters/:id › returns character with related data
Expected: 200
Received: 500
Database connection timeout
Root Causes:
- Test database not properly configured in CI
- Missing environment variables
- Race condition (test runs before setup completes)
- Test isolation issue (previous test left dirty state)
Diagnostic Questions:
- Does test pass when run alone? (
npm test -- CharacterCard)
- Are environment variables set in GitHub Actions?
- Is the database service running? (check workflow YAML)
- Is test cleanup happening? (afterEach hooks)
Fixes:
-
Check GitHub Actions secrets/env vars:
env:
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/testdb
NODE_ENV: test
-
Add test isolation:
afterEach(async () => {
await db.query('TRUNCATE TABLE characters, quotes CASCADE');
});
-
Wait for services to be ready:
- name: Wait for PostgreSQL
run: |
until pg_isready -h localhost -p 5432; do
sleep 1
done
2. Build Failures
2A. Dependency Install Failure
Symptom:
Run npm ci
npm ERR! cipm can only install packages when your package.json and
package-lock.json are in sync.
Root Cause: package-lock.json is out of sync with package.json
Fixes:
-
Locally regenerate lock file:
rm package-lock.json
npm install
git add package-lock.json
git commit -m "fix: regenerate package-lock.json"
-
Or use npm install in CI (slower but more forgiving):
- run: npm install
2B. Build Step Failure
Symptom:
Run npm run build
> react-scripts build
Failed to compile.
Module not found: Can't resolve './CharacterCard' in '/src/pages'
Root Causes:
- Import path wrong (case-sensitive on Linux, not on Mac/Windows)
- File not committed to git
- Build-time environment variable missing
CI vs Local Differences:
- CI runs on Linux (case-sensitive filesystem)
- CI clones from git (doesn't see untracked files)
- CI has different environment variables
Diagnostic Questions:
- Is the file name exactly right? (
CharacterCard.js vs. characterCard.js)
- Is the file committed? (
git ls-files | grep CharacterCard)
- Does the build need env vars? (check for
process.env.REACT_APP_*)
Fixes:
-
Fix import case:
import CharacterCard from './CharacterCard';
import CharacterCard from './characterCard';
-
Commit missing files:
git add src/components/CharacterCard.js
git commit -m "fix: add missing component file"
-
Add build-time env vars:
- name: Build
env:
REACT_APP_API_URL: ${{ secrets.API_URL }}
run: npm run build
3. Linting Failures
Symptom:
Run npm run lint
/home/runner/work/fanhub/src/components/CharacterCard.js
12:7 error 'character' is assigned a value but never used no-unused-vars
✖ 1 problem (1 error, 0 warnings)
Root Cause: Code passes locally because lint warnings were ignored
Why CI Catches It:
- Local:
npm run lint may just warn
- CI: Often configured to fail on errors (
--max-warnings 0)
Fixes:
-
Fix the lint error (preferred):
const { character } = props;
const { name } = props;
-
Run lint with auto-fix locally:
npm run lint -- --fix
-
Add lint-staged to prevent this:
{
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"*.js": "eslint --fix"
}
}
4. Docker Build Failures in CI
4A. COPY Path Issues
Symptom:
Step 4/7 : COPY package*.json ./
COPY failed: file not found in build context or excluded by .dockerignore:
stat package.json: file does not exist
Root Cause: Docker build context is wrong in GitHub Actions
CI vs Local Difference:
- Local: You run
docker build from the right directory
- CI: Workflow might run from repo root
Diagnostic Questions:
- What's the
docker build command in the workflow?
- Where is the Dockerfile? (
backend/Dockerfile)
- Where is package.json relative to the Dockerfile?
Fixes:
-
Check workflow docker build command:
- name: Build Docker image
run: docker build -f backend/Dockerfile .
- name: Build Docker image
run: docker build -f backend/Dockerfile ./backend
-
Or adjust Dockerfile COPY paths:
# If context is repo root and Dockerfile is in backend/:
COPY backend/package*.json ./
5. Flaky Tests
Symptom: Test passes sometimes, fails other times (~30% failure rate)
Example:
Run npm test
FAIL src/api/characters.test.js (Run 1/1)
● GET /api/characters/:id › returns character with related data
Expected: 200
Received: 500
But re-running the workflow... it passes.
Root Causes:
- Race condition (async operations not properly awaited)
- Shared state between tests (one test affects another)
- External dependency (database, network)
- Timing-dependent assertion
Diagnostic Questions:
- Does it fail consistently or intermittently?
- Does it pass when run alone?
- Is there shared state (global variables, database)?
- Are async operations properly awaited?
Fixes:
-
Improve test isolation:
beforeEach(async () => {
await db.resetAllTables();
});
-
Add retry logic for known-flaky tests:
jest.retryTimes(2);
-
Use proper async patterns:
render(<CharacterCard id={1} />);
expect(screen.getByText('Name')).toBeInTheDocument();
render(<CharacterCard id={1} />);
await waitFor(() => {
expect(screen.getByText('Name')).toBeInTheDocument();
});
-
Increase timeout for slow CI runners:
jest.setTimeout(10000);
Diagnostic Workflow
When a GitHub Actions build fails:
-
Identify which step failed
- Click on the failed workflow run
- Expand the failed step
- Look for the red ✖ icon
-
Extract the actual error message
- Don't stop at "exit code 1"
- Scroll up to find the actual error (npm ERR!, FAIL, ERROR)
- Copy the error message
-
Determine the failure type
| Error Contains | Failure Type |
|---|
FAIL, Timeout | Test failure |
npm ERR!, ERESOLVE | Dependency issue |
Module not found | Build error |
error + eslint | Lint failure |
COPY failed | Docker build issue |
-
Check if it's a regression
- Did this pass on the previous commit?
- Check the commit diff—what changed?
- Look at previous successful runs for comparison
-
Distinguish CI-specific vs. universal issues
| Issue | CI-Specific? |
|---|
| Test timeout | Maybe (CI slower) |
| Import case mismatch | Yes (Linux vs Mac) |
| Missing mocks | No (universal) |
| Docker context path | Yes (workflow-specific) |
| Lint error | No (should fail locally too) |
-
Apply the appropriate fix
- See specific sections above for each failure type
Quick Triage Guide
Build Failed
└─ Which step?
├─ npm ci
│ └─ "out of sync" → Regenerate package-lock.json
├─ npm run lint
│ └─ ESLint error → Fix or run --fix locally
├─ npm test
│ ├─ "Timeout" → Check mocks, increase timeout
│ ├─ Assertion failed → Check DB setup, env vars
│ └─ "Flaky" → Improve test isolation, add retries
├─ npm run build
│ ├─ "Module not found" → Check import case, file committed
│ └─ Build error → Check for missing env vars
└─ docker build
└─ "COPY failed" → Check context path in workflow
Cross-Skill Integration
This skill works well with:
Docker Build Debugger Skill:
- When Docker build fails in CI
- Validates Dockerfile patterns
- Checks COPY order, layer caching
Dependency Conflict Resolver Skill:
- When npm ci fails with ERESOLVE
- Diagnoses peer dependency conflicts
- Suggests upgrade paths
Example question that uses both:
"The CI pipeline fails during Docker build. The error is 'ENOENT package.json'. What should I check?"
Copilot might:
- Use Build Pipeline Analyzer: Check CI workflow docker build context
- Use Docker Build Debugger: Validate Dockerfile COPY order
When to Use This Skill
Ask Copilot with this skill when:
- GitHub Actions workflow fails
- Need to understand what step failed and why
- Want to diagnose test failures in CI
- Dealing with flaky tests
- Docker build works locally but fails in CI
- Teaching someone about CI/CD debugging
Example prompts:
- "The GitHub Actions build failed with test timeout. How do I debug it?"
- "Why does my Docker build work locally but fail in CI?"
- "This test is flaky—passes sometimes, fails others. What should I check?"
- "The workflow failed at the lint step. How do I fix ESLint errors?"
Prevention Strategies
1. Run CI Checks Locally
npm ci
npm run lint
npm test -- --coverage
npm run build
2. Use Act to Test Workflows Locally
act
3. Add Lint-Staged (Pre-commit Hooks)
Catch issues before they reach CI:
{
"lint-staged": {
"*.js": ["eslint --fix", "git add"]
}
}
4. Monitor Flaky Tests
Track which tests fail intermittently:
for i in {1..10}; do npm test; done
Links to Future Modules
This skill connects to:
Module 6 (MCP Servers):
- Use GitHub MCP to query Actions logs programmatically
- Fetch failure history for pattern analysis
Module 8 (Copilot Web):
- Create/modify GitHub Actions workflows in browser
- Your pipeline knowledge speeds up workflow creation
Module 9 (Copilot CLI):
- Run CI commands locally through CLI
- Debug workflows from terminal
Module 10 (Agentic SDLC):
- Automated testing and CI/CD integration
- Full build → test → deploy pipeline