diff --git a/.github/workflows/infra.yml b/.github/workflows/infra.yml index 18aea892b..d3766725d 100644 --- a/.github/workflows/infra.yml +++ b/.github/workflows/infra.yml @@ -1,5 +1,18 @@ name: infra on: + workflow_call: + inputs: + app_name: + description: 'The name of the application to deploy' + required: true + type: string + secrets: + AWS_ACCESS_KEY_ID: + required: true + AWS_SECRET_ACCESS_KEY: + required: true + AWS_REGION: + required: true push: pull_request: types: [opened, reopened] diff --git a/.github/workflows/pricing-coverage.yml b/.github/workflows/pricing-coverage.yml new file mode 100644 index 000000000..ac348fc13 --- /dev/null +++ b/.github/workflows/pricing-coverage.yml @@ -0,0 +1,43 @@ +name: pricing-coverage +on: + workflow_dispatch: + repository_dispatch: + types: + - script + push: + branches: + - master + paths: + - "ecommerce/pricing/Gemfile.lock" + - ".github/workflows/pricing-coverage.yml" + pull_request: + types: [opened, synchronize, reopened] + paths: + - "ecommerce/pricing/Gemfile.lock" + - ".github/workflows/pricing-coverage.yml" + schedule: + - cron: '0 17 * * *' +jobs: + test: + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: ruby-3.3.7 + bundler-cache: true + working-directory: ecommerce/pricing + - name: Run tests + run: make -C ecommerce/pricing test + mutate: + needs: test + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: ruby-3.3.7 + bundler-cache: true + working-directory: ecommerce/pricing + - name: Run full mutation testing + run: make -C ecommerce/pricing mutate diff --git a/.github/workflows/pricing-mutate.yml b/.github/workflows/pricing-mutate.yml new file mode 100644 index 000000000..cf8873021 --- /dev/null +++ b/.github/workflows/pricing-mutate.yml @@ -0,0 +1,37 @@ +name: pricing-mutate +on: + pull_request: + types: [opened, synchronize, reopened] + paths: + - "ecommerce/pricing/**" + - ".github/workflows/pricing-mutate.yml" +jobs: + test: + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: ruby-3.3.7 + bundler-cache: true + working-directory: ecommerce/pricing + - name: Run tests + run: make -C ecommerce/pricing test + mutate: + needs: test + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: ruby-3.3.7 + bundler-cache: true + working-directory: ecommerce/pricing + - name: Run incremental mutation testing + run: make -C ecommerce/pricing mutate-changes + env: + GIT_BASE_SHA: ${{ github.event.pull_request.base.sha }} diff --git a/.github/workflows/pricing.yml b/.github/workflows/pricing.yml index c3b076cc2..e562dd425 100644 --- a/.github/workflows/pricing.yml +++ b/.github/workflows/pricing.yml @@ -1,283 +1,19 @@ name: pricing on: - push: pull_request: - types: [opened, reopened] + types: [opened, synchronize, reopened] + paths: + - "ecommerce/pricing/**" + - ".github/workflows/pricing.yml" + workflow_dispatch: jobs: - determine_run_parameters: - runs-on: ubuntu-24.04 - outputs: - mutant_mode: ${{ steps.set_params.outputs.mutant_mode }} - mutant_since_target: ${{ steps.set_params.outputs.mutant_since_target }} - num_groups: ${{ steps.set_params.outputs.num_groups }} - steps: - - name: Determine Mutation Run Parameters - id: set_params - shell: bash - env: - EVENT_NAME: ${{ github.event_name }} - REF_NAME: ${{ github.ref_name }} - PR_BASE_REF: ${{ github.event.pull_request.base.ref }} - PR_TITLE: ${{ github.event.pull_request.title }} - PR_BODY: ${{ github.event.pull_request.body }} - COMMIT_MESSAGES_JOINED_WITH_SPACES_ACTIONS: ${{ join(github.event.commits.*.message, ' ') }} - COMMIT_MESSAGES_JOINED_WITH_SLASHES_ACTIONS: ${{ join(github.event.commits.*.message, ' // ') }} - - run: | - echo "--- Debug: Determining mutation run parameters for pricing ---" - echo "Event name: $EVENT_NAME" - echo "Ref name: $REF_NAME" - echo "Base ref (for PR): $PR_BASE_REF" - echo "PR title: $PR_TITLE" - - RAW_COMMIT_MESSAGES_FOR_JOIN_WITH_SLASHES="$COMMIT_MESSAGES_JOINED_WITH_SLASHES_ACTIONS" - RAW_COMMIT_MESSAGES_FOR_JOIN_WITH_SPACES="$COMMIT_MESSAGES_FOR_JOIN_WITH_SPACES_ACTIONS" - - CLEANED_COMMIT_MESSAGES_FOR_LOG="${RAW_COMMIT_MESSAGES_FOR_JOIN_WITH_SLASHES//\'/}" - COMMIT_MESSAGES_LOG=$(echo "${CLEANED_COMMIT_MESSAGES_FOR_LOG}" | head -c 500) - echo "Commit messages in push (cleaned, first 500 chars): ${COMMIT_MESSAGES_LOG}..." - - CLEANED_COMMIT_MESSAGES_FOR_CONTAINS="${RAW_COMMIT_MESSAGES_FOR_JOIN_WITH_SPACES//\'/}" - - if [[ "${CLEANED_COMMIT_MESSAGES_FOR_CONTAINS}" == *"[mutate-full]"* ]]; then - CONTAINS_MUTATE_FULL_IN_PUSH="true" - else - CONTAINS_MUTATE_FULL_IN_PUSH="false" - fi - echo "Contains '[mutate-full]' in push commit messages (from cleaned messages): $CONTAINS_MUTATE_FULL_IN_PUSH" - - CLEANED_PR_TITLE="${PR_TITLE//\'/}" - if [[ "${CLEANED_PR_TITLE}" == *"[mutate-full]"* ]]; then - CONTAINS_MUTATE_FULL_IN_PR_TITLE="true" - else - CONTAINS_MUTATE_FULL_IN_PR_TITLE="false" - fi - echo "Contains '[mutate-full]' in PR title (from cleaned title): $CONTAINS_MUTATE_FULL_IN_PR_TITLE" - - CLEANED_PR_BODY="${PR_BODY//\'/}" - if [[ "${CLEANED_PR_BODY}" == *"[mutate-full]"* ]]; then - CONTAINS_MUTATE_FULL_IN_PR_BODY="true" - else - CONTAINS_MUTATE_FULL_IN_PR_BODY="false" - fi - echo "Contains '[mutate-full]' in PR body (from cleaned body): $CONTAINS_MUTATE_FULL_IN_PR_BODY" - - echo "---------------------------------------------" - - FINAL_MUTANT_MODE="full" - FINAL_NUM_GROUPS=16 - FINAL_SINCE_TARGET="" - - IS_MUTATE_FULL_TRIGGERED="false" - if [[ "$EVENT_NAME" == "pull_request" && \ - ( "$CONTAINS_MUTATE_FULL_IN_PR_TITLE" == "true" || "$CONTAINS_MUTATE_FULL_IN_PR_BODY" == "true" ) ]]; then - echo "Logic path: [mutate-full] in PR title/body." - IS_MUTATE_FULL_TRIGGERED="true" - elif [[ "$EVENT_NAME" == "push" && "$CONTAINS_MUTATE_FULL_IN_PUSH" == "true" ]]; then - echo "Logic path: [mutate-full] in push commit message(s)." - IS_MUTATE_FULL_TRIGGERED="true" - fi - - if [[ "$IS_MUTATE_FULL_TRIGGERED" == "true" ]]; then - echo "Action: Mode set to 'full' (NUM_GROUPS=16) due to [mutate-full] trigger." - FINAL_MUTANT_MODE="full" - FINAL_NUM_GROUPS=16 - else - if [[ "$EVENT_NAME" == "pull_request" ]]; then - echo "Logic path: Pull request event (no [mutate-full] trigger)." - echo "Action: Mode set to 'incremental' (NUM_GROUPS=2) for PR." - FINAL_MUTANT_MODE="incremental" - FINAL_NUM_GROUPS=2 - FINAL_SINCE_TARGET="origin/$PR_BASE_REF" - echo "Incremental target: $FINAL_SINCE_TARGET" - elif [[ "$EVENT_NAME" == "push" ]]; then - if [[ "$REF_NAME" == "master" || "$REF_NAME" == "main" ]]; then - echo "Logic path: Push event to main branch (no [mutate-full] trigger)." - echo "Action: Mode set to 'full' (NUM_GROUPS=16) for main branch." - FINAL_MUTANT_MODE="full" - FINAL_NUM_GROUPS=16 - else - echo "Logic path: Push event to non-main branch ('$REF_NAME') (no [mutate-full] trigger)." - echo "Action: Mode set to 'incremental' (NUM_GROUPS=2) for branch push." - FINAL_MUTANT_MODE="incremental" - FINAL_NUM_GROUPS=2 - FINAL_SINCE_TARGET="origin/master" - echo "Incremental target: $FINAL_SINCE_TARGET" - fi - fi - fi - - echo "Debug before GITHUB_OUTPUT: FINAL_MUTANT_MODE='${FINAL_MUTANT_MODE}'" - echo "Debug before GITHUB_OUTPUT: FINAL_SINCE_TARGET='${FINAL_SINCE_TARGET}'" - echo "Debug before GITHUB_OUTPUT: FINAL_NUM_GROUPS='${FINAL_NUM_GROUPS}'" - - echo "mutant_mode=${FINAL_MUTANT_MODE}" >> $GITHUB_OUTPUT - echo "mutant_since_target=${FINAL_SINCE_TARGET}" >> $GITHUB_OUTPUT - echo "num_groups=${FINAL_NUM_GROUPS}" >> $GITHUB_OUTPUT - - echo "--- Final Parameters for pricing ---" - echo "Mutant Mode: ${FINAL_MUTANT_MODE}" - echo "Mutant Since Target: ${FINAL_SINCE_TARGET}" - echo "Num Groups: ${FINAL_NUM_GROUPS}" - echo "------------------------" - test: runs-on: ubuntu-24.04 - strategy: - fail-fast: false - env: - WORKING_DIRECTORY: ecommerce/pricing - steps: - - uses: actions/checkout@v3 - - uses: ruby/setup-ruby@v1 - with: - ruby-version: ruby-3.3.7 - bundler-cache: true - working-directory: ${{ env.WORKING_DIRECTORY }} - - run: make test - working-directory: ${{ env.WORKING_DIRECTORY }} - - uses: 8398a7/action-slack@v3 - with: - status: custom - fields: workflow,job,commit,repo,ref,author,took - custom_payload: | - { - attachments: [{ - color: '${{ job.status }}' === 'success' ? 'good' : '${{ job.status }}' === 'failure' ? 'danger' : 'warning', - text: `${process.env.AS_WORKFLOW}/${{ github.job }} ${{ job.status }} in ${process.env.AS_TOOK}\n${process.env.AS_COMMIT} in ${process.env.AS_REF} for pricing`, - }] - } - env: - SLACK_WEBHOOK_URL: ${{ secrets.CI_WEBHOOK }} - if: always() - continue-on-error: true - - prepare_mutation_subjects_pricing: - runs-on: ubuntu-24.04 - needs: determine_run_parameters - outputs: - subject_groups: ${{ steps.split_subjects.outputs.subject_groups }} - env: - WORKING_DIRECTORY: ecommerce/pricing - steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - uses: ruby/setup-ruby@v1 - with: - ruby-version: ruby-3.3.7 - bundler-cache: true - working-directory: ${{ env.WORKING_DIRECTORY }} - - name: List and split subjects for pricing - id: split_subjects - working-directory: ${{ env.WORKING_DIRECTORY }} - env: - NUM_GROUPS_FROM_CI: ${{ needs.determine_run_parameters.outputs.num_groups }} - run: | - echo "--- Preparing subjects for pricing ---" - SUBJECT_LIST_OUTPUT=$(bundle exec mutant environment subject list) - - mapfile -t subjects_array < <( \ - echo "$SUBJECT_LIST_OUTPUT" | \ - awk 'NR == 1 {next} /Run options:/ {exit} {print}' | \ - sed 's/\x1b\[[0-9;]*m//g' | \ - sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | \ - awk 'NF' \ - ) - - if [ ${#subjects_array[@]} -eq 0 ]; then - echo "No subjects found for pricing after cleaning. Setting empty subject_groups." - echo "subject_groups=[]" >> $GITHUB_OUTPUT - exit 0 - fi - - total_subjects=${#subjects_array[@]} - NUM_GROUPS=${NUM_GROUPS_FROM_CI:-2} - echo "Total subjects found: $total_subjects" - echo "Number of parallel groups to create: $NUM_GROUPS" - groups_json_array_content="" - - for (( i=0; i> $GITHUB_OUTPUT - echo "-----------------------------------" - - mutate: - needs: [determine_run_parameters, prepare_mutation_subjects_pricing] - if: ${{ needs.prepare_mutation_subjects_pricing.outputs.subject_groups != '[]' && needs.prepare_mutation_subjects_pricing.outputs.subject_groups != '' }} - runs-on: ubuntu-24.04 - strategy: - fail-fast: false - matrix: - subject_group: ${{ fromJson(needs.prepare_mutation_subjects_pricing.outputs.subject_groups) }} - env: - WORKING_DIRECTORY: ecommerce/pricing - MUTANT_MODE: ${{ needs.determine_run_parameters.outputs.mutant_mode }} - MUTANT_SINCE_TARGET: ${{ needs.determine_run_parameters.outputs.mutant_since_target }} steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 + - uses: actions/checkout@v4 - uses: ruby/setup-ruby@v1 with: ruby-version: ruby-3.3.7 bundler-cache: true - working-directory: ${{ env.WORKING_DIRECTORY }} - - name: Run mutation tests (parallel group for pricing) - run: | - echo "Debug from CI step before calling make (using PASSED_ var names):" - echo " Value for PASSED_MODE='${{ env.ENV_CLI_MUTANT_MODE }}'" - echo " Value for PASSED_SINCE_TARGET='${{ env.ENV_CLI_MUTANT_SINCE_TARGET }}'" - echo " CI_MUTATE_SUBJECTS (from env): '${{ env.CI_MUTATE_SUBJECTS }}'" - - make mutate \ - PASSED_MODE="${{ env.ENV_CLI_MUTANT_MODE }}" \ - PASSED_SINCE_TARGET="${{ env.ENV_CLI_MUTANT_SINCE_TARGET }}" - working-directory: ${{ env.WORKING_DIRECTORY }} - env: - CI_MUTATE_SUBJECTS: ${{ matrix.subject_group }} - - notify_pricing_mutation_summary: - runs-on: ubuntu-24.04 - needs: [mutate, prepare_mutation_subjects_pricing] - if: always() && needs.prepare_mutation_subjects_pricing.outputs.subject_groups != '[]' && needs.prepare_mutation_subjects_pricing.outputs.subject_groups != '' - steps: - - name: Determine notification color - id: set_color - run: | - if [[ "${{ needs.mutate.result }}" == "success" ]]; then - echo "NOTIFICATION_COLOR=good" >> $GITHUB_ENV - elif [[ "${{ needs.mutate.result }}" == "failure" ]]; then - echo "NOTIFICATION_COLOR=danger" >> $GITHUB_ENV - else - echo "NOTIFICATION_COLOR=warning" >> $GITHUB_ENV - fi - - name: Send mutation summary notification - uses: 8398a7/action-slack@v3 - with: - status: custom - fields: workflow,commit,repo,ref,author - custom_payload: | - { - "attachments": [{ - "color": "${{ env.NOTIFICATION_COLOR }}", - "text": "<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|pricing> Mutation Test Summary:\nStatus: ${{ needs.mutate.result }}\nWorkflow: <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|${{ github.workflow }}>\nCommit: <${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }}|${{ github.sha }}> in ${{ github.ref }}" - }] - } - env: - SLACK_WEBHOOK_URL: ${{ secrets.CI_WEBHOOK }} \ No newline at end of file + working-directory: ecommerce/pricing + - run: make -C ecommerce/pricing test diff --git a/.github/workflows/rails_application-coverage.yml b/.github/workflows/rails_application-coverage.yml new file mode 100644 index 000000000..30bc45f0c --- /dev/null +++ b/.github/workflows/rails_application-coverage.yml @@ -0,0 +1,67 @@ +name: rails_application-coverage +on: + workflow_dispatch: + repository_dispatch: + types: + - script + push: + branches: + - master + paths: + - "rails_application/Gemfile.lock" + - ".github/workflows/rails_application-coverage.yml" + pull_request: + types: [opened, synchronize, reopened] + paths: + - "rails_application/Gemfile.lock" + - ".github/workflows/rails_application-coverage.yml" + schedule: + - cron: '0 17 * * *' +jobs: + test: + runs-on: ubuntu-24.04 + services: + postgres: + image: postgres:17-alpine + env: + POSTGRES_DB: cqrs-es-sample-with-res_test + POSTGRES_PASSWORD: secret + ports: + - 5432:5432 + options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 + steps: + - uses: actions/checkout@v4 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: ruby-3.3.7 + bundler-cache: true + working-directory: rails_application + - name: Run tests + run: make -C rails_application test + env: + DATABASE_URL: "postgres://postgres:secret@localhost:5432/cqrs-es-sample-with-res_test" + RAILS_ENV: test + mutate: + needs: test + runs-on: ubuntu-24.04 + services: + postgres: + image: postgres:17-alpine + env: + POSTGRES_DB: cqrs-es-sample-with-res_test + POSTGRES_PASSWORD: secret + ports: + - 5432:5432 + options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 + steps: + - uses: actions/checkout@v4 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: ruby-3.3.7 + bundler-cache: true + working-directory: rails_application + - name: Run full mutation testing + run: make -C rails_application mutate + env: + DATABASE_URL: "postgres://postgres:secret@localhost:5432/cqrs-es-sample-with-res_test" + RAILS_ENV: test diff --git a/.github/workflows/rails_application-mutate.yml b/.github/workflows/rails_application-mutate.yml new file mode 100644 index 000000000..1c34f7189 --- /dev/null +++ b/.github/workflows/rails_application-mutate.yml @@ -0,0 +1,60 @@ +name: rails_application-mutate +on: + pull_request: + types: [opened, synchronize, reopened] + paths: + - "rails_application/**" + - ".github/workflows/rails_application-mutate.yml" +jobs: + test: + runs-on: ubuntu-24.04 + services: + postgres: + image: postgres:17-alpine + env: + POSTGRES_DB: cqrs-es-sample-with-res_test + POSTGRES_PASSWORD: secret + ports: + - 5432:5432 + options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: ruby-3.3.7 + bundler-cache: true + working-directory: rails_application + - name: Run tests + run: make -C rails_application test + env: + DATABASE_URL: "postgres://postgres:secret@localhost:5432/cqrs-es-sample-with-res_test" + RAILS_ENV: test + mutate: + needs: test + runs-on: ubuntu-24.04 + services: + postgres: + image: postgres:17-alpine + env: + POSTGRES_DB: cqrs-es-sample-with-res_test + POSTGRES_PASSWORD: secret + ports: + - 5432:5432 + options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: ruby-3.3.7 + bundler-cache: true + working-directory: rails_application + - name: Run incremental mutation testing + run: make -C rails_application mutate-changes + env: + DATABASE_URL: "postgres://postgres:secret@localhost:5432/cqrs-es-sample-with-res_test" + RAILS_ENV: test + GIT_BASE_SHA: ${{ github.event.pull_request.base.sha }} diff --git a/.github/workflows/rails_application.yml b/.github/workflows/rails_application.yml index f56e20752..c7b122341 100644 --- a/.github/workflows/rails_application.yml +++ b/.github/workflows/rails_application.yml @@ -1,249 +1,16 @@ name: rails_application on: - push: pull_request: - types: [ opened, reopened ] + types: [opened, synchronize, reopened] + paths: + - "rails_application/**" + - ".github/workflows/rails_application.yml" + push: + branches: + - master jobs: - determine_run_parameters: - runs-on: ubuntu-24.04 - outputs: - mutant_mode: ${{ steps.set_params.outputs.mutant_mode }} - mutant_since_target: ${{ steps.set_params.outputs.mutant_since_target }} - num_groups: ${{ steps.set_params.outputs.num_groups }} - steps: - - name: Determine Mutation Run Parameters - id: set_params - shell: bash - env: - EVENT_NAME: ${{ github.event_name }} - REF_NAME: ${{ github.ref_name }} - PR_BASE_REF: ${{ github.event.pull_request.base.ref }} - PR_TITLE_RAW: ${{ github.event.pull_request.title }} - PR_BODY_RAW: ${{ github.event.pull_request.body }} - COMMIT_MESSAGES_JOINED_WITH_SPACES_RAW: ${{ join(github.event.commits.*.message, ' ') }} - COMMIT_MESSAGES_JOINED_WITH_SLASHES_RAW: ${{ join(github.event.commits.*.message, ' // ') }} - run: | - echo "--- Debug: Determining mutation run parameters ---" - echo "Event name: $EVENT_NAME" - echo "Ref name: $REF_NAME" - echo "Base ref (for PR): $PR_BASE_REF" - echo "PR title (raw): $PR_TITLE_RAW" - - CLEANED_COMMIT_MESSAGES_FOR_LOG_RAW="${COMMIT_MESSAGES_JOINED_WITH_SLASHES_RAW//\'/}" - COMMIT_MESSAGES_LOG=$(echo "${CLEANED_COMMIT_MESSAGES_FOR_LOG_RAW}" | head -c 500) - echo "Commit messages in push (cleaned, first 500 chars): ${COMMIT_MESSAGES_LOG}..." - - CLEANED_COMMIT_MESSAGES_FOR_CONTAINS="${COMMIT_MESSAGES_JOINED_WITH_SPACES_RAW//\'/}" - if [[ "${CLEANED_COMMIT_MESSAGES_FOR_CONTAINS}" == *"[mutate-full]"* ]]; then - CONTAINS_MUTATE_FULL_IN_PUSH="true" - else - CONTAINS_MUTATE_FULL_IN_PUSH="false" - fi - echo "Contains '[mutate-full]' in push commit messages (from cleaned messages): $CONTAINS_MUTATE_FULL_IN_PUSH" - - CLEANED_PR_TITLE="${PR_TITLE_RAW//\'/}" - if [[ "${CLEANED_PR_TITLE}" == *"[mutate-full]"* ]]; then - CONTAINS_MUTATE_FULL_IN_PR_TITLE="true" - else - CONTAINS_MUTATE_FULL_IN_PR_TITLE="false" - fi - echo "Contains '[mutate-full]' in PR title (from cleaned title): $CONTAINS_MUTATE_FULL_IN_PR_TITLE" - - CLEANED_PR_BODY="${PR_BODY_RAW//\'/}" - if [[ "${CLEANED_PR_BODY}" == *"[mutate-full]"* ]]; then - CONTAINS_MUTATE_FULL_IN_PR_BODY="true" - else - CONTAINS_MUTATE_FULL_IN_PR_BODY="false" - fi - echo "Contains '[mutate-full]' in PR body (from cleaned body): $CONTAINS_MUTATE_FULL_IN_PR_BODY" - echo "---------------------------------------------" - - FINAL_MUTANT_MODE="full" - FINAL_NUM_GROUPS=16 - FINAL_SINCE_TARGET="" - - IS_MUTATE_FULL_TRIGGERED="false" - if [[ "$EVENT_NAME" == "pull_request" && \ - ( "$CONTAINS_MUTATE_FULL_IN_PR_TITLE" == "true" || "$CONTAINS_MUTATE_FULL_IN_PR_BODY" == "true" ) ]]; then - echo "Logic path: [mutate-full] in PR title/body." - IS_MUTATE_FULL_TRIGGERED="true" - elif [[ "$EVENT_NAME" == "push" && "$CONTAINS_MUTATE_FULL_IN_PUSH" == "true" ]]; then - echo "Logic path: [mutate-full] in push commit message(s)." - IS_MUTATE_FULL_TRIGGERED="true" - fi - - if [[ "$IS_MUTATE_FULL_TRIGGERED" == "true" ]]; then - echo "Action: Mode set to 'full' (NUM_GROUPS=16) due to [mutate-full] trigger." - FINAL_MUTANT_MODE="full" - FINAL_NUM_GROUPS=16 - else - if [[ "$EVENT_NAME" == "pull_request" ]]; then - echo "Logic path: Pull request event (no [mutate-full] trigger)." - echo "Action: Mode set to 'incremental' (NUM_GROUPS=2) for PR." - FINAL_MUTANT_MODE="incremental" - FINAL_NUM_GROUPS=2 - FINAL_SINCE_TARGET="origin/$PR_BASE_REF" - echo "Incremental target: $FINAL_SINCE_TARGET" - elif [[ "$EVENT_NAME" == "push" ]]; then - if [[ "$REF_NAME" == "master" ]]; then # UWAGA: W oryginalnym pliku było "master", a nie "master" || "main". Dostosuj jeśli trzeba. - echo "Logic path: Push event to master branch (no [mutate-full] trigger)." - echo "Action: Mode set to 'full' (NUM_GROUPS=16) for master branch." - FINAL_MUTANT_MODE="full" - FINAL_NUM_GROUPS=16 - else - echo "Logic path: Push event to non-master branch ('$REF_NAME') (no [mutate-full] trigger)." - echo "Action: Mode set to 'incremental' (NUM_GROUPS=2) for branch push." - FINAL_MUTANT_MODE="incremental" - FINAL_NUM_GROUPS=2 - FINAL_SINCE_TARGET="origin/master" - echo "Incremental target: $FINAL_SINCE_TARGET" - fi - fi - fi - - echo "mutant_mode=${FINAL_MUTANT_MODE}" >> $GITHUB_OUTPUT - echo "mutant_since_target=${FINAL_SINCE_TARGET}" >> $GITHUB_OUTPUT - echo "num_groups=${FINAL_NUM_GROUPS}" >> $GITHUB_OUTPUT - - echo "--- Final Parameters ---" - echo "Mutant Mode: ${FINAL_MUTANT_MODE}" - echo "Mutant Since Target: ${FINAL_SINCE_TARGET}" - echo "Num Groups: ${FINAL_NUM_GROUPS}" - echo "------------------------" - test: runs-on: ubuntu-24.04 - strategy: - fail-fast: false - env: - WORKING_DIRECTORY: rails_application - services: - postgres: - image: postgres:17-alpine - env: - POSTGRES_DB: cqrs-es-sample-with-res_test - POSTGRES_PASSWORD: secret - ports: - - 5432:5432 - options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 - steps: - - uses: actions/checkout@v3 - - uses: ruby/setup-ruby@v1 - with: - ruby-version: ruby-3.3.7 - bundler-cache: true - working-directory: ${{ env.WORKING_DIRECTORY }} - - name: Assets Precompile - working-directory: ${{ env.WORKING_DIRECTORY }} - run: bundle exec rails tailwindcss:build - - run: make test - working-directory: ${{ env.WORKING_DIRECTORY }} - - uses: 8398a7/action-slack@v3 - with: - status: custom - fields: workflow,commit,repo,ref,author - custom_payload: | - { - attachments: [{ - color: '${{ job.status }}' === 'success' ? 'good' : '${{ job.status }}' === 'failure' ? 'danger' : 'warning', - text: `${process.env.AS_WORKFLOW}/${{ github.job }} ${{ job.status }}\n${process.env.AS_COMMIT} in ${process.env.AS_REF}` - }] - } - env: - SLACK_WEBHOOK_URL: ${{ secrets.CI_WEBHOOK }} - if: always() - continue-on-error: true - - prepare_mutation_subjects_rails: - runs-on: ubuntu-24.04 - needs: determine_run_parameters - outputs: - subject_groups: ${{ steps.split_subjects.outputs.subject_groups }} - env: - WORKING_DIRECTORY: rails_application - services: - postgres: - image: postgres:17-alpine - env: - POSTGRES_DB: cqrs-es-sample-with-res_test - POSTGRES_PASSWORD: secret - ports: - - 5432:5432 - options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 - steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - uses: ruby/setup-ruby@v1 - with: - ruby-version: ruby-3.3.7 - bundler-cache: true - working-directory: ${{ env.WORKING_DIRECTORY }} - - name: List and split subjects for rails_application - id: split_subjects - working-directory: ${{ env.WORKING_DIRECTORY }} - env: - NUM_GROUPS_FROM_CI: ${{ needs.determine_run_parameters.outputs.num_groups }} - run: | - echo "Waiting for PostgreSQL to be ready..." - until pg_isready -h localhost -p 5432 -U "postgres" -d "cqrs-es-sample-with-res_test"; do - sleep 1 - done - echo "PostgreSQL is ready." - - RAILS_ENV=test bundle exec rails db:prepare - - SUBJECT_LIST_OUTPUT=$(RAILS_ENV=test bundle exec mutant environment subject list) - mapfile -t subjects_array < <( \ - echo "$SUBJECT_LIST_OUTPUT" | \ - awk 'NR == 1 {next} /Run options:/ {exit} {print}' | \ - sed 's/\x1b\[[0-9;]*m//g' | \ - sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | \ - awk 'NF' \ - ) - - if [ ${#subjects_array[@]} -eq 0 ]; then - echo "No subjects found for rails_application after cleaning. Setting empty subject_groups." - echo "subject_groups=[]" >> $GITHUB_OUTPUT - exit 0 - fi - - total_subjects=${#subjects_array[@]} - NUM_GROUPS=${NUM_GROUPS_FROM_CI:-16} - echo "Number of parallel groups to create: $NUM_GROUPS" - groups_json_array_content="" - - for (( i=0; i> $GITHUB_OUTPUT - - mutate: - needs: [determine_run_parameters, prepare_mutation_subjects_rails] - if: ${{ needs.prepare_mutation_subjects_rails.outputs.subject_groups != '[]' && needs.prepare_mutation_subjects_rails.outputs.subject_groups != '' }} - runs-on: ubuntu-24.04 - strategy: - fail-fast: false - matrix: - subject_group: ${{ fromJson(needs.prepare_mutation_subjects_rails.outputs.subject_groups) }} - env: - WORKING_DIRECTORY: rails_application - MUTANT_MODE: ${{ needs.determine_run_parameters.outputs.mutant_mode }} - MUTANT_SINCE_TARGET: ${{ needs.determine_run_parameters.outputs.mutant_since_target }} services: postgres: image: postgres:17-alpine @@ -254,82 +21,24 @@ jobs: - 5432:5432 options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 + - uses: actions/checkout@v4 - uses: ruby/setup-ruby@v1 with: ruby-version: ruby-3.3.7 bundler-cache: true - working-directory: ${{ env.WORKING_DIRECTORY }} - - name: Assets Precompile - working-directory: ${{ env.WORKING_DIRECTORY }} - run: bundle exec rails tailwindcss:build - - name: Run mutation tests (parallel group) - run: make mutate - working-directory: ${{ env.WORKING_DIRECTORY }} - env: - CI_MUTATE_SUBJECTS: ${{ matrix.subject_group }} - - notify_rails_mutation_summary: - runs-on: ubuntu-24.04 - needs: [mutate, prepare_mutation_subjects_rails] - if: always() && needs.prepare_mutation_subjects_rails.outputs.subject_groups != '[]' && needs.prepare_mutation_subjects_rails.outputs.subject_groups != '' - steps: - - name: Determine notification color - id: set_color - run: | - if [[ "${{ needs.mutate.result }}" == "success" ]]; then - echo "NOTIFICATION_COLOR=good" >> $GITHUB_ENV - elif [[ "${{ needs.mutate.result }}" == "failure" ]]; then - echo "NOTIFICATION_COLOR=danger" >> $GITHUB_ENV - else - echo "NOTIFICATION_COLOR=warning" >> $GITHUB_ENV - fi - - name: Send mutation summary notification - uses: 8398a7/action-slack@v3 - with: - status: custom - fields: workflow,commit,repo,ref,author - custom_payload: | - { - "attachments": [{ - "color": "${{ env.NOTIFICATION_COLOR }}", - "text": "<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|rails_application> Mutation Test Summary:\nStatus: ${{ needs.mutate.result }}\nWorkflow: <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|${{ github.workflow }}>\nCommit: <${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }}|${{ github.sha }}> in ${{ github.ref }}" - }] - } - env: - SLACK_WEBHOOK_URL: ${{ secrets.CI_WEBHOOK }} - - release: - runs-on: ubuntu-24.04 - strategy: - fail-fast: false - env: - WORKING_DIRECTORY: rails_application - needs: [ test ] - if: ${{ github.ref == 'refs/heads/master' }} - steps: - - name: Install Heroku CLI - run: curl https://cli-assets.heroku.com/install.sh | sh - - uses: actions/checkout@v3 - - uses: akhileshns/heroku-deploy@v3.14.15 - with: - heroku_api_key: ${{ secrets.HEROKU_API_KEY }} - heroku_app_name: "res-ecommerce-rails" - heroku_email: "dev@arkency.com" - - uses: 8398a7/action-slack@v3 - with: - status: custom - fields: workflow,job,commit,repo,ref,author,took - custom_payload: | - { - attachments: [{ - color: '${{ job.status }}' === 'success' ? 'good' : '${{ job.status }}' === 'failure' ? 'danger' : 'warning', - text: `${process.env.AS_WORKFLOW}/${{ github.job }} ${{ job.status }} in ${process.env.AS_TOOK}\n${process.env.AS_COMMIT} in ${process.env.AS_REF}`, - }] - } - env: - SLACK_WEBHOOK_URL: ${{ secrets.RELEASE_WEBHOOK }} - if: always() - continue-on-error: true + working-directory: rails_application + - name: Run tests + run: make -C rails_application test + env: + DATABASE_URL: "postgres://postgres:secret@localhost:5432/cqrs-es-sample-with-res_test" + RAILS_ENV: test + deploy: + needs: test + if: github.event_name == 'push' && github.ref == 'refs/heads/master' + uses: ./.github/workflows/infra.yml + with: + app_name: rails_application + secrets: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AWS_REGION: ${{ secrets.AWS_REGION }} diff --git a/ecommerce/pricing/Makefile b/ecommerce/pricing/Makefile index 2ed702e7d..7382e574b 100644 --- a/ecommerce/pricing/Makefile +++ b/ecommerce/pricing/Makefile @@ -1,44 +1,21 @@ -MUTANT_MODE_INTERNAL := $(PASSED_MODE) -MUTANT_SINCE_TARGET_INTERNAL := $(PASSED_SINCE_TARGET) +GIT_BASE_SHA ?= $(shell git merge-base HEAD origin/master) install: @bundle install test: - @echo "Running unit tests for pricing" - @bundle exec ruby -e "require \"rake/rake_test_loader\"" test/*_test.rb + @bundle exec ruby -e "require 'rake/rake_test_loader'" test/*_test.rb -mutate: - $(eval SUBJECTS_TO_RUN := $(strip $(CI_MUTATE_SUBJECTS))) - $(eval TEMP_ACTUAL_MUTANT_ARGS :=) +mutate: ## Run full mutation tests + @echo "Running full mutation tests..." + @RUBYOPT="-Ilib -Itest" bundle exec mutant run 'Pricing*' - @echo "--- Preparing Mutation Test Run for pricing ---" -ifeq ($(MUTANT_MODE_INTERNAL),incremental) - @echo " Conditional: MUTANT_MODE_INTERNAL is 'incremental'." - ifndef MUTANT_SINCE_TARGET_INTERNAL - $(error FATAL ERROR (Makefile): MUTANT_MODE_INTERNAL ('$(MUTANT_MODE_INTERNAL)') is incremental, but MUTANT_SINCE_TARGET_INTERNAL is NOT DEFINED. PASSED_SINCE_TARGET was '$(PASSED_SINCE_TARGET)'.) - endif - ifeq ($(strip $(MUTANT_SINCE_TARGET_INTERNAL)),) - $(error FATAL ERROR (Makefile): MUTANT_MODE_INTERNAL ('$(MUTANT_MODE_INTERNAL)') is incremental, but MUTANT_SINCE_TARGET_INTERNAL IS EMPTY. PASSED_SINCE_TARGET was '$(PASSED_SINCE_TARGET)', internal value was '[$(MUTANT_SINCE_TARGET_INTERNAL)]'.) - endif +mutate-changes: ## Run incremental mutation tests on changes + @echo "Running incremental mutation tests against $(GIT_BASE_SHA)..." + @RUBYOPT="-Ilib -Itest" bundle exec mutant run --since $(GIT_BASE_SHA) 'Pricing*' - @echo " MUTANT_SINCE_TARGET_INTERNAL appears to be set and non-empty: '[$(MUTANT_SINCE_TARGET_INTERNAL)]'" - $(eval TEMP_ACTUAL_MUTANT_ARGS := --since $(MUTANT_SINCE_TARGET_INTERNAL)) - @echo " Action: Set for Incremental Mutation." - @echo " Target for --since: '$(MUTANT_SINCE_TARGET_INTERNAL)'" -else - @echo " Conditional: MUTANT_MODE_INTERNAL is NOT 'incremental' (actual value: '$(MUTANT_MODE_INTERNAL)'). Setting for Full Mutation." -endif +help: + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%%-30s\033[0m %%s\n", $$1, $$2}' - @echo " Final TEMP_ACTUAL_MUTANT_ARGS: '$(TEMP_ACTUAL_MUTANT_ARGS)'" -ifeq ($(SUBJECTS_TO_RUN),) - @echo " Subjects: All relevant (within scope of full/incremental mode)" -else - @echo " Subjects: Specific group for CI - '$(SUBJECTS_TO_RUN)'" -endif - @echo "-----------------------------------------------------" - - @echo "Executing: bundle exec mutant run $(TEMP_ACTUAL_MUTANT_ARGS) $(SUBJECTS_TO_RUN)" - @bundle exec mutant run $(TEMP_ACTUAL_MUTANT_ARGS) $(SUBJECTS_TO_RUN) - -.PHONY: install test mutate +.PHONY: install test mutate mutate-changes help +.DEFAULT_GOAL := help diff --git a/ecommerce/pricing/test/test_helper.rb b/ecommerce/pricing/test/test_helper.rb index 4830dd82a..1054c00ed 100644 --- a/ecommerce/pricing/test/test_helper.rb +++ b/ecommerce/pricing/test/test_helper.rb @@ -1,4 +1,7 @@ -require "minitest/autorun" +unless $PROGRAM_NAME.end_with?('/mutant') && ARGV.any? { |arg| arg.start_with?('--since') } + require "minitest/autorun" +end + require "mutant/minitest/coverage" require "active_support/all" diff --git a/rails_application/Makefile b/rails_application/Makefile index 38c3b7b32..496f68332 100644 --- a/rails_application/Makefile +++ b/rails_application/Makefile @@ -1,48 +1,33 @@ +GIT_BASE_SHA ?= $(shell git merge-base HEAD origin/master) + install: ## Installs dependencies, runs migrations, creates db & seeds if necessary @bin/setup - @env RAILS_ENV=test bin/rails db:create dev: - @$(MAKE) -j 10 web css - -mutate: ## Run mutation tests - $(eval ACTUAL_MUTANT_ARGS :=) - $(eval SUBJECTS_TO_RUN := $(strip $(CI_MUTATE_SUBJECTS))) - - @echo "--- Preparing Mutation Test Run ---" -ifeq ($(MUTANT_MODE),incremental) - ifndef MUTANT_SINCE_TARGET - $(error MUTANT_MODE is 'incremental', but MUTANT_SINCE_TARGET is not set. This variable should be set by the CI workflow.) - endif - $(eval ACTUAL_MUTANT_ARGS := --since $(MUTANT_SINCE_TARGET)) - @echo "Mutation Mode: Incremental" - @echo "Target for --since: $(MUTANT_SINCE_TARGET)" -else - @echo "Mutation Mode: Full" -endif - -ifeq ($(SUBJECTS_TO_RUN),) - @echo "Subjects: All relevant (within scope of full/incremental mode)" -else - @echo "Subjects: Specific group for CI - '$(SUBJECTS_TO_RUN)'" -endif - @echo "------------------------------------" - @echo "Executing: env RAILS_ENV=test bundle exec mutant run $(ACTUAL_MUTANT_ARGS) $(SUBJECTS_TO_RUN)" - @env RAILS_ENV=test bundle exec mutant run $(ACTUAL_MUTANT_ARGS) $(SUBJECTS_TO_RUN) + @$(MAKE) -j 2 web css + +mutate: ## Run full mutation tests + @echo "Running full mutation tests..." + @RAILS_ENV=test bundle exec mutant run + +mutate-changes: ## Run incremental mutation tests on changes + @echo "Running incremental mutation tests against $(GIT_BASE_SHA)..." + @RAILS_ENV=test bundle exec mutant run --since $(GIT_BASE_SHA) test: ## Run unit tests + @echo "Building Tailwind CSS..." @bin/rails tailwindcss:build - @echo "Running unit tests" + @echo "Running unit tests..." @bin/rails test help: - @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' - -.PHONY: help test db -.DEFAULT_GOAL := help + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%%-30s\033[0m %%s\n", $$1, $$2}' css: - bin/rails tailwindcss:watch[always] + @bin/rails tailwindcss:watch[always] web: - bin/rails server -p 3000 + @bin/rails server -p 3000 + +.PHONY: help install dev test mutate mutate-changes css web +.DEFAULT_GOAL := help