Implementing Code Quality Workflows
1. Running CodeQL Analysis
CodeQL is a powerful static analysis engine that helps identify security vulnerabilities and code quality issues in your GitHub Actions workflows.
| Property | Description | Default Value |
|---|---|---|
| uses | Specifies the CodeQL action to run | github/codeql-action/analyze@v2 |
| with.language | Programming language to analyze (e.g., javascript, python) |
Detected from the repository |
| with.category | Category of analysis to run (e.g., security-and-quality) |
security-and-quality |
Example: Running CodeQL Analysis
name: "CodeQL Analysis"
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: javascript
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
Note: CodeQL analysis requires the
actions/checkout step to be run before initializing the CodeQL action.
Warning: Ensure that the
languages parameter matches the languages used in your project to avoid missing vulnerabilities.
Key Points
- CodeQL is a static analysis tool that detects security vulnerabilities and code quality issues.
- It can be integrated into GitHub Actions workflows to run automatically on push or pull request events.
- CodeQL supports multiple programming languages including JavaScript, Python, Java, and more.
2. Using SonarCloud
| Property | Description | Default |
|---|---|---|
| sonar.projectKey | Unique key for the project in SonarCloud | Derived from repository name |
| sonar.sources | Path to source files | . |
| sonar.tests | Path to test files | src/test |
| sonar.language | Programming language of the project | Determined automatically |
| sonar.coverage.exclusions | Paths to exclude from coverage reports | None |
Example: SonarCloud Analysis
name: SonarCloud Analysis
on:
push:
branches:
- main
jobs:
analyze:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up JDK
uses: actions/setup-java@v3
with:
java-version: "17"
distribution: "temurin"
- name: Cache SonarCloud packages
uses: actions/cache@v3
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
restore-keys: ${{ runner.os }}-sonar
- name: Analyze with SonarCloud
uses: sonarqube-community/sonarcloud-github-action@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
Note: Ensure the
SONAR_TOKEN is set in your repository secrets.
Key Features
- Automated code quality analysis
- Coverage reporting
- Bug and vulnerability detection
- Code duplication detection
- Supports multiple languages (Java, JavaScript, Python, etc.)
3. Using ESLint
| Option | Values | Notes |
|---|---|---|
| extends | "eslint:recommended" |
Base ESLint ruleset |
| rules | { "no-console": "warn" } |
Custom rule overrides |
| env | { "browser": true, "node": true } |
Environment-specific globals |
Example: ESLint Configuration
{
"extends": ["eslint:recommended"],
"rules": {
"no-console": "warn",
"no-unused-vars": "error"
},
"env": {
"browser": true,
"node": true
}
}
Example: GitHub Action Workflow
name: Lint Code
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
- name: Install dependencies
run: npm install
- name: Run ESLint
run: npx eslint .
4. Using Prettier
| Option | Values | Notes |
|---|---|---|
| prettier.config.js | { "semi": true, "singleQuote": true } |
Configuration file for Prettier settings |
| prettier.ignore | node_modules/ |
Directories or files to ignore during formatting |
Example: Format JavaScript files with Prettier
const fs = require('fs');
const prettier = require('prettier');
const fileContent = fs.readFileSync('./src/index.js', 'utf8');
const formattedContent = prettier.format(fileContent, {
parser: 'babel',
semi: true,
singleQuote: true
});
fs.writeFileSync('./src/index.js', formattedContent);
Example: GitHub Actions workflow using Prettier
name: Format with Prettier
on:
push:
branches: [ main ]
jobs:
format:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install Prettier
run: npm install --save-dev prettier
- name: Format code
run: npx prettier --write .
Note: Prettier can be integrated into CI pipelines to enforce consistent code formatting across all contributions.
5. Using Dependency Scanning
Dependency scanning in GitHub Actions helps identify vulnerabilities in project dependencies. It integrates with tools like dependency-check, Snyk, and OWASP Dependency-Check.
| Tool | Description | Integration | Scan Type |
|---|---|---|---|
| Snyk | Security platform for identifying vulnerabilities in dependencies | snyk/monitor or snyk/snyk-action |
Static Analysis |
| OWASP Dependency-Check | Open-source tool for identifying vulnerable dependencies | owasp/dependency-check-action |
Static Analysis |
| GitHub Security Advisory | Automatically scans for known vulnerabilities in dependencies | github/codeql-action/analyze |
Static Analysis |
Example: Snyk Dependency Scan
name: Snyk Dependency Scan
on:
push:
branches: [ main ]
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Snyk to check for vulnerabilities
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
Example: OWASP Dependency Check
name: OWASP Dependency Check
on:
schedule:
- cron: '0 0 * * 0'
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run OWASP Dependency Check
uses: owasp/dependency-check-action@v2.1.0
with:
project: my-project
outdir: ./reports
Note: Ensure that the
SNYK_TOKEN or other credentials are stored in GitHub Secrets for secure access.
Warning: Regular dependency scans should be scheduled to detect new vulnerabilities as they are discovered.
6. Scanning for Secrets
| Option | Values | Notes |
|---|---|---|
| github.token | secrets.GITHUB_TOKEN |
Default token with read/write permissions for the repository |
| scan.secrets | true |
Enable secret scanning in the workflow |
| fail-on-secrets | true |
Fail the workflow if secrets are detected |
Example: Secret Scanning Workflow
name: Scan for Secrets
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
scan-secrets:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Scan for secrets
uses: github/super-linter@v5
env:
VALIDATE_ALL_CODEBASE: true
DEFAULT_BRANCH: main
Note: The
github/super-linter action includes secret scanning capabilities by default. Ensure that VALIDATE_ALL_CODEBASE is set to true for comprehensive scanning.
Warning: Never commit secrets to your repository. Use GitHub Actions secrets or environment variables for sensitive data.
7. Running Security Audits
| Step | Description | Action | Notes |
|---|---|---|---|
| 1 | Set up a workflow file | workflow_dispatch trigger |
Initiates the workflow manually or on schedule |
| 2 | Install security tools | actions/checkout and github/codeql-action/init |
Clones repo and initializes CodeQL for scanning |
| 3 | Run security scan | github/codeql-action/analyze |
Scans code for vulnerabilities and security issues |
| 4 | Upload results | github/codeql-action/upload |
Uploads scan results to GitHub for review |
Example: Security Audit Workflow
name: Security Audit
on:
workflow_dispatch:
schedule:
- cron: '0 0 * * 0'
jobs:
security-scan:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: javascript
- name: Perform scan
uses: github/codeql-action/analyze@v2
Note: Ensure that the workflow runs with appropriate permissions to access and upload scan results.
8. Using License Checkers
| Checker | Description | Usage | Notes |
|---|---|---|---|
| licensee | License checker for Ruby gems, npm packages, and more | licensee check |
Supports multiple ecosystems; can be integrated into CI |
| fossa | Enterprise-grade license compliance tool | fossa analyze |
Requires API key; provides detailed reports |
| scanoss | Open source license scanner with GitHub integration | scanoss scan |
Supports multiple languages and platforms |
Example: Using licensee in GitHub Actions
name: License Check
on:
push:
branches: [ main ]
jobs:
license-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install licensee
run: gem install licensee
- name: Run license check
run: licensee check
Note: licensee checks for license compatibility and ensures no prohibited licenses are used in dependencies.
9. Generating Code Metrics
| Metric | Description | Tool | Configuration |
|---|---|---|---|
| Lines of Code (LOC) | Total lines in the codebase | codecov |
coverage: 100% |
| Code Coverage | Percentage of code executed by tests | cobertura |
threshold: 80% |
| Cyclomatic Complexity | Measures the number of linearly independent paths through code | sonarqube |
max: 10 |
| Maintainability Index | Quantifies how maintainable the code is | sonarqube |
score: > 50 |
| Code Duplication | Percentage of duplicated code blocks | simian |
threshold: 5% |
Example: Setting up Code Coverage with Jest
{
"scripts": {
"test": "jest --coverage"
},
"jest": {
"collectCoverageFrom": [
"src/**/*.{js,ts}"
]
}
}
Example: Using Codecov to Upload Coverage Reports
name: Code Coverage
on:
push:
branches: [ main ]
jobs:
coverage:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install dependencies
run: npm install
- name: Run tests with coverage
run: npm test
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
file: ./coverage/lcov.info
Note: Ensure that your CI pipeline includes a step to generate and upload coverage reports for accurate metric tracking.
10. Creating Quality Gates
Example: Basic Quality Gate Workflow
name: Code Quality Gates
on:
pull_request:
branches: [ main ]
jobs:
quality-gate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run linter
run: |
npm install
npm run lint
- name: Run tests
run: npm test
| Step | Description | Configuration |
|---|---|---|
| on.pull_request | Triggers workflow on pull request to main branch | branches: [ main ] |
| jobs.quality-gate.runs-on | Runner environment for quality checks | ubuntu-latest |
| steps.name | Step name for clarity in logs | Any descriptive string |
Note: Quality gates ensure code meets standards before merging. This example includes linting and testing steps.
Quality Gate vs. Continuous Integration
- Quality Gate: Enforces strict criteria before merging
- CI: Runs tests on every commit, but doesn't block merges
11. Commenting on PRs
| Option | Values | Notes |
|---|---|---|
| github.event.pull_request.number | 123 |
PR number from event |
| github.event.pull_request.head.sha | abc123def456... |
Head commit SHA |
| github.token | ${{ secrets.GITHUB_TOKEN }} |
Token with write permissions |
Example: Comment on PR with linting results
name: Comment on PR
on:
pull_request:
types: [opened, synchronize]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run linter
run: |
npm install
npx eslint src/
- name: Comment on PR
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const fs = require('fs');
const results = fs.readFileSync('lint-results.txt', 'utf8');
await github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `Linting issues found:\n\`\`\`\n${results}\n\`\`\``
});
Note: Requires
pull_request or push trigger to access PR context.
Warning: Avoid excessive comments that can spam the PR conversation.
12. Using Pre-commit Hooks
| Hook Type | Description | Configuration | Example |
|---|---|---|---|
| pre-commit | Runs before committing code | .pre-commit-config.yaml |
|
| pre-push | Runs before pushing to remote | .pre-commit-config.yaml |
|
Example: Setting up pre-commit hooks in GitHub Actions
name: Pre-commit Checks
on:
pull_request:
branches: [ main ]
jobs:
pre-commit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Install pre-commit
run: pip install pre-commit
- name: Run pre-commit hooks
run: pre-commit run --all-files
Note: Ensure
.pre-commit-config.yaml is committed to the repository for hooks to be enforced.
Warning: If pre-commit hooks fail, the GitHub Actions job will also fail and prevent the commit/push.