Cognitive Code Analysis is designed to run in continuous integration pipelines. You can analyse only the PHP files changed in a pull or merge request, publish the results as a comment, and upload reports as build artifacts.
This guide includes workflow examples originally shared in GitHub issue #29.
A typical CI integration follows these steps:
- Check out the repository with full git history (
fetch-depth: 0) - Determine which PHP files changed compared to the target branch
- Run
bin/phpcca analyseon those files only - Publish the report (Markdown comment, SARIF upload, or quality gate)
When phpcca.yaml exists in the project root, analyse loads it automatically. Use --config=path/to/config.yaml to override.
| Format | --report-type |
Use case |
|---|---|---|
| Markdown | markdown |
Human-readable PR/MR comments |
| GitHub Actions | github-actions |
Inline annotations in Actions logs |
| SARIF | sarif |
GitHub Code Scanning |
| GitLab Code Quality | gitlab-codequality |
GitLab merge request widget |
| Checkstyle XML | checkstyle |
Jenkins, Maven Checkstyle Plugin |
| JUnit XML | junit |
Jenkins JUnit plugin, build failure gates |
Example:
bin/phpcca analyse src/ChangedFile.php --report-type=sarif --report-file=results.sarifSee Baseline Analysis to compare metrics against a previous run using --baseline or --generate-baseline.
The workflow below runs on pull requests, analyses changed PHP files, posts a Markdown report as a PR comment, and uploads the report as an artifact.
Add --config=phpcca.yaml if your config file is not named phpcca.yaml or not in the working directory.
name: Code Metrics
on:
pull_request:
paths:
- '**/*.php'
branches:
- '*'
permissions:
pull-requests: write
contents: read
jobs:
code-metrics:
name: Cognitive Code Analysis
runs-on: ubuntu-24.04
if: github.event_name == 'pull_request'
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Fetch base branch
run: |
git fetch origin ${{ github.base_ref }}:${{ github.base_ref }}
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.4'
extensions: json, fileinfo
tools: composer
- name: Install dependencies
run: composer install --prefer-dist --no-ansi --no-interaction --no-progress --no-scripts
- name: Analyze changed PHP files
id: analyze
run: |
BASE_SHA="${{ github.event.pull_request.base.sha }}"
HEAD_SHA="${{ github.sha }}"
CHANGED_FILES=$(git diff --name-only --diff-filter=ACMR $BASE_SHA...$HEAD_SHA | grep '\.php$' | tr '\n' ' ' || echo "")
if [ -n "$CHANGED_FILES" ]; then
echo "Analyzing files: $CHANGED_FILES"
bin/phpcca analyse $CHANGED_FILES --report-type=markdown --report-file=cca-report.md || true
if [ -f "cca-report.md" ] && [ -s "cca-report.md" ]; then
echo "has_report=true" >> $GITHUB_OUTPUT
echo "Report generated successfully"
else
echo "has_report=false" >> $GITHUB_OUTPUT
echo "No report generated"
fi
else
echo "has_report=false" >> $GITHUB_OUTPUT
echo "No PHP files changed, skipping analysis"
fi
- name: Post comment to PR
if: steps.analyze.outputs.has_report == 'true'
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const report = fs.readFileSync('cca-report.md', 'utf8');
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: report
});
- name: Upload report artifact
if: always()
uses: actions/upload-artifact@v4
with:
name: cca-report
path: cca-report.md
if-no-files-found: ignoreReplace the Markdown report step with:
bin/phpcca analyse $CHANGED_FILES --report-type=sarif --report-file=results.sarifThen upload results.sarif using the GitHub Code Scanning upload action.
The job below runs on merge requests, analyses changed PHP files, posts a Markdown report as an MR note, and stores the report as an artifact.
Use --config=phpcca.yaml when your config file is not auto-discovered from the project root.
Code-Metrics:
interruptible: true
extends: .setup_composer_install
image: registry.gitlab.com/clipmyhorsetv/infrastructure/php_docker_images:8.4-nginx-php-dev
stage: tests
dependencies:
- PHP-Unit
variables:
GIT_DEPTH: 0
before_script:
- git config --global --add safe.directory $CI_PROJECT_DIR
- git fetch origin $CI_MERGE_REQUEST_TARGET_BRANCH_NAME:$CI_MERGE_REQUEST_TARGET_BRANCH_NAME
script:
- composer install --prefer-dist --no-ansi --no-interaction --no-progress --no-scripts
- |
if [ "$CI_PIPELINE_SOURCE" = "merge_request_event" ] && [ -n "$CI_MERGE_REQUEST_DIFF_BASE_SHA" ]; then
CHANGED_FILES=$(git diff --name-only --diff-filter=ACMR $CI_MERGE_REQUEST_DIFF_BASE_SHA...$CI_COMMIT_SHA | grep '\.php$' | tr '\n' ' ')
else
CHANGED_FILES=$(find src/ -name "*.php" | tr '\n' ' ')
fi
if [ -n "$CHANGED_FILES" ]; then
bin/phpcca analyse $CHANGED_FILES --report-type=markdown --report-file=cca-report.md --config=phpcca.yaml
if [ -f "cca-report.md" ] && [ -s "cca-report.md" ]; then
# Try with CI_JOB_TOKEN first, fallback to CI/CD variables
if [ -n "$VALIDATOR" ]; then
TOKEN="$VALIDATOR"
else
TOKEN="$CI_JOB_TOKEN"
fi
echo "Posting comment to merge request $CI_MERGE_REQUEST_IID..."
echo "Report content preview:"
head -5 cca-report.md
# Use POST with body as query parameter as per GitLab API documentation
RESPONSE=$(curl -s -w "\n%{http_code}" --request POST --header "PRIVATE-TOKEN: $TOKEN" \
--data-urlencode "body=$(cat cca-report.md)" \
"https://gitlab.com/api/v4/projects/$CI_PROJECT_ID/merge_requests/$CI_MERGE_REQUEST_IID/notes")
HTTP_CODE=$(echo "$RESPONSE" | tail -1)
RESPONSE_BODY=$(echo "$RESPONSE" | head -n -1)
echo "HTTP Response Code: $HTTP_CODE"
echo "Response Body: $RESPONSE_BODY"
if [ "$HTTP_CODE" = "201" ]; then
echo "Comment posted successfully"
else
echo "Failed to post comment. HTTP Code: $HTTP_CODE"
fi
fi
else
echo "No PHP files changed, skipping analysis"
echo "[]" > cca-report.md
fi
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
changes:
compare_to: "refs/heads/$CI_DEFAULT_BRANCH"
paths:
- '**/*.php'
- when: never
artifacts:
when: always
paths:
- cca-report.mdReplace the Markdown report with:
bin/phpcca analyse $CHANGED_FILES --report-type=gitlab-codequality --report-file=gl-code-quality.jsonGitLab picks up the Code Quality report automatically when configured in your pipeline.
- Analyse only changed files in PR/MR pipelines to keep feedback fast and relevant.
- Use baselines to show deltas between runs; see Baseline Analysis.
- Disable cache in CI if you want a fresh analysis every run:
cognitive: cache: enabled: false
- Fail the build on complexity regressions using
--report-type=junitor--report-type=checkstylewith your CI platform's quality gate support.
- Configuration — project setup with
bin/phpcca initandphpcca.yaml - Baseline Analysis — track complexity changes over time
- Creating Custom Reporters — extend report output for custom CI integrations
- Issue #29 — original feature discussion for GitHub Actions and branch comparison