Skip to content

Commit ce27ff2

Browse files
authored
Merge pull request #454 from RailsEventStore/mutations-rethought
Remodeled mutation test configuration on CI
2 parents af5bbf1 + ad087b4 commit ce27ff2

File tree

10 files changed

+269
-654
lines changed

10 files changed

+269
-654
lines changed

.github/workflows/infra.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
name: infra
22
on:
3+
workflow_call:
4+
inputs:
5+
app_name:
6+
description: 'The name of the application to deploy'
7+
required: true
8+
type: string
9+
secrets:
10+
AWS_ACCESS_KEY_ID:
11+
required: true
12+
AWS_SECRET_ACCESS_KEY:
13+
required: true
14+
AWS_REGION:
15+
required: true
316
push:
417
pull_request:
518
types: [opened, reopened]
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
name: pricing-coverage
2+
on:
3+
workflow_dispatch:
4+
repository_dispatch:
5+
types:
6+
- script
7+
push:
8+
branches:
9+
- master
10+
paths:
11+
- "ecommerce/pricing/Gemfile.lock"
12+
- ".github/workflows/pricing-coverage.yml"
13+
pull_request:
14+
paths:
15+
- "ecommerce/pricing/Gemfile.lock"
16+
- ".github/workflows/pricing-coverage.yml"
17+
schedule:
18+
- cron: '0 17 * * *'
19+
jobs:
20+
test:
21+
runs-on: ubuntu-24.04
22+
steps:
23+
- uses: actions/checkout@v4
24+
- uses: ruby/setup-ruby@v1
25+
with:
26+
ruby-version: ruby-3.3.7
27+
bundler-cache: true
28+
working-directory: ecommerce/pricing
29+
- name: Run tests
30+
run: make -C ecommerce/pricing test
31+
mutate:
32+
needs: test
33+
runs-on: ubuntu-24.04
34+
steps:
35+
- uses: actions/checkout@v4
36+
- uses: ruby/setup-ruby@v1
37+
with:
38+
ruby-version: ruby-3.3.7
39+
bundler-cache: true
40+
working-directory: ecommerce/pricing
41+
- name: Run full mutation testing
42+
run: make -C ecommerce/pricing mutate
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: pricing-mutate
2+
on:
3+
push:
4+
pull_request:
5+
types: [opened, reopened]
6+
jobs:
7+
test:
8+
runs-on: ubuntu-24.04
9+
steps:
10+
- uses: actions/checkout@v4
11+
with:
12+
fetch-depth: 0
13+
- uses: ruby/setup-ruby@v1
14+
with:
15+
ruby-version: ruby-3.3.7
16+
bundler-cache: true
17+
working-directory: ecommerce/pricing
18+
- name: Run tests
19+
run: make -C ecommerce/pricing test
20+
mutate:
21+
needs: test
22+
runs-on: ubuntu-24.04
23+
steps:
24+
- uses: actions/checkout@v4
25+
with:
26+
fetch-depth: 0
27+
- uses: ruby/setup-ruby@v1
28+
with:
29+
ruby-version: ruby-3.3.7
30+
bundler-cache: true
31+
working-directory: ecommerce/pricing
32+
- name: Run incremental mutation testing
33+
run: make -C ecommerce/pricing mutate-changes

.github/workflows/pricing.yml

Lines changed: 4 additions & 270 deletions
Original file line numberDiff line numberDiff line change
@@ -3,281 +3,15 @@ on:
33
push:
44
pull_request:
55
types: [opened, reopened]
6+
workflow_dispatch:
67
jobs:
7-
determine_run_parameters:
8-
runs-on: ubuntu-24.04
9-
outputs:
10-
mutant_mode: ${{ steps.set_params.outputs.mutant_mode }}
11-
mutant_since_target: ${{ steps.set_params.outputs.mutant_since_target }}
12-
num_groups: ${{ steps.set_params.outputs.num_groups }}
13-
steps:
14-
- name: Determine Mutation Run Parameters
15-
id: set_params
16-
shell: bash
17-
env:
18-
EVENT_NAME: ${{ github.event_name }}
19-
REF_NAME: ${{ github.ref_name }}
20-
PR_BASE_REF: ${{ github.event.pull_request.base.ref }}
21-
PR_TITLE: ${{ github.event.pull_request.title }}
22-
PR_BODY: ${{ github.event.pull_request.body }}
23-
COMMIT_MESSAGES_JOINED_WITH_SPACES_ACTIONS: ${{ join(github.event.commits.*.message, ' ') }}
24-
COMMIT_MESSAGES_JOINED_WITH_SLASHES_ACTIONS: ${{ join(github.event.commits.*.message, ' // ') }}
25-
26-
run: |
27-
echo "--- Debug: Determining mutation run parameters for pricing ---"
28-
echo "Event name: $EVENT_NAME"
29-
echo "Ref name: $REF_NAME"
30-
echo "Base ref (for PR): $PR_BASE_REF"
31-
echo "PR title: $PR_TITLE"
32-
33-
RAW_COMMIT_MESSAGES_FOR_JOIN_WITH_SLASHES="$COMMIT_MESSAGES_JOINED_WITH_SLASHES_ACTIONS"
34-
RAW_COMMIT_MESSAGES_FOR_JOIN_WITH_SPACES="$COMMIT_MESSAGES_FOR_JOIN_WITH_SPACES_ACTIONS"
35-
36-
CLEANED_COMMIT_MESSAGES_FOR_LOG="${RAW_COMMIT_MESSAGES_FOR_JOIN_WITH_SLASHES//\'/}"
37-
COMMIT_MESSAGES_LOG=$(echo "${CLEANED_COMMIT_MESSAGES_FOR_LOG}" | head -c 500)
38-
echo "Commit messages in push (cleaned, first 500 chars): ${COMMIT_MESSAGES_LOG}..."
39-
40-
CLEANED_COMMIT_MESSAGES_FOR_CONTAINS="${RAW_COMMIT_MESSAGES_FOR_JOIN_WITH_SPACES//\'/}"
41-
42-
if [[ "${CLEANED_COMMIT_MESSAGES_FOR_CONTAINS}" == *"[mutate-full]"* ]]; then
43-
CONTAINS_MUTATE_FULL_IN_PUSH="true"
44-
else
45-
CONTAINS_MUTATE_FULL_IN_PUSH="false"
46-
fi
47-
echo "Contains '[mutate-full]' in push commit messages (from cleaned messages): $CONTAINS_MUTATE_FULL_IN_PUSH"
48-
49-
CLEANED_PR_TITLE="${PR_TITLE//\'/}"
50-
if [[ "${CLEANED_PR_TITLE}" == *"[mutate-full]"* ]]; then
51-
CONTAINS_MUTATE_FULL_IN_PR_TITLE="true"
52-
else
53-
CONTAINS_MUTATE_FULL_IN_PR_TITLE="false"
54-
fi
55-
echo "Contains '[mutate-full]' in PR title (from cleaned title): $CONTAINS_MUTATE_FULL_IN_PR_TITLE"
56-
57-
CLEANED_PR_BODY="${PR_BODY//\'/}"
58-
if [[ "${CLEANED_PR_BODY}" == *"[mutate-full]"* ]]; then
59-
CONTAINS_MUTATE_FULL_IN_PR_BODY="true"
60-
else
61-
CONTAINS_MUTATE_FULL_IN_PR_BODY="false"
62-
fi
63-
echo "Contains '[mutate-full]' in PR body (from cleaned body): $CONTAINS_MUTATE_FULL_IN_PR_BODY"
64-
65-
echo "---------------------------------------------"
66-
67-
FINAL_MUTANT_MODE="full"
68-
FINAL_NUM_GROUPS=16
69-
FINAL_SINCE_TARGET=""
70-
71-
IS_MUTATE_FULL_TRIGGERED="false"
72-
if [[ "$EVENT_NAME" == "pull_request" && \
73-
( "$CONTAINS_MUTATE_FULL_IN_PR_TITLE" == "true" || "$CONTAINS_MUTATE_FULL_IN_PR_BODY" == "true" ) ]]; then
74-
echo "Logic path: [mutate-full] in PR title/body."
75-
IS_MUTATE_FULL_TRIGGERED="true"
76-
elif [[ "$EVENT_NAME" == "push" && "$CONTAINS_MUTATE_FULL_IN_PUSH" == "true" ]]; then
77-
echo "Logic path: [mutate-full] in push commit message(s)."
78-
IS_MUTATE_FULL_TRIGGERED="true"
79-
fi
80-
81-
if [[ "$IS_MUTATE_FULL_TRIGGERED" == "true" ]]; then
82-
echo "Action: Mode set to 'full' (NUM_GROUPS=16) due to [mutate-full] trigger."
83-
FINAL_MUTANT_MODE="full"
84-
FINAL_NUM_GROUPS=16
85-
else
86-
if [[ "$EVENT_NAME" == "pull_request" ]]; then
87-
echo "Logic path: Pull request event (no [mutate-full] trigger)."
88-
echo "Action: Mode set to 'incremental' (NUM_GROUPS=2) for PR."
89-
FINAL_MUTANT_MODE="incremental"
90-
FINAL_NUM_GROUPS=2
91-
FINAL_SINCE_TARGET="origin/$PR_BASE_REF"
92-
echo "Incremental target: $FINAL_SINCE_TARGET"
93-
elif [[ "$EVENT_NAME" == "push" ]]; then
94-
if [[ "$REF_NAME" == "master" || "$REF_NAME" == "main" ]]; then
95-
echo "Logic path: Push event to main branch (no [mutate-full] trigger)."
96-
echo "Action: Mode set to 'full' (NUM_GROUPS=16) for main branch."
97-
FINAL_MUTANT_MODE="full"
98-
FINAL_NUM_GROUPS=16
99-
else
100-
echo "Logic path: Push event to non-main branch ('$REF_NAME') (no [mutate-full] trigger)."
101-
echo "Action: Mode set to 'incremental' (NUM_GROUPS=2) for branch push."
102-
FINAL_MUTANT_MODE="incremental"
103-
FINAL_NUM_GROUPS=2
104-
FINAL_SINCE_TARGET="origin/master"
105-
echo "Incremental target: $FINAL_SINCE_TARGET"
106-
fi
107-
fi
108-
fi
109-
110-
echo "Debug before GITHUB_OUTPUT: FINAL_MUTANT_MODE='${FINAL_MUTANT_MODE}'"
111-
echo "Debug before GITHUB_OUTPUT: FINAL_SINCE_TARGET='${FINAL_SINCE_TARGET}'"
112-
echo "Debug before GITHUB_OUTPUT: FINAL_NUM_GROUPS='${FINAL_NUM_GROUPS}'"
113-
114-
echo "mutant_mode=${FINAL_MUTANT_MODE}" >> $GITHUB_OUTPUT
115-
echo "mutant_since_target=${FINAL_SINCE_TARGET}" >> $GITHUB_OUTPUT
116-
echo "num_groups=${FINAL_NUM_GROUPS}" >> $GITHUB_OUTPUT
117-
118-
echo "--- Final Parameters for pricing ---"
119-
echo "Mutant Mode: ${FINAL_MUTANT_MODE}"
120-
echo "Mutant Since Target: ${FINAL_SINCE_TARGET}"
121-
echo "Num Groups: ${FINAL_NUM_GROUPS}"
122-
echo "------------------------"
123-
1248
test:
1259
runs-on: ubuntu-24.04
126-
strategy:
127-
fail-fast: false
128-
env:
129-
WORKING_DIRECTORY: ecommerce/pricing
130-
steps:
131-
- uses: actions/checkout@v3
132-
- uses: ruby/setup-ruby@v1
133-
with:
134-
ruby-version: ruby-3.3.7
135-
bundler-cache: true
136-
working-directory: ${{ env.WORKING_DIRECTORY }}
137-
- run: make test
138-
working-directory: ${{ env.WORKING_DIRECTORY }}
139-
- uses: 8398a7/action-slack@v3
140-
with:
141-
status: custom
142-
fields: workflow,job,commit,repo,ref,author,took
143-
custom_payload: |
144-
{
145-
attachments: [{
146-
color: '${{ job.status }}' === 'success' ? 'good' : '${{ job.status }}' === 'failure' ? 'danger' : 'warning',
147-
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`,
148-
}]
149-
}
150-
env:
151-
SLACK_WEBHOOK_URL: ${{ secrets.CI_WEBHOOK }}
152-
if: always()
153-
continue-on-error: true
154-
155-
prepare_mutation_subjects_pricing:
156-
runs-on: ubuntu-24.04
157-
needs: determine_run_parameters
158-
outputs:
159-
subject_groups: ${{ steps.split_subjects.outputs.subject_groups }}
160-
env:
161-
WORKING_DIRECTORY: ecommerce/pricing
162-
steps:
163-
- uses: actions/checkout@v3
164-
with:
165-
fetch-depth: 0
166-
- uses: ruby/setup-ruby@v1
167-
with:
168-
ruby-version: ruby-3.3.7
169-
bundler-cache: true
170-
working-directory: ${{ env.WORKING_DIRECTORY }}
171-
- name: List and split subjects for pricing
172-
id: split_subjects
173-
working-directory: ${{ env.WORKING_DIRECTORY }}
174-
env:
175-
NUM_GROUPS_FROM_CI: ${{ needs.determine_run_parameters.outputs.num_groups }}
176-
run: |
177-
echo "--- Preparing subjects for pricing ---"
178-
SUBJECT_LIST_OUTPUT=$(bundle exec mutant environment subject list)
179-
180-
mapfile -t subjects_array < <( \
181-
echo "$SUBJECT_LIST_OUTPUT" | \
182-
awk 'NR == 1 {next} /Run options:/ {exit} {print}' | \
183-
sed 's/\x1b\[[0-9;]*m//g' | \
184-
sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | \
185-
awk 'NF' \
186-
)
187-
188-
if [ ${#subjects_array[@]} -eq 0 ]; then
189-
echo "No subjects found for pricing after cleaning. Setting empty subject_groups."
190-
echo "subject_groups=[]" >> $GITHUB_OUTPUT
191-
exit 0
192-
fi
193-
194-
total_subjects=${#subjects_array[@]}
195-
NUM_GROUPS=${NUM_GROUPS_FROM_CI:-2}
196-
echo "Total subjects found: $total_subjects"
197-
echo "Number of parallel groups to create: $NUM_GROUPS"
198-
groups_json_array_content=""
199-
200-
for (( i=0; i<NUM_GROUPS; i++ )); do
201-
current_group_subjects_array=()
202-
for (( j=i; j<total_subjects; j+=NUM_GROUPS )); do
203-
current_group_subjects_array+=("${subjects_array[j]}")
204-
done
205-
206-
if [ ${#current_group_subjects_array[@]} -gt 0 ]; then
207-
group_subjects_string=$(IFS=' '; echo "${current_group_subjects_array[*]}")
208-
209-
if [ -n "$groups_json_array_content" ]; then
210-
groups_json_array_content="$groups_json_array_content,"
211-
fi
212-
escaped_group_subjects_string=$(printf '%s' "$group_subjects_string" | sed 's/"/\\"/g')
213-
groups_json_array_content="$groups_json_array_content\"$escaped_group_subjects_string\""
214-
fi
215-
done
216-
echo "Generated subject_groups for pricing: [$groups_json_array_content]"
217-
echo "subject_groups=[$groups_json_array_content]" >> $GITHUB_OUTPUT
218-
echo "-----------------------------------"
219-
220-
mutate:
221-
needs: [determine_run_parameters, prepare_mutation_subjects_pricing]
222-
if: ${{ needs.prepare_mutation_subjects_pricing.outputs.subject_groups != '[]' && needs.prepare_mutation_subjects_pricing.outputs.subject_groups != '' }}
223-
runs-on: ubuntu-24.04
224-
strategy:
225-
fail-fast: false
226-
matrix:
227-
subject_group: ${{ fromJson(needs.prepare_mutation_subjects_pricing.outputs.subject_groups) }}
228-
env:
229-
WORKING_DIRECTORY: ecommerce/pricing
230-
MUTANT_MODE: ${{ needs.determine_run_parameters.outputs.mutant_mode }}
231-
MUTANT_SINCE_TARGET: ${{ needs.determine_run_parameters.outputs.mutant_since_target }}
23210
steps:
233-
- uses: actions/checkout@v3
234-
with:
235-
fetch-depth: 0
11+
- uses: actions/checkout@v4
23612
- uses: ruby/setup-ruby@v1
23713
with:
23814
ruby-version: ruby-3.3.7
23915
bundler-cache: true
240-
working-directory: ${{ env.WORKING_DIRECTORY }}
241-
- name: Run mutation tests (parallel group for pricing)
242-
run: |
243-
echo "Debug from CI step before calling make (using PASSED_ var names):"
244-
echo " Value for PASSED_MODE='${{ env.ENV_CLI_MUTANT_MODE }}'"
245-
echo " Value for PASSED_SINCE_TARGET='${{ env.ENV_CLI_MUTANT_SINCE_TARGET }}'"
246-
echo " CI_MUTATE_SUBJECTS (from env): '${{ env.CI_MUTATE_SUBJECTS }}'"
247-
248-
make mutate \
249-
PASSED_MODE="${{ env.ENV_CLI_MUTANT_MODE }}" \
250-
PASSED_SINCE_TARGET="${{ env.ENV_CLI_MUTANT_SINCE_TARGET }}"
251-
working-directory: ${{ env.WORKING_DIRECTORY }}
252-
env:
253-
CI_MUTATE_SUBJECTS: ${{ matrix.subject_group }}
254-
255-
notify_pricing_mutation_summary:
256-
runs-on: ubuntu-24.04
257-
needs: [mutate, prepare_mutation_subjects_pricing]
258-
if: always() && needs.prepare_mutation_subjects_pricing.outputs.subject_groups != '[]' && needs.prepare_mutation_subjects_pricing.outputs.subject_groups != ''
259-
steps:
260-
- name: Determine notification color
261-
id: set_color
262-
run: |
263-
if [[ "${{ needs.mutate.result }}" == "success" ]]; then
264-
echo "NOTIFICATION_COLOR=good" >> $GITHUB_ENV
265-
elif [[ "${{ needs.mutate.result }}" == "failure" ]]; then
266-
echo "NOTIFICATION_COLOR=danger" >> $GITHUB_ENV
267-
else
268-
echo "NOTIFICATION_COLOR=warning" >> $GITHUB_ENV
269-
fi
270-
- name: Send mutation summary notification
271-
uses: 8398a7/action-slack@v3
272-
with:
273-
status: custom
274-
fields: workflow,commit,repo,ref,author
275-
custom_payload: |
276-
{
277-
"attachments": [{
278-
"color": "${{ env.NOTIFICATION_COLOR }}",
279-
"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 }}"
280-
}]
281-
}
282-
env:
283-
SLACK_WEBHOOK_URL: ${{ secrets.CI_WEBHOOK }}
16+
working-directory: ecommerce/pricing
17+
- run: make -C ecommerce/pricing test

0 commit comments

Comments
 (0)