Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 36 additions & 3 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -164,16 +164,26 @@ jobs:
name: Validate Composer configuration is normalized
command: docker compose exec -T cli composer normalize --dry-run || [ "${VORTEX_CI_COMPOSER_NORMALIZE_IGNORE_FAILURE:-0}" -eq 1 ]

#;< TOOL_CODE_QUALITY_REPORTS
- run:
name: Prepare code quality report directory
command: docker compose exec -T cli mkdir -p .logs/lint
#;> TOOL_CODE_QUALITY_REPORTS

#;< TOOL_PHPCS
- run:
name: Lint code with PHPCS
command: docker compose exec -T cli vendor/bin/phpcs || [ "${VORTEX_CI_PHPCS_IGNORE_FAILURE:-0}" -eq 1 ]
command: docker compose exec -T cli vendor/bin/phpcs --report-full --report-checkstyle=.logs/lint/phpcs.xml || [ "${VORTEX_CI_PHPCS_IGNORE_FAILURE:-0}" -eq 1 ]
#;> TOOL_PHPCS

#;< TOOL_PHPSTAN
- run:
name: Lint code with PHPStan
command: docker compose exec -T cli vendor/bin/phpstan || [ "${VORTEX_CI_PHPSTAN_IGNORE_FAILURE:-0}" -eq 1 ]
# PHPStan emits one format per run, so the console run is repeated to
# carry the step's exit code.
command: |
docker compose exec -T cli sh -c 'vendor/bin/phpstan --no-progress --error-format=checkstyle > .logs/lint/phpstan.xml' || true
docker compose exec -T cli vendor/bin/phpstan || [ "${VORTEX_CI_PHPSTAN_IGNORE_FAILURE:-0}" -eq 1 ]
#;> TOOL_PHPSTAN

#;< TOOL_RECTOR
Expand All @@ -185,7 +195,11 @@ jobs:
#;< TOOL_TWIG_CS_FIXER
- run:
name: Lint code with Twig CS Fixer
command: docker compose exec -T cli vendor/bin/twig-cs-fixer || [ "${VORTEX_CI_TWIG_CS_FIXER_IGNORE_FAILURE:-0}" -eq 1 ]
# Twig CS Fixer emits one format per run, so the console run is
# repeated to carry the step's exit code.
command: |
docker compose exec -T cli sh -c 'vendor/bin/twig-cs-fixer --report=checkstyle > .logs/lint/twig-cs-fixer.xml' || true
docker compose exec -T cli vendor/bin/twig-cs-fixer || [ "${VORTEX_CI_TWIG_CS_FIXER_IGNORE_FAILURE:-0}" -eq 1 ]
#;> TOOL_TWIG_CS_FIXER

#;< TOOL_BEHAT
Expand All @@ -208,6 +222,25 @@ jobs:
#;> DRUPAL_THEME
#;> TOOL_ESLINT_STYLELINT

#;< TOOL_CODE_QUALITY_REPORTS
- run:
name: Process code quality reports
command: |
mkdir -p "${VORTEX_CI_ARTIFACTS}"
if docker compose ps --services --filter "status=running" | grep -q cli && docker compose exec -T cli test -d /app/.logs; then
docker compose --progress quiet cp cli:/app/.logs/. "${VORTEX_CI_ARTIFACTS}/"
fi
# Reports name files by their path inside the container, which
# does not exist outside it.
if [ -d "${VORTEX_CI_ARTIFACTS}/lint" ]; then
find "${VORTEX_CI_ARTIFACTS}/lint" -name '*.xml' -exec sed -i 's| name="/app/| name="|g' {} +
fi
when: always

- store_artifacts:
path: *artifacts
#;> TOOL_CODE_QUALITY_REPORTS

# Audit job runs in its own workflow, independently of the commit workflow.
audit:
<<: *runner_config
Expand Down
48 changes: 44 additions & 4 deletions .github/workflows/build-test-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -157,27 +157,43 @@ jobs:
run: docker compose exec -T cli composer normalize --dry-run
continue-on-error: ${{ vars.VORTEX_CI_COMPOSER_NORMALIZE_IGNORE_FAILURE == '1' }}

#;< TOOL_CODE_QUALITY_REPORTS
- name: Prepare code quality report directory
run: docker compose exec -T cli mkdir -p .logs/lint
#;> TOOL_CODE_QUALITY_REPORTS

#;< TOOL_PHPCS
- name: Lint code with PHPCS
run: docker compose exec -T cli vendor/bin/phpcs
run: docker compose exec -T cli vendor/bin/phpcs --report-full --report-checkstyle=.logs/lint/phpcs.xml
continue-on-error: ${{ vars.VORTEX_CI_PHPCS_IGNORE_FAILURE == '1' }}
#;> TOOL_PHPCS

#;< TOOL_PHPSTAN
- name: Lint code with PHPStan
run: docker compose exec -T cli vendor/bin/phpstan
# PHPStan emits one format per run, so the annotating run is repeated
# to carry the step's exit code.
run: |
docker compose exec -T cli sh -c 'vendor/bin/phpstan --no-progress --error-format=checkstyle > .logs/lint/phpstan.xml' || true
docker compose exec -T cli vendor/bin/phpstan --no-progress --error-format=github
continue-on-error: ${{ vars.VORTEX_CI_PHPSTAN_IGNORE_FAILURE == '1' }}
#;> TOOL_PHPSTAN

#;< TOOL_RECTOR
- name: Lint code with Rector
run: docker compose exec -T cli vendor/bin/rector --dry-run
# Rector has no checkstyle or JUnit formatter, so it annotates without
# writing a report.
run: docker compose exec -T cli vendor/bin/rector --dry-run --output-format=github
continue-on-error: ${{ vars.VORTEX_CI_RECTOR_IGNORE_FAILURE == '1' }}
#;> TOOL_RECTOR

#;< TOOL_TWIG_CS_FIXER
- name: Lint code with Twig CS Fixer
run: docker compose exec -T cli vendor/bin/twig-cs-fixer
# Twig CS Fixer emits one format per run, so the annotating run is
# repeated to carry the step's exit code. It names files by their path
# inside the container, which does not exist outside it.
run: |
docker compose exec -T cli sh -c 'vendor/bin/twig-cs-fixer --report=checkstyle > .logs/lint/twig-cs-fixer.xml' || true
docker compose exec -T cli vendor/bin/twig-cs-fixer --report=github | sed 's|file=/app/|file=|'
continue-on-error: ${{ vars.VORTEX_CI_TWIG_CS_FIXER_IGNORE_FAILURE == '1' }}
#;> TOOL_TWIG_CS_FIXER

Expand All @@ -200,6 +216,30 @@ jobs:
#;> DRUPAL_THEME
#;> TOOL_ESLINT_STYLELINT

#;< TOOL_CODE_QUALITY_REPORTS
- name: Process code quality reports
if: always()
Comment thread
coderabbitai[bot] marked this conversation as resolved.
run: |
mkdir -p ".logs"
if docker compose ps --services --filter "status=running" | grep -q cli && docker compose exec -T cli test -d /app/.logs; then
docker compose --progress quiet cp cli:/app/.logs/. ".logs/"
Comment thread
coderabbitai[bot] marked this conversation as resolved.
fi
# Reports name files by their path inside the container, which does
# not exist outside it.
if [ -d ".logs/lint" ]; then
find .logs/lint -name '*.xml' -exec sed -i 's| name="/app/| name="|g' {} +
fi

- name: Upload code quality reports
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
if: always()
with:
name: lint-artifacts
path: .logs
include-hidden-files: true
if-no-files-found: warn
Comment thread
coderabbitai[bot] marked this conversation as resolved.
#;> TOOL_CODE_QUALITY_REPORTS

#;< !PROVISION_TYPE_PROFILE
database:
runs-on: ubuntu-latest
Expand Down
9 changes: 9 additions & 0 deletions .vortex/docs/content/continuous-integration/circleci.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,12 @@ Coverage reports can be posted as PR comments. This requires a `GITHUB_TOKEN`
environment variable with permission to post comments. Each new report replaces
the previous one - older comments are minimized to keep the PR timeline clean.
To disable PR comments, set `VORTEX_CI_CODE_COVERAGE_PR_COMMENT_SKIP` to `1`.

### Code quality results

PHPCS, PHPStan and Twig CS Fixer write a checkstyle report to `.logs/lint/`,
which the `lint` job stores as build artifacts. Each tool keeps its console
output and its `VORTEX_CI_<TOOL>_IGNORE_FAILURE` behavior.

CircleCI has no check annotations, so the reports are read from the
**Artifacts** tab. The same reports are annotated inline on GitHub Actions.
18 changes: 18 additions & 0 deletions .vortex/docs/content/continuous-integration/github-actions.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -238,3 +238,21 @@ Tests run across parallel build instances, so a separate check is created for
each instance (for example, `Test results (0)` and `Test results (1)`). To
disable publishing, set `VORTEX_CI_TEST_RESULTS_SKIP` to `1` in **Settings →
Secrets and variables → Actions → Variables**.

### Code quality results

PHPStan, Rector and Twig CS Fixer run with their own GitHub Actions output
format, so each finding is annotated against its own file and line and a
coding-standards failure no longer needs the job log to locate it. No extra
action or token is involved: the annotation is the tool's own output.

PHPCS, PHPStan and Twig CS Fixer also write a checkstyle report to
`.logs/lint/`, uploaded as the `lint-artifacts` artifact. Rector writes no
report, because it offers neither a checkstyle nor a JUnit formatter.

PHPCS is the one tool with no GitHub output format, so its findings are read
from the artifact rather than from an annotation.

Each tool keeps its `VORTEX_CI_<TOOL>_IGNORE_FAILURE` behavior. The annotating
tools print the annotation format instead of their usual table, so the job log
lists the same findings that appear on the diff.
6 changes: 6 additions & 0 deletions .vortex/installer/src/Prompts/Handlers/Tools.php
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,12 @@ public static function getToolDefinitions(string $filter = 'all'): array {
'/^\h*lint:\R\h*usage:\h*Lint back-end and front-end code\.\R\h*cmd:\h*\|\h*\R\h*$\R\h*$/um',
],
],
// Tools that write a checkstyle report for the CI annotation steps.
// Rector is absent: it has no checkstyle or JUnit output format.
'code_quality_reports' => [
'tools' => [self::PHPCS, self::PHPSTAN, self::TWIG_CS_FIXER],
'token' => 'TOOL_CODE_QUALITY_REPORTS',
],
'test' => [
'tools' => [self::PHPUNIT, self::BEHAT],
'ahoy' => [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,20 +138,34 @@ jobs:
run: docker compose exec -T cli composer normalize --dry-run
continue-on-error: ${{ vars.VORTEX_CI_COMPOSER_NORMALIZE_IGNORE_FAILURE == '1' }}

- name: Prepare code quality report directory
run: docker compose exec -T cli mkdir -p .logs/lint

- name: Lint code with PHPCS
run: docker compose exec -T cli vendor/bin/phpcs
run: docker compose exec -T cli vendor/bin/phpcs --report-full --report-checkstyle=.logs/lint/phpcs.xml
continue-on-error: ${{ vars.VORTEX_CI_PHPCS_IGNORE_FAILURE == '1' }}

- name: Lint code with PHPStan
run: docker compose exec -T cli vendor/bin/phpstan
# PHPStan emits one format per run, so the annotating run is repeated
# to carry the step's exit code.
run: |
docker compose exec -T cli sh -c 'vendor/bin/phpstan --no-progress --error-format=checkstyle > .logs/lint/phpstan.xml' || true
docker compose exec -T cli vendor/bin/phpstan --no-progress --error-format=github
continue-on-error: ${{ vars.VORTEX_CI_PHPSTAN_IGNORE_FAILURE == '1' }}

- name: Lint code with Rector
run: docker compose exec -T cli vendor/bin/rector --dry-run
# Rector has no checkstyle or JUnit formatter, so it annotates without
# writing a report.
run: docker compose exec -T cli vendor/bin/rector --dry-run --output-format=github
continue-on-error: ${{ vars.VORTEX_CI_RECTOR_IGNORE_FAILURE == '1' }}

- name: Lint code with Twig CS Fixer
run: docker compose exec -T cli vendor/bin/twig-cs-fixer
# Twig CS Fixer emits one format per run, so the annotating run is
# repeated to carry the step's exit code. It names files by their path
# inside the container, which does not exist outside it.
run: |
docker compose exec -T cli sh -c 'vendor/bin/twig-cs-fixer --report=checkstyle > .logs/lint/twig-cs-fixer.xml' || true
docker compose exec -T cli vendor/bin/twig-cs-fixer --report=github | sed 's|file=/app/|file=|'
continue-on-error: ${{ vars.VORTEX_CI_TWIG_CS_FIXER_IGNORE_FAILURE == '1' }}

- name: Lint code with Gherkin Lint
Expand All @@ -167,6 +181,28 @@ jobs:
run: docker compose exec -T cli bash -c "npm --prefix=\${WEBROOT}/themes/custom/\${DRUPAL_THEME} run lint"
continue-on-error: ${{ vars.VORTEX_CI_NODEJS_LINT_IGNORE_FAILURE == '1' }}

- name: Process code quality reports
if: always()
run: |
mkdir -p ".logs"
if docker compose ps --services --filter "status=running" | grep -q cli && docker compose exec -T cli test -d /app/.logs; then
docker compose --progress quiet cp cli:/app/.logs/. ".logs/"
fi
# Reports name files by their path inside the container, which does
# not exist outside it.
if [ -d ".logs/lint" ]; then
find .logs/lint -name '*.xml' -exec sed -i 's| name="/app/| name="|g' {} +
fi

- name: Upload code quality reports
uses: actions/upload-artifact@__HASH__ # __VERSION__
if: always()
with:
name: lint-artifacts
path: .logs
include-hidden-files: true
if-no-files-found: warn

database:
runs-on: ubuntu-latest
if: ${{ !inputs.deploy_target && (github.event_name == 'push' || !startsWith(github.head_ref, 'project/')) }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,21 +147,33 @@ jobs:
name: Validate Composer configuration is normalized
command: docker compose exec -T cli composer normalize --dry-run || [ "${VORTEX_CI_COMPOSER_NORMALIZE_IGNORE_FAILURE:-0}" -eq 1 ]

- run:
name: Prepare code quality report directory
command: docker compose exec -T cli mkdir -p .logs/lint

- run:
name: Lint code with PHPCS
command: docker compose exec -T cli vendor/bin/phpcs || [ "${VORTEX_CI_PHPCS_IGNORE_FAILURE:-0}" -eq 1 ]
command: docker compose exec -T cli vendor/bin/phpcs --report-full --report-checkstyle=.logs/lint/phpcs.xml || [ "${VORTEX_CI_PHPCS_IGNORE_FAILURE:-0}" -eq 1 ]

- run:
name: Lint code with PHPStan
command: docker compose exec -T cli vendor/bin/phpstan || [ "${VORTEX_CI_PHPSTAN_IGNORE_FAILURE:-0}" -eq 1 ]
# PHPStan emits one format per run, so the console run is repeated to
# carry the step's exit code.
command: |
docker compose exec -T cli sh -c 'vendor/bin/phpstan --no-progress --error-format=checkstyle > .logs/lint/phpstan.xml' || true
docker compose exec -T cli vendor/bin/phpstan || [ "${VORTEX_CI_PHPSTAN_IGNORE_FAILURE:-0}" -eq 1 ]

- run:
name: Lint code with Rector
command: docker compose exec -T cli vendor/bin/rector --dry-run || [ "${VORTEX_CI_RECTOR_IGNORE_FAILURE:-0}" -eq 1 ]

- run:
name: Lint code with Twig CS Fixer
command: docker compose exec -T cli vendor/bin/twig-cs-fixer || [ "${VORTEX_CI_TWIG_CS_FIXER_IGNORE_FAILURE:-0}" -eq 1 ]
# Twig CS Fixer emits one format per run, so the console run is
# repeated to carry the step's exit code.
command: |
docker compose exec -T cli sh -c 'vendor/bin/twig-cs-fixer --report=checkstyle > .logs/lint/twig-cs-fixer.xml' || true
docker compose exec -T cli vendor/bin/twig-cs-fixer || [ "${VORTEX_CI_TWIG_CS_FIXER_IGNORE_FAILURE:-0}" -eq 1 ]

- run:
name: Lint code with Gherkin Lint
Expand All @@ -177,6 +189,23 @@ jobs:
[ "${VORTEX_FRONTEND_BUILD_SKIP:-0}" -eq 1 ] && exit 0
docker compose exec -T cli bash -c "npm --prefix=\${WEBROOT}/themes/custom/\${DRUPAL_THEME} run lint" || [ "${VORTEX_CI_NODEJS_LINT_IGNORE_FAILURE:-0}" -eq 1 ]

- run:
name: Process code quality reports
command: |
mkdir -p "${VORTEX_CI_ARTIFACTS}"
if docker compose ps --services --filter "status=running" | grep -q cli && docker compose exec -T cli test -d /app/.logs; then
docker compose --progress quiet cp cli:/app/.logs/. "${VORTEX_CI_ARTIFACTS}/"
fi
# Reports name files by their path inside the container, which
# does not exist outside it.
if [ -d "${VORTEX_CI_ARTIFACTS}/lint" ]; then
find "${VORTEX_CI_ARTIFACTS}/lint" -name '*.xml' -exec sed -i 's| name="/app/| name="|g' {} +
fi
when: always

- store_artifacts:
path: *artifacts

# Audit job runs in its own workflow, independently of the commit workflow.
audit:
<<: *runner_config
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@@ -490,6 +490,17 @@
@@ -526,6 +526,17 @@
</details>
hide_and_recreate: true

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,21 +147,33 @@ jobs:
name: Validate Composer configuration is normalized
command: docker compose exec -T cli composer normalize --dry-run || [ "${VORTEX_CI_COMPOSER_NORMALIZE_IGNORE_FAILURE:-0}" -eq 1 ]

- run:
name: Prepare code quality report directory
command: docker compose exec -T cli mkdir -p .logs/lint

- run:
name: Lint code with PHPCS
command: docker compose exec -T cli vendor/bin/phpcs || [ "${VORTEX_CI_PHPCS_IGNORE_FAILURE:-0}" -eq 1 ]
command: docker compose exec -T cli vendor/bin/phpcs --report-full --report-checkstyle=.logs/lint/phpcs.xml || [ "${VORTEX_CI_PHPCS_IGNORE_FAILURE:-0}" -eq 1 ]

- run:
name: Lint code with PHPStan
command: docker compose exec -T cli vendor/bin/phpstan || [ "${VORTEX_CI_PHPSTAN_IGNORE_FAILURE:-0}" -eq 1 ]
# PHPStan emits one format per run, so the console run is repeated to
# carry the step's exit code.
command: |
docker compose exec -T cli sh -c 'vendor/bin/phpstan --no-progress --error-format=checkstyle > .logs/lint/phpstan.xml' || true
docker compose exec -T cli vendor/bin/phpstan || [ "${VORTEX_CI_PHPSTAN_IGNORE_FAILURE:-0}" -eq 1 ]

- run:
name: Lint code with Rector
command: docker compose exec -T cli vendor/bin/rector --dry-run || [ "${VORTEX_CI_RECTOR_IGNORE_FAILURE:-0}" -eq 1 ]

- run:
name: Lint code with Twig CS Fixer
command: docker compose exec -T cli vendor/bin/twig-cs-fixer || [ "${VORTEX_CI_TWIG_CS_FIXER_IGNORE_FAILURE:-0}" -eq 1 ]
# Twig CS Fixer emits one format per run, so the console run is
# repeated to carry the step's exit code.
command: |
docker compose exec -T cli sh -c 'vendor/bin/twig-cs-fixer --report=checkstyle > .logs/lint/twig-cs-fixer.xml' || true
docker compose exec -T cli vendor/bin/twig-cs-fixer || [ "${VORTEX_CI_TWIG_CS_FIXER_IGNORE_FAILURE:-0}" -eq 1 ]

- run:
name: Lint code with Gherkin Lint
Expand All @@ -177,6 +189,23 @@ jobs:
[ "${VORTEX_FRONTEND_BUILD_SKIP:-0}" -eq 1 ] && exit 0
docker compose exec -T cli bash -c "npm --prefix=\${WEBROOT}/themes/custom/\${DRUPAL_THEME} run lint" || [ "${VORTEX_CI_NODEJS_LINT_IGNORE_FAILURE:-0}" -eq 1 ]

- run:
name: Process code quality reports
command: |
mkdir -p "${VORTEX_CI_ARTIFACTS}"
if docker compose ps --services --filter "status=running" | grep -q cli && docker compose exec -T cli test -d /app/.logs; then
docker compose --progress quiet cp cli:/app/.logs/. "${VORTEX_CI_ARTIFACTS}/"
fi
# Reports name files by their path inside the container, which
# does not exist outside it.
if [ -d "${VORTEX_CI_ARTIFACTS}/lint" ]; then
find "${VORTEX_CI_ARTIFACTS}/lint" -name '*.xml' -exec sed -i 's| name="/app/| name="|g' {} +
fi
when: always

- store_artifacts:
path: *artifacts

# Audit job runs in its own workflow, independently of the commit workflow.
audit:
<<: *runner_config
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@@ -264,6 +264,9 @@
@@ -300,6 +300,9 @@
VORTEX_FETCH_DB_SEMAPHORE=/tmp/fetch-db-fresh ./vendor/bin/vortex-fetch-db
echo "db_hash=${{ hashFiles('.data') }}" >> "$GITHUB_ENV"
timeout-minutes: 30
Expand Down
Loading
Loading