Skip to content

Commit 690b69b

Browse files
committed
For selected contexts split & run mutation tests in parallel jobs to shorten the execution time.
1 parent ca6e770 commit 690b69b

File tree

4 files changed

+127
-3
lines changed

4 files changed

+127
-3
lines changed

.github/workflows/pricing.yml

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,64 @@ jobs:
3535
if: always()
3636
continue-on-error: true
3737

38+
prepare_mutation_subjects_pricing:
39+
runs-on: ubuntu-24.04
40+
outputs:
41+
subject_groups: ${{ steps.split_subjects.outputs.subject_groups }}
42+
env:
43+
WORKING_DIRECTORY: ecommerce/pricing
44+
steps:
45+
- uses: actions/checkout@v3
46+
- uses: ruby/setup-ruby@v1
47+
with:
48+
ruby-version: ruby-3.3.7
49+
bundler-cache: true
50+
working-directory: ${{ env.WORKING_DIRECTORY }}
51+
- name: List and split subjects for pricing
52+
id: split_subjects
53+
working-directory: ${{ env.WORKING_DIRECTORY }}
54+
run: |
55+
SUBJECT_LIST_OUTPUT=$(RAILS_ENV=test bundle exec mutant environment subject list)
56+
# Skip the first line (e.g., "Subjects in environment: XX") and read subjects into an array
57+
mapfile -t subjects_array < <(echo "$SUBJECT_LIST_OUTPUT" | tail -n +2 | sed 's/\x1b\[[0-9;]*m//g' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | awk 'NF')
58+
59+
if [ ${#subjects_array[@]} -eq 0 ]; then
60+
echo "No subjects found for pricing. Setting empty subject_groups."
61+
echo "subject_groups=[]" >> $GITHUB_OUTPUT
62+
exit 0
63+
fi
64+
65+
total_subjects=${#subjects_array[@]}
66+
NUM_GROUPS=2 # Define the number of parallel jobs
67+
groups_json_array_content=""
68+
69+
for (( i=0; i<NUM_GROUPS; i++ )); do
70+
current_group_subjects_array=()
71+
for (( j=i; j<total_subjects; j+=NUM_GROUPS )); do
72+
current_group_subjects_array+=("${subjects_array[j]}")
73+
done
74+
75+
if [ ${#current_group_subjects_array[@]} -gt 0 ]; then
76+
group_subjects_string=$(IFS=' '; echo "${current_group_subjects_array[*]}")
77+
78+
if [ -n "$groups_json_array_content" ]; then
79+
groups_json_array_content="$groups_json_array_content,"
80+
fi
81+
escaped_group_subjects_string=$(printf '%s' "$group_subjects_string" | sed 's/"/\\"/g')
82+
groups_json_array_content="$groups_json_array_content\"$escaped_group_subjects_string\""
83+
fi
84+
done
85+
echo "Generated subject_groups: [$groups_json_array_content]"
86+
echo "subject_groups=[$groups_json_array_content]" >> $GITHUB_OUTPUT
87+
3888
mutate:
89+
needs: prepare_mutation_subjects_pricing
90+
if: ${{ needs.prepare_mutation_subjects_pricing.outputs.subject_groups != '[]' && needs.prepare_mutation_subjects_pricing.outputs.subject_groups != '' }}
3991
runs-on: ubuntu-24.04
4092
strategy:
4193
fail-fast: false
94+
matrix:
95+
subject_group: ${{ fromJson(needs.prepare_mutation_subjects_pricing.outputs.subject_groups) }}
4296
env:
4397
WORKING_DIRECTORY: ecommerce/pricing
4498
steps:
@@ -50,6 +104,8 @@ jobs:
50104
working-directory: ${{ env.WORKING_DIRECTORY }}
51105
- run: make mutate
52106
working-directory: ${{ env.WORKING_DIRECTORY }}
107+
env:
108+
CI_MUTATE_SUBJECTS: ${{ matrix.subject_group }}
53109
- uses: 8398a7/action-slack@v3
54110
with:
55111
status: custom
@@ -58,7 +114,7 @@ jobs:
58114
{
59115
attachments: [{
60116
color: '${{ job.status }}' === 'success' ? 'good' : '${{ job.status }}' === 'failure' ? 'danger' : 'warning',
61-
text: `${process.env.AS_WORKFLOW}/${process.env.AS_JOB} ${{ job.status }} in ${process.env.AS_TOOK}\n${process.env.AS_COMMIT} in ${process.env.AS_REF}`,
117+
text: `${process.env.AS_WORKFLOW}/${process.env.AS_JOB} (shard ${{ strategy.job-index+1 }}/${{ strategy.job-total }}) ${{ job.status }} in ${process.env.AS_TOOK}\n${process.env.AS_COMMIT} in ${process.env.AS_REF}`,
62118
}]
63119
}
64120
env:

.github/workflows/rails_application.yml

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,64 @@ jobs:
4747
if: always()
4848
continue-on-error: true
4949

50+
prepare_mutation_subjects_rails:
51+
runs-on: ubuntu-24.04
52+
outputs:
53+
subject_groups: ${{ steps.split_subjects.outputs.subject_groups }}
54+
env:
55+
WORKING_DIRECTORY: rails_application
56+
steps:
57+
- uses: actions/checkout@v3
58+
- uses: ruby/setup-ruby@v1
59+
with:
60+
ruby-version: ruby-3.3.7
61+
bundler-cache: true
62+
working-directory: ${{ env.WORKING_DIRECTORY }}
63+
- name: List and split subjects for rails_application
64+
id: split_subjects
65+
working-directory: ${{ env.WORKING_DIRECTORY }}
66+
run: |
67+
SUBJECT_LIST_OUTPUT=$(RAILS_ENV=test bundle exec mutant environment subject list)
68+
# Skip the first line (e.g., "Subjects in environment: 47") and read subjects into an array
69+
mapfile -t subjects_array < <(echo "$SUBJECT_LIST_OUTPUT" | tail -n +2 | sed 's/\x1b\[[0-9;]*m//g' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | awk 'NF')
70+
71+
if [ ${#subjects_array[@]} -eq 0 ]; then
72+
echo "No subjects found for rails_application. Setting empty subject_groups."
73+
echo "subject_groups=[]" >> $GITHUB_OUTPUT
74+
exit 0
75+
fi
76+
77+
total_subjects=${#subjects_array[@]}
78+
NUM_GROUPS=2 # Define the number of parallel jobs
79+
groups_json_array_content=""
80+
81+
for (( i=0; i<NUM_GROUPS; i++ )); do
82+
current_group_subjects_array=()
83+
for (( j=i; j<total_subjects; j+=NUM_GROUPS )); do
84+
current_group_subjects_array+=("${subjects_array[j]}")
85+
done
86+
87+
if [ ${#current_group_subjects_array[@]} -gt 0 ]; then
88+
group_subjects_string=$(IFS=' '; echo "${current_group_subjects_array[*]}")
89+
90+
if [ -n "$groups_json_array_content" ]; then
91+
groups_json_array_content="$groups_json_array_content,"
92+
fi
93+
escaped_group_subjects_string=$(printf '%s' "$group_subjects_string" | sed 's/"/\\"/g')
94+
groups_json_array_content="$groups_json_array_content\"$escaped_group_subjects_string\""
95+
fi
96+
done
97+
echo "Generated subject_groups: [$groups_json_array_content]"
98+
echo "subject_groups=[$groups_json_array_content]" >> $GITHUB_OUTPUT
99+
50100
mutate:
101+
needs: prepare_mutation_subjects_rails
102+
if: ${{ needs.prepare_mutation_subjects_rails.outputs.subject_groups != '[]' && needs.prepare_mutation_subjects_rails.outputs.subject_groups != '' }}
51103
runs-on: ubuntu-24.04
52104
strategy:
53105
fail-fast: false
106+
matrix:
107+
subject_group: ${{ fromJson(needs.prepare_mutation_subjects_rails.outputs.subject_groups) }}
54108
env:
55109
WORKING_DIRECTORY: rails_application
56110
services:
@@ -74,6 +128,8 @@ jobs:
74128
run: bundle exec rails tailwindcss:build
75129
- run: make mutate
76130
working-directory: ${{ env.WORKING_DIRECTORY }}
131+
env:
132+
CI_MUTATE_SUBJECTS: ${{ matrix.subject_group }}
77133
- uses: 8398a7/action-slack@v3
78134
with:
79135
status: custom
@@ -82,7 +138,7 @@ jobs:
82138
{
83139
attachments: [{
84140
color: '${{ job.status }}' === 'success' ? 'good' : '${{ job.status }}' === 'failure' ? 'danger' : 'warning',
85-
text: `${process.env.AS_WORKFLOW}/${process.env.AS_JOB} ${{ job.status }} in ${process.env.AS_TOOK}\n${process.env.AS_COMMIT} in ${process.env.AS_REF}`,
141+
text: `${process.env.AS_WORKFLOW}/${process.env.AS_JOB} (shard ${{ strategy.job-index+1 }}/${{ strategy.job-total }}) ${{ job.status }} in ${process.env.AS_TOOK}\n${process.env.AS_COMMIT} in ${process.env.AS_REF}`,
86142
}]
87143
}
88144
env:

ecommerce/pricing/Makefile

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ test:
55
@bundle exec ruby -e "require \"rake/rake_test_loader\"" test/*_test.rb
66

77
mutate:
8-
@RAILS_ENV=test bundle exec mutant run
8+
ifeq ($(CI_MUTATE_SUBJECTS),)
9+
@echo "Running all mutation tests (local or full CI run)"
10+
@env RAILS_ENV=test bundle exec mutant run
11+
else
12+
@echo "Running CI mutation tests for subjects: $(CI_MUTATE_SUBJECTS)"
13+
@env RAILS_ENV=test bundle exec mutant run $(CI_MUTATE_SUBJECTS)
14+
endif
915

1016
.PHONY: install test mutate

rails_application/Makefile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,13 @@ dev:
66
@$(MAKE) -j 10 web css
77

88
mutate: ## Run mutation tests
9+
ifeq ($(CI_MUTATE_SUBJECTS),)
10+
@echo "Running all mutation tests (local or full CI run)"
911
@env RAILS_ENV=test bundle exec mutant run
12+
else
13+
@echo "Running CI mutation tests for subjects: $(CI_MUTATE_SUBJECTS)"
14+
@env RAILS_ENV=test bundle exec mutant run $(CI_MUTATE_SUBJECTS)
15+
endif
1016

1117
test: ## Run unit tests
1218
@bin/rails tailwindcss:build

0 commit comments

Comments
 (0)