diff --git a/.github/workflows/build-test-deploy.yml b/.github/workflows/build-test-deploy.yml index a41378b..51c3eed 100644 --- a/.github/workflows/build-test-deploy.yml +++ b/.github/workflows/build-test-deploy.yml @@ -2,6 +2,9 @@ # # This configuration file uses a custom "container" executor to run the # Docker stack to speed up the build process. +#; +#; Comments starting with '#;<' and '#;>' are internal Vortex comments +#; and will be removed during installation or update of Vortex. name: Database, Build, Test and Deploy on: @@ -37,13 +40,25 @@ on: workflow_dispatch: inputs: + deploy_target: + type: string + description: 'Deploy target: "" or "PR-"
next line' + required: false + default: '' + override_db: + type: boolean + description: 'Override existing database' + required: false + default: false enable_terminal: type: boolean - description: 'Enable terminal session.' + description: 'Enable terminal session' required: false default: false + #;< !PROVISION_TYPE_PROFILE schedule: - cron: '0 18 * * *' + #;> !PROVISION_TYPE_PROFILE defaults: run: @@ -59,11 +74,13 @@ jobs: lint: runs-on: ubuntu-latest - if: ${{ github.event_name != 'schedule' && (github.event_name == 'push' || !startsWith(github.head_ref, 'project/')) }} + #;< !PROVISION_TYPE_PROFILE + if: ${{ !inputs.deploy_target && github.event_name != 'schedule' && (github.event_name == 'push' || !startsWith(github.head_ref, 'project/')) }} + #;> !PROVISION_TYPE_PROFILE container: # https://hub.docker.com/r/drevops/ci-runner - image: drevops/ci-runner:26.2.0@sha256:fe1561c2984a1023e84eebe6461056b0b55afedbb2512e6c2c7f19aca6beb398 + image: drevops/ci-runner:26.3.0@sha256:788b02ff938be5e3c1d915d786b4be3b6453ac6091eaaa50d1414552d5131e97 env: PACKAGE_TOKEN: ${{ secrets.PACKAGE_TOKEN }} VORTEX_CONTAINER_REGISTRY_USER: ${{ secrets.VORTEX_CONTAINER_REGISTRY_USER }} @@ -114,7 +131,9 @@ jobs: docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c " \ if [ -n \"${PACKAGE_TOKEN:-}\" ]; then export COMPOSER_AUTH='{\"github-oauth\": {\"github.com\": \"${PACKAGE_TOKEN-}\"}}'; fi && \ COMPOSER_MEMORY_LIMIT=-1 composer --ansi install --prefer-dist" + #;< TOOL_ESLINT_STYLELINT docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli bash -c "yarn install --frozen-lockfile" + #;> TOOL_ESLINT_STYLELINT - name: Audit Composer packages run: docker compose exec -T cli composer audit @@ -124,42 +143,61 @@ jobs: run: docker compose exec -T cli composer normalize --dry-run continue-on-error: ${{ vars.VORTEX_CI_COMPOSER_NORMALIZE_IGNORE_FAILURE == '1' }} + #;< TOOL_PHPCS - name: Lint code with PHPCS run: docker compose exec -T cli vendor/bin/phpcs 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 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 continue-on-error: ${{ vars.VORTEX_CI_RECTOR_IGNORE_FAILURE == '1' }} + #;> TOOL_RECTOR + + #;< TOOL_PHPMD + - name: Lint code with PHPMD + run: docker compose exec -T cli vendor/bin/phpmd . text phpmd.xml + continue-on-error: ${{ vars.VORTEX_CI_PHPMD_IGNORE_FAILURE == '1' }} + #;> TOOL_PHPMD - name: Lint code with Twig CS Fixer run: docker compose exec -T cli vendor/bin/twig-cs-fixer continue-on-error: ${{ vars.VORTEX_CI_TWIG_CS_FIXER_IGNORE_FAILURE == '1' }} + #;< TOOL_BEHAT - name: Lint code with Gherkin Lint run: docker compose exec -T cli vendor/bin/gherkinlint lint tests/behat/features continue-on-error: ${{ vars.VORTEX_CI_GHERKIN_LINT_IGNORE_FAILURE == '1' }} + #;> TOOL_BEHAT + #;< TOOL_ESLINT_STYLELINT - name: Lint module code with NodeJS linters run: docker compose exec -T cli bash -c "yarn run lint" continue-on-error: ${{ vars.VORTEX_CI_NODEJS_LINT_IGNORE_FAILURE == '1' }} + #;> TOOL_ESLINT_STYLELINT + #;< DRUPAL_THEME - name: Lint theme code with NodeJS linters if: ${{ vars.VORTEX_FRONTEND_BUILD_SKIP != '1' }} run: docker compose exec -T cli bash -c "yarn --cwd=\${WEBROOT}/themes/custom/\${DRUPAL_THEME} run lint" continue-on-error: ${{ vars.VORTEX_CI_NODEJS_LINT_IGNORE_FAILURE == '1' }} + #;> DRUPAL_THEME + #;< !PROVISION_TYPE_PROFILE database: runs-on: ubuntu-latest - if: ${{ github.event_name == 'push' || !startsWith(github.head_ref, 'project/') }} + if: ${{ !inputs.deploy_target && (github.event_name == 'push' || !startsWith(github.head_ref, 'project/')) }} container: # https://hub.docker.com/r/drevops/ci-runner - image: drevops/ci-runner:26.2.0@sha256:fe1561c2984a1023e84eebe6461056b0b55afedbb2512e6c2c7f19aca6beb398 + image: drevops/ci-runner:26.3.0@sha256:788b02ff938be5e3c1d915d786b4be3b6453ac6091eaaa50d1414552d5131e97 env: PACKAGE_TOKEN: ${{ secrets.PACKAGE_TOKEN }} VORTEX_CONTAINER_REGISTRY_USER: ${{ secrets.VORTEX_CONTAINER_REGISTRY_USER }} @@ -235,6 +273,16 @@ jobs: VORTEX_DOWNLOAD_DB_SEMAPHORE=/tmp/download-db-success ./scripts/vortex/download-db.sh echo "db_hash=${{ hashFiles('.data') }}" >> "$GITHUB_ENV" timeout-minutes: 30 + #;< DB_DOWNLOAD_SOURCE_ACQUIA + env: + VORTEX_ACQUIA_KEY: ${{ secrets.VORTEX_ACQUIA_KEY }} + VORTEX_ACQUIA_SECRET: ${{ secrets.VORTEX_ACQUIA_SECRET }} + #;> DB_DOWNLOAD_SOURCE_ACQUIA + + #;< MIGRATION + - name: Download migration DB + run: VORTEX_DB_INDEX=2 ./scripts/vortex/download-db.sh + #;> MIGRATION - name: Export DB run: | @@ -256,11 +304,14 @@ jobs: with: path: .data key: v26.2.0-db11-${{ hashFiles('db_cache_branch') }}-${{ hashFiles('db_cache_fallback_yes') }}-${{ hashFiles('db_cache_timestamp') }} + #;> !PROVISION_TYPE_PROFILE build: runs-on: ubuntu-latest + #;< !PROVISION_TYPE_PROFILE needs: database - if: ${{ github.event_name != 'schedule' && (github.event_name == 'push' || !startsWith(github.head_ref, 'project/')) }} + if: ${{ !inputs.deploy_target && github.event_name != 'schedule' && (github.event_name == 'push' || !startsWith(github.head_ref, 'project/')) }} + #;> !PROVISION_TYPE_PROFILE strategy: # A matrix to run multiple jobs in parallel. @@ -270,7 +321,7 @@ jobs: container: # https://hub.docker.com/r/drevops/ci-runner - image: drevops/ci-runner:26.2.0@sha256:fe1561c2984a1023e84eebe6461056b0b55afedbb2512e6c2c7f19aca6beb398 + image: drevops/ci-runner:26.3.0@sha256:788b02ff938be5e3c1d915d786b4be3b6453ac6091eaaa50d1414552d5131e97 env: PACKAGE_TOKEN: ${{ secrets.PACKAGE_TOKEN }} VORTEX_CONTAINER_REGISTRY_USER: ${{ secrets.VORTEX_CONTAINER_REGISTRY_USER }} @@ -281,6 +332,7 @@ jobs: VORTEX_SSH_DISABLE_STRICT_HOST_KEY_CHECKING: "1" VORTEX_SSH_REMOVE_ALL_KEYS: "1" VORTEX_DEBUG: ${{ vars.VORTEX_DEBUG }} + #;< !PROVISION_TYPE_PROFILE # How often to refresh the cache of the DB dump. Refer to `date` command. VORTEX_CI_DB_CACHE_TIMESTAMP: +%Y%m%d # Use previous database caches on this branch as a fallback if the above cache @@ -289,6 +341,7 @@ jobs: VORTEX_CI_DB_CACHE_FALLBACK: "yes" # Which branch to use as a source of DB caches. VORTEX_CI_DB_CACHE_BRANCH: "develop" + #;> !PROVISION_TYPE_PROFILE steps: - name: Preserve $HOME set in the container @@ -310,6 +363,7 @@ jobs: run: composer validate --strict continue-on-error: ${{ vars.VORTEX_CI_COMPOSER_VALIDATE_IGNORE_FAILURE == '1' }} + #;< !PROVISION_TYPE_PROFILE - name: Create cache keys files for database caching run: | echo "${VORTEX_CI_DB_CACHE_BRANCH}" | tee db_cache_branch @@ -332,6 +386,7 @@ jobs: key: v26.2.0-db11-${{ hashFiles('db_cache_branch') }}-${{ hashFiles('db_cache_fallback_yes') }}-${{ hashFiles('db_cache_timestamp') }} restore-keys: | v26.2.0-db11-${{ hashFiles('db_cache_branch') }}-${{ hashFiles('db_cache_fallback_yes') }}- + #;> !PROVISION_TYPE_PROFILE - name: Login to container registry run: ./scripts/vortex/login-container-registry.sh @@ -359,9 +414,16 @@ jobs: docker compose exec cli mkdir -p .data docker compose cp -L .data/db.sql cli:/app/.data/db.sql fi + #;< MIGRATION + if [ -f ".data/${VORTEX_DOWNLOAD_DB2_FILE:-db2.sql}" ]; then + docker compose exec -T cli mkdir -p .data + docker compose cp -L ".data/${VORTEX_DOWNLOAD_DB2_FILE:-db2.sql}" cli:"/app/.data/${VORTEX_DOWNLOAD_DB2_FILE:-db2.sql}" + fi + #;> MIGRATION docker compose exec $(env | cut -f1 -d= | sed 's/^/-e /') -T cli ./scripts/vortex/provision.sh timeout-minutes: 30 + #;< TOOL_PHPUNIT - name: Test with PHPUnit if: ${{ matrix.instance == 0 || strategy.job-total == 1 }} run: docker compose exec -T cli vendor/bin/phpunit @@ -381,8 +443,15 @@ jobs: RATE=$(grep -om1 'line-rate="[0-9.]*"' .logs/coverage/phpunit/cobertura.xml | tr -cd '0-9.') PERCENT=$(awk "BEGIN {printf \"%.2f\", $RATE*100}") echo "Coverage: $PERCENT% (threshold: $VORTEX_CI_CODE_COVERAGE_THRESHOLD%)" | tee -a "$GITHUB_STEP_SUMMARY" - echo "COVERAGE_PERCENT=${PERCENT}" >> "$GITHUB_ENV" - { echo "COVERAGE_CONTENT<> "$GITHUB_ENV" + { + echo "COVERAGE_PERCENT=${PERCENT}" + echo "COVERAGE_SUMMARY<> "$GITHUB_ENV" env: VORTEX_CI_CODE_COVERAGE_THRESHOLD: ${{ vars.VORTEX_CI_CODE_COVERAGE_THRESHOLD || '90' }} @@ -392,10 +461,17 @@ jobs: with: header: coverage-gha message: | - **Code coverage (GitHub Actions)** + **Code coverage** (threshold: ${{ vars.VORTEX_CI_CODE_COVERAGE_THRESHOLD || '90' }}%) ``` - ${{ env.COVERAGE_CONTENT }} + ${{ env.COVERAGE_SUMMARY }} ``` +
+ Per-class coverage + + ``` + ${{ env.COVERAGE_DETAILS }} + ``` +
hide_and_recreate: true - name: Upload coverage report to Codecov @@ -417,7 +493,9 @@ jobs: fi env: VORTEX_CI_CODE_COVERAGE_THRESHOLD: ${{ vars.VORTEX_CI_CODE_COVERAGE_THRESHOLD || '90' }} + #;> TOOL_PHPUNIT + #;< TOOL_BEHAT - name: Test with Behat run: | # shellcheck disable=SC2170 @@ -429,6 +507,7 @@ jobs: VORTEX_CI_BEHAT_PROFILE: ${{ vars.VORTEX_CI_BEHAT_PROFILE }} continue-on-error: ${{ vars.VORTEX_CI_BEHAT_IGNORE_FAILURE == '1' }} timeout-minutes: 30 + #;> TOOL_BEHAT - name: Process test logs and artifacts if: always() @@ -464,14 +543,17 @@ jobs: with: detached: true + #;< DEPLOYMENT deploy: runs-on: ubuntu-latest needs: [build, lint] - if: ${{ github.event_name != 'schedule' && !startsWith(github.head_ref || github.ref_name, 'deps/') && (github.event_name == 'push' || !startsWith(github.head_ref, 'project/')) }} + #;< !PROVISION_TYPE_PROFILE + if: ${{ !cancelled() && (inputs.deploy_target || (github.event_name != 'schedule' && !startsWith(github.head_ref || github.ref_name, 'deps/') && (github.event_name == 'push' || !startsWith(github.head_ref, 'project/')))) }} + #;> !PROVISION_TYPE_PROFILE container: # https://hub.docker.com/r/drevops/ci-runner - image: drevops/ci-runner:26.2.0@sha256:fe1561c2984a1023e84eebe6461056b0b55afedbb2512e6c2c7f19aca6beb398 + image: drevops/ci-runner:26.3.0@sha256:788b02ff938be5e3c1d915d786b4be3b6453ac6091eaaa50d1414552d5131e97 env: TZ: ${{ vars.TZ || 'UTC' }} TERM: xterm-256color @@ -482,6 +564,19 @@ jobs: - name: Preserve $HOME set in the container run: echo HOME=/root >> "$GITHUB_ENV" # https://github.com/actions/runner/issues/863 + - name: Resolve deploy target + if: ${{ inputs.deploy_target }} + env: + DEPLOY_TARGET: ${{ inputs.deploy_target }} + GH_TOKEN: ${{ github.token }} + run: | + echo "DEPLOY_BRANCH=${DEPLOY_TARGET}" >> "$GITHUB_ENV" + if echo "${DEPLOY_TARGET}" | grep -iq '^pr-'; then + echo "DEPLOY_PR_NUMBER=${DEPLOY_TARGET#*-}" >> "$GITHUB_ENV" + echo "DEPLOY_PR_HEAD_SHA=$(gh pr view "${DEPLOY_TARGET#*-}" --repo "${{ github.repository }}" --json headRefOid --jq '.headRefOid')" >> "$GITHUB_ENV" + echo "DEPLOY_BRANCH=$(gh pr view "${DEPLOY_TARGET#*-}" --repo "${{ github.repository }}" --json headRefName --jq '.headRefName')" >> "$GITHUB_ENV" + fi + - name: Checkout code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: @@ -490,7 +585,7 @@ jobs: # Do not persist credentials after checkout # to allow using the custom credentials to push to a remote repo. persist-credentials: false - ref: ${{ github.head_ref || github.ref_name }} + ref: ${{ env.DEPLOY_BRANCH || github.head_ref || github.ref_name }} - name: Fix Git ownership permissions run: git config --global --add safe.directory "$GITHUB_WORKSPACE" @@ -498,15 +593,16 @@ jobs: - name: Load environment variables from .env run: t=$(mktemp) && export -p >"${t}" && set -a && . ./.env && set +a && . "${t}" && env >> "$GITHUB_ENV" + # Artifact deployments do not work for manual deploys as the build job is skipped. - name: Download exported codebase as an artifact uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 - if: ${{ contains(env.VORTEX_DEPLOY_TYPES, 'artifact') }} + if: ${{ !inputs.deploy_target && contains(env.VORTEX_DEPLOY_TYPES, 'artifact') }} with: name: code-artifact path: "/tmp/artifacts" - name: Unpack downloaded exported codebase - if: ${{ contains(env.VORTEX_DEPLOY_TYPES, 'artifact') }} + if: ${{ !inputs.deploy_target && contains(env.VORTEX_DEPLOY_TYPES, 'artifact') }} run: | mkdir -p /tmp/workspace tar -xpf /tmp/artifacts/code.tar -C /tmp/workspace @@ -524,10 +620,9 @@ jobs: run: ./scripts/vortex/deploy.sh env: VORTEX_DEPLOY_MODE: ${{ startsWith(github.ref, 'refs/tags/') && 'tag' || 'branch' }} - # Get branch for PR from 'head_ref' or for branch from 'ref_name'. - VORTEX_DEPLOY_BRANCH: ${{ github.head_ref || github.ref_name }} - VORTEX_DEPLOY_PR: ${{ github.event.number }} - VORTEX_DEPLOY_PR_HEAD: ${{ github.event.pull_request.head.sha }} + VORTEX_DEPLOY_BRANCH: ${{ env.DEPLOY_BRANCH || github.head_ref || github.ref_name }} + VORTEX_DEPLOY_PR: ${{ env.DEPLOY_PR_NUMBER || github.event.number }} + VORTEX_DEPLOY_PR_HEAD: ${{ env.DEPLOY_PR_HEAD_SHA || github.event.pull_request.head.sha }} VORTEX_DEPLOY_ARTIFACT_SRC: /tmp/workspace/code VORTEX_DEPLOY_ARTIFACT_ROOT: ${{ github.workspace }} VORTEX_DEPLOY_ARTIFACT_GIT_REMOTE: ${{ vars.VORTEX_DEPLOY_ARTIFACT_GIT_REMOTE }} @@ -538,4 +633,6 @@ jobs: VORTEX_DEPLOY_ALLOW_SKIP: ${{ vars.VORTEX_DEPLOY_ALLOW_SKIP }} VORTEX_DEPLOY_SKIP_PRS: ${{ vars.VORTEX_DEPLOY_SKIP_PRS }} VORTEX_DEPLOY_SKIP_BRANCHES: ${{ vars.VORTEX_DEPLOY_SKIP_BRANCHES }} + VORTEX_DEPLOY_ACTION: ${{ inputs.override_db && 'deploy_override_db' || '' }} timeout-minutes: 30 + #;> DEPLOYMENT