-
Notifications
You must be signed in to change notification settings - Fork 2
Feature/metrics dashboard #156
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- Add phploc and phpmd composer dependencies for code metrics - Create phpmd.xml configuration for complexity analysis - Create .jscpd.json for PHP/JS/CSS duplication detection - Add CI jobs for metrics generation: - metrics-coverage: PHPUnit with clover XML and HTML reports - metrics-static-analysis: PHPStan and PHPCS JSON output - metrics-security: phpcs-security-audit JSON output - metrics-complexity: PHPLOC and PHPMD JSON output - metrics-duplication: jscpd for PHP, JavaScript, and CSS - Create metrics.yml workflow to process and deploy dashboard - Add Python script to parse all metrics and generate: - Interactive HTML dashboard with Chart.js trends - SVG badges for each metric category - JSON API endpoint for programmatic access - Historical data with 90-day retention - Add test fixtures for local script development - Add code quality badges to README linking to dashboard Dashboard will be available at: https://matthewdeaves.github.io/willow/metrics/ Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove phploc from composer.json (conflicts with phpunit via sebastian/version) - Replace phploc with PHPMD for complexity metrics in all workflows - Use defusedxml for secure XML parsing (fixes Semgrep security warning) - Update dashboard template to show PHPMD violations instead of phploc metrics - Update Python script to use PHPMD data throughout - Add PHPMD and Duplication badges to README - Remove unused phploc fixture file Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
jscpd returns exit code 1 when duplicates are found, which is expected behavior. Add || true to allow the workflow to continue and upload the report regardless of the exit code. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
CakePHP 5.2.11 (released Jan 9, 2026) has a bug with PHP 8.1 that causes "Cannot use 'Cake\ORM\Behavior\true' as class name" error in TreeBehavior. Pin to <5.2.11 only for PHP 8.1 until fixed. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
| metrics-coverage: | ||
| runs-on: ubuntu-latest | ||
| name: Metrics - Coverage | ||
| needs: test | ||
|
|
||
| steps: | ||
| - uses: actions/checkout@v6 | ||
|
|
||
| - name: Setup MySQL | ||
| run: | | ||
| sudo service mysql start | ||
| mysql -e 'CREATE DATABASE IF NOT EXISTS cms_test;' -uroot -proot | ||
| - name: Setup Redis | ||
| run: | | ||
| sudo apt-get update | ||
| sudo apt-get install -y redis-server | ||
| sudo service redis-server start | ||
| - name: Setup PHP | ||
| uses: shivammathur/setup-php@v2 | ||
| with: | ||
| php-version: '8.3' | ||
| extensions: mbstring, intl, pdo_mysql, pcntl, sockets, bcmath, zip | ||
| coverage: xdebug | ||
|
|
||
| - name: Install Composer dependencies | ||
| run: composer update --no-interaction --prefer-dist | ||
|
|
||
| - name: Copy Configs | ||
| run: | | ||
| cp docker/github/app_local.php config/app_local.php | ||
| cp docker/github/app.php config/app.php | ||
| - name: Run PHPUnit with Coverage | ||
| run: | | ||
| php -d display_errors=on vendor/bin/phpunit \ | ||
| --coverage-clover coverage.xml \ | ||
| --coverage-html coverage-html/ \ | ||
| --coverage-text | ||
| env: | ||
| XDEBUG_MODE: coverage | ||
| REDIS_HOST: 127.0.0.1 | ||
| REDIS_PORT: 6379 | ||
| REDIS_PASSWORD: "" | ||
| REDIS_URL: "redis://127.0.0.1:6379/0" | ||
|
|
||
| - name: Upload Coverage Artifacts | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: phpunit-coverage | ||
| path: | | ||
| coverage.xml | ||
| coverage-html/ | ||
| retention-days: 30 | ||
|
|
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
| metrics-static-analysis: | ||
| runs-on: ubuntu-latest | ||
| name: Metrics - Static Analysis | ||
|
|
||
| steps: | ||
| - uses: actions/checkout@v6 | ||
|
|
||
| - name: Setup PHP | ||
| uses: shivammathur/setup-php@v2 | ||
| with: | ||
| php-version: '8.3' | ||
| extensions: mbstring, intl | ||
|
|
||
| - name: Install Composer dependencies | ||
| run: composer update --no-interaction --prefer-dist | ||
|
|
||
| - name: Run PHPStan (JSON output) | ||
| run: | | ||
| php -d memory_limit=-1 vendor/bin/phpstan analyse src/ \ | ||
| --error-format=json > phpstan.json || true | ||
| - name: Run PHP CodeSniffer (JSON output) | ||
| run: | | ||
| vendor/bin/phpcs \ | ||
| --standard=vendor/cakephp/cakephp-codesniffer/CakePHP \ | ||
| --report=json src/ tests/ > phpcs.json || true | ||
| - name: Upload PHPStan Results | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: phpstan-results | ||
| path: phpstan.json | ||
| retention-days: 30 | ||
|
|
||
| - name: Upload PHPCS Results | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: phpcs-results | ||
| path: phpcs.json | ||
| retention-days: 30 | ||
|
|
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 6 days ago
In general, the fix is to add an explicit permissions block that scopes down the GITHUB_TOKEN to only what the workflow needs. In this workflow, all shown jobs (security, metrics-coverage, metrics-static-analysis, metrics-security, metrics-duplication, etc.) only need to read repository contents (for actions/checkout) and upload artifacts, which does not require any special write scopes to the repository. Therefore, the best minimal fix is to add a single root-level permissions block with contents: read, which applies to all jobs that do not override it.
Concretely, in .github/workflows/ci.yml, insert:
permissions:
contents: readnear the top of the file, after the name: CI line and before the on: trigger block. This will ensure that every job, including the one beginning at line 167, runs with a read-only GITHUB_TOKEN for repository contents. No additional imports or methods are required; this is purely a YAML workflow configuration change and does not alter the functional behavior of the jobs, since none of them currently rely on write permissions.
-
Copy modified lines R3-R5
| @@ -1,5 +1,8 @@ | ||
| name: CI | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| on: | ||
| push: | ||
| branches: |
| metrics-security: | ||
| runs-on: ubuntu-latest | ||
| name: Metrics - Security | ||
|
|
||
| steps: | ||
| - uses: actions/checkout@v6 | ||
|
|
||
| - name: Setup PHP | ||
| uses: shivammathur/setup-php@v2 | ||
| with: | ||
| php-version: '8.3' | ||
| extensions: mbstring, intl | ||
|
|
||
| - name: Install Composer dependencies | ||
| run: composer update --no-interaction --prefer-dist | ||
|
|
||
| - name: Run Security Audit (JSON output) | ||
| run: | | ||
| vendor/bin/phpcs --standard=phpcs-security.xml \ | ||
| --report=json src/ > security-phpcs.json || true | ||
| - name: Upload Security Results | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: security-results | ||
| path: security-phpcs.json | ||
| retention-days: 30 | ||
|
|
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 6 days ago
In general, the fix is to explicitly define a minimal permissions: block so the GITHUB_TOKEN has only the scopes required. For this workflow, all shown jobs are CI/metrics jobs that only need to read the repository (via actions/checkout) and upload artifacts; they do not need to write to repository contents, issues, or pull requests. Therefore, setting permissions: contents: read at the top level of the workflow is sufficient and avoids repeating the same block in each job.
The single best change with minimal functional impact is to add a root-level permissions: section just under the name: CI line (and before on:). This will apply to all jobs in the workflow, including metrics-security, metrics-static-analysis, metrics-complexity, and metrics-duplication, unless any job overrides it with its own permissions: block. No other code or steps need to change, and no new imports or actions are required.
Concretely:
- Edit
.github/workflows/ci.yml. - Insert:
permissions:
contents: readimmediately after the existing name: CI line at the top of the file. This ensures CodeQL sees an explicit permission limitation and that the GITHUB_TOKEN is restricted to read-only contents access for the entire workflow.
-
Copy modified lines R3-R5
| @@ -1,5 +1,8 @@ | ||
| name: CI | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| on: | ||
| push: | ||
| branches: |
| metrics-complexity: | ||
| runs-on: ubuntu-latest | ||
| name: Metrics - Complexity | ||
|
|
||
| steps: | ||
| - uses: actions/checkout@v6 | ||
|
|
||
| - name: Setup PHP | ||
| uses: shivammathur/setup-php@v2 | ||
| with: | ||
| php-version: '8.3' | ||
| extensions: mbstring, intl | ||
|
|
||
| - name: Install Composer dependencies | ||
| run: composer update --no-interaction --prefer-dist | ||
|
|
||
| - name: Run PHPMD (JSON output) | ||
| run: vendor/bin/phpmd src/ json phpmd.xml > phpmd.json || true | ||
|
|
||
| - name: Upload Complexity Results | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: complexity-results | ||
| path: phpmd.json | ||
| retention-days: 30 | ||
|
|
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 6 days ago
In general, fix this by explicitly declaring minimal GITHUB_TOKEN permissions either at the workflow root (affecting all jobs without their own permissions) or at the specific job level. For these metrics jobs, they only need to read the repository contents and upload artifacts, which does not require any extra GitHub write scopes, so contents: read is sufficient.
The single best, non-invasive fix is to add a permissions block at the top level of .github/workflows/ci.yml, just under the name: CI line and before on:, setting contents: read. This will apply to all jobs (including metrics-complexity) that do not override it, tightening GITHUB_TOKEN while preserving existing functionality. No additional imports or dependencies are needed; we are only changing workflow configuration.
Concretely:
- Edit
.github/workflows/ci.yml. - After line
1: name: CI, insert:permissions: contents: read
- Leave all job definitions and steps unchanged.
-
Copy modified lines R2-R3
| @@ -1,4 +1,6 @@ | ||
| name: CI | ||
| permissions: | ||
| contents: read | ||
|
|
||
| on: | ||
| push: |
| metrics-duplication: | ||
| runs-on: ubuntu-latest | ||
| name: Metrics - Duplication | ||
|
|
||
| steps: | ||
| - uses: actions/checkout@v6 | ||
|
|
||
| - name: Setup Node.js | ||
| uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: '20' | ||
|
|
||
| - name: Run jscpd | ||
| run: | | ||
| npx jscpd src/ plugins/ webroot/ --reporters json --output jscpd-report/ || true | ||
| - name: Upload Duplication Results | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: duplication-results | ||
| path: jscpd-report/ |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 6 days ago
In general, the fix is to explicitly specify minimal GITHUB_TOKEN permissions for the workflow or for the specific job. Since the metrics jobs only need to read the repository contents and upload artifacts, the minimal safe permission is contents: read. This prevents the job from inheriting potentially broader repo/org defaults.
The best targeted fix here is to add a permissions block to the metrics-duplication job (the one CodeQL flags at line 262). That job uses actions/checkout, actions/setup-node, runs npx jscpd, and uploads artifacts; none of these require write access to the repo. We can therefore insert:
permissions:
contents: readdirectly under the job name (e.g., after metrics-duplication: and before runs-on:). This change is localized to the shown snippet, does not alter functionality, and satisfies the least-privilege recommendation. No imports or additional methods are necessary because this is pure workflow-configuration.
-
Copy modified lines R262-R263
| @@ -259,6 +259,8 @@ | ||
| retention-days: 30 | ||
|
|
||
| metrics-duplication: | ||
| permissions: | ||
| contents: read | ||
| runs-on: ubuntu-latest | ||
| name: Metrics - Duplication | ||
|
|
The defusedxml import is already in place with fallback. Adding nosemgrep comment to suppress the false positive since ET could be defusedxml.ElementTree when the package is installed. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Since the metrics workflow always installs defusedxml, use it directly instead of a try/except fallback. This is the proper fix for the Semgrep XML security warning. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
No description provided.