Skip to content

Merge pull request #24 from Rahul5430/dependabot/github_actions/actio… #41

Merge pull request #24 from Rahul5430/dependabot/github_actions/actio…

Merge pull request #24 from Rahul5430/dependabot/github_actions/actio… #41

Workflow file for this run

name: Checks
on:
push:
branches: [main]
jobs:
checks:
runs-on: ubuntu-latest
concurrency:
group: checks-${{ github.ref }}
cancel-in-progress: true
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0 # Fetch full history for gitleaks
- uses: actions/setup-node@v6
with:
node-version: 20
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Security audit (high+)
run: |
set -e
npm audit --production --audit-level=high
- name: Run Gitleaks secret scan
uses: gitleaks/gitleaks-action@v2
- name: ESLint
run: npm run lint
- name: TypeScript typecheck
run: npx tsc --noEmit
- name: Run tests with coverage
env:
FIRESTORE_EMULATOR_HOST: 127.0.0.1:8080
run: npm run test:coverage
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./coverage/lcov.info
flags: unittests
fail_ci_if_error: true
- name: Upload coverage artifact
uses: actions/upload-artifact@v6
with:
name: jest-coverage
path: coverage
- name: Generate Job Summary
uses: actions/github-script@v8
with:
script: |
const fs = require('fs');
const path = require('path');
// Read coverage summary
let coverageSummary = 'N/A';
let coveragePercent = 'N/A';
let coverageStatus = '❌';
try {
const coverageFile = 'coverage/coverage-summary.json';
if (fs.existsSync(coverageFile)) {
const coverage = JSON.parse(fs.readFileSync(coverageFile, 'utf8'));
const total = coverage.total;
coveragePercent = `${total.lines.pct}%`;
coverageStatus = total.lines.pct >= 95 ? '✅' : '❌';
coverageSummary = `Lines: ${total.lines.pct}% | Functions: ${total.functions.pct}% | Branches: ${total.branches.pct}% | Statements: ${total.statements.pct}%`;
}
} catch (e) {
console.log('Could not read coverage summary:', e.message);
}
// Read test results
let testSummary = 'N/A';
let testStatus = '❌';
try {
const testFile = 'coverage/test-results.json';
if (fs.existsSync(testFile)) {
const testResults = JSON.parse(fs.readFileSync(testFile, 'utf8'));
const { numTotalTests, numPassedTests, numFailedTests } = testResults;
testSummary = `${numPassedTests}/${numTotalTests} passed`;
testStatus = numFailedTests === 0 ? '✅' : '❌';
}
} catch (e) {
// Fallback: try to parse from Jest output
testSummary = 'See logs for details';
}
// Check Gitleaks results
let gitleaksStatus = '✅';
let gitleaksSummary = 'No secrets found';
try {
// Check if Gitleaks found any leaks by looking at the job context
// This is a simplified check - in practice, Gitleaks action handles this
gitleaksStatus = '✅';
gitleaksSummary = 'No secrets detected (excluded false positives)';
} catch (e) {
gitleaksStatus = '❌';
gitleaksSummary = 'Secrets detected - check logs';
}
// Get artifact URLs
const artifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: context.runId
});
const coverageArtifact = artifacts.data.artifacts.find(a => a.name === 'jest-coverage');
const coverageUrl = coverageArtifact ?
`[Download Coverage Report](${coverageArtifact.archive_download_url})` :
'Not available';
// Create summary
const summary = `# 🔍 Quality Checks Summary
## Status Overview
| Check | Status | Details |
|-------|--------|---------|
| **Lint** | ✅ | ESLint passed |
| **TypeCheck** | ✅ | TypeScript compilation successful |
| **Tests** | ${testStatus} | ${testSummary} |
| **Coverage** | ${coverageStatus} | ${coverageSummary} |
| **Security Audit** | ✅ | npm audit passed (high+ vulnerabilities) |
| **Secret Scan** | ${gitleaksStatus} | ${gitleaksSummary} |
## Coverage Details
- **Threshold**: 95% (${coverageStatus === '✅' ? 'PASSED' : 'FAILED'})
- **Current**: ${coveragePercent}
- **Report**: ${coverageUrl}
## Security Checks
- ✅ **npm audit**: No high+ severity vulnerabilities found
- ${gitleaksStatus} **Gitleaks**: ${gitleaksSummary}
## Artifacts
- 📊 **Coverage Report**: ${coverageUrl}
---
*Generated by GitHub Actions*`;
await github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: summary
}).catch(() => {
// If not a PR, just log the summary
console.log('Job Summary:', summary);
});
// Also set as job summary
core.summary
.addHeading('Quality Checks Summary')
.addTable([
[{data: 'Check', header: true}, {data: 'Status', header: true}, {data: 'Details', header: true}],
['Lint', '✅', 'ESLint passed'],
['TypeCheck', '✅', 'TypeScript compilation successful'],
['Tests', testStatus, testSummary],
['Coverage', coverageStatus, coverageSummary],
['Security Audit', '✅', 'npm audit passed (high+ vulnerabilities)'],
['Secret Scan', gitleaksStatus, gitleaksSummary]
])
.addHeading('Coverage Details', 2)
.addRaw('')
.addRaw(`- **Threshold**: 95% (${coverageStatus === '✅' ? 'PASSED' : 'FAILED'})\n`)
.addRaw(`- **Current**: ${coveragePercent}\n`)
.addRaw(`- **Report**: ${coverageUrl}\n`)
.addHeading('Security Checks', 2)
.addRaw('')
.addRaw(`- ✅ **npm audit**: No high+ severity vulnerabilities found\n`)
.addRaw(`- ${gitleaksStatus} **Gitleaks**: ${gitleaksSummary}\n`)
.addHeading('Artifacts', 2)
.addRaw('')
.addRaw(`- 📊 **Coverage Report**: ${coverageUrl}\n`)
.write();
// Optional: Email notification on failure (commented out)
/*
// Uncomment to enable email notifications on failure
if (context.job === 'checks' && context.payload.action === 'completed' && context.payload.workflow_run.conclusion === 'failure') {
const emailSummary = `# ❌ Quality Checks Failed
## Failed Checks
- Repository: ${context.repo.owner}/${context.repo.repo}
- Branch: ${context.payload.head_branch || 'main'}
- Workflow: ${context.workflow}
- Run ID: ${context.runId}
- Commit: ${context.sha}
## Next Steps
1. Check the [workflow logs](https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId})
2. Fix the failing checks
3. Push a new commit to retry
---
*This is an automated notification from GitHub Actions*`;
// Add to job summary for visibility
core.summary
.addHeading('❌ Failure Notification', 1)
.addRaw(emailSummary)
.write();
}
*/