Add minimum coverage threshold (2/6): Service logic & REST API
What does this MR do and why?
This is MR 2 of 6 in a stacked series that adds a minimum coverage threshold to the Coverage-Check approval rule.
| MR | Branch | Base | Content |
|---|---|---|---|
| 1 | 6284-coverage-threshold-1-db-model-ff |
master |
DB migration & model validation (!226363 (merged)) |
| 2 (this MR) | 6284-coverage-threshold-2-service-rest |
6284-coverage-threshold-1-db-model-ff |
Service logic, REST API & feature flag |
| 3 | 6284-coverage-threshold-3-graphql |
6284-coverage-threshold-2-service-rest |
GraphQL mutations & fields |
| 4 | 6284-coverage-threshold-4-blockage-reason |
6284-coverage-threshold-3-graphql |
blockage_reason feature & GraphQL exposure |
| 5 | 6284-coverage-threshold-5-frontend |
6284-coverage-threshold-4-blockage-reason |
Frontend: Settings UI + MR widget feedback |
| 6 | 6284-coverage-threshold-6-docs |
master |
Documentation (standalone, no dependency) |
Splitting was discussed and agreed upon with @kherman1 and @hfyngvason in !224343 (closed).
This MR includes:
coverage_minimum_thresholdfeature flag (gitlab_com_derisk) definition, introduced here together with its first consumer in the critical mergeability path (recommended by @hfyngvason; relocated from MR 1 per @SamWord's review)- Absolute threshold check in
Ci::SyncReportsToApprovalRulesService#require_coverage_approval?, gated behind the feature flag. When enabled and a threshold is set, approval is required if pipeline coverage falls below the threshold, regardless of whether coverage decreased from the base pipeline. - Helper method
coverage_minimum_threshold_forto read the threshold from the MR's approval rules - REST API
coverage_minimum_thresholdparameter on project approval rule create and update endpoints coverage_minimum_thresholdexposure in the approval rule API entity (only forcode_coveragerules)- Standardized API parameter descriptions per reviewer feedback from @idurham
- Generated OpenAPI v2/v3 documentation updates
Files to review in this MR
Note: This is a stacked MR. The diff shows cumulative changes against
master. Please focus your review on the files listed below, which are the ones introduced in this MR.
ee/config/feature_flags/gitlab_com_derisk/coverage_minimum_threshold.yml- Feature flag definitionee/app/services/ci/sync_reports_to_approval_rules_service.rb- Threshold check + helper methodee/lib/api/entities/approval_rule.rb- Entity exposureee/lib/api/helpers/project_approval_rules_helpers.rb- API parameters (create + update)ee/spec/services/ci/sync_reports_to_approval_rules_service_spec.rb- Service testsee/spec/requests/api/project_approval_rules_spec.rb- API integration testsdoc/api/openapi/openapi_v2.yaml- Generated OpenAPI v2doc/api/openapi/openapi_v3.yaml- Generated OpenAPI v3
Related to #6284 Extracted from !224343 (closed)
How to set up and validate locally
Prerequisites
- MR 1 (!226363 (merged)) must be applied first (migration run)
1. Enable the feature flag
Feature.enable(:coverage_minimum_threshold)
2. Test the REST API
Replace <TOKEN> with your personal access token and <PROJECT_ID> with a project ID where you are a maintainer.
Create a coverage rule with threshold:
curl -s -X POST "http://gdk.local:3000/api/v4/projects/<PROJECT_ID>/approval_rules" \
-H "PRIVATE-TOKEN: <TOKEN>" \
-H "Content-Type: application/json" \
-d '{"name": "Coverage-Check", "approvals_required": 1, "report_type": "code_coverage", "coverage_minimum_threshold": 80.0}'Expected response includes:
{
"id": 123,
"name": "Coverage-Check",
"report_type": "code_coverage",
"coverage_minimum_threshold": 80.0
}Update the threshold:
curl -s -X PUT "http://gdk.local:3000/api/v4/projects/<PROJECT_ID>/approval_rules/<RULE_ID>" \
-H "PRIVATE-TOKEN: <TOKEN>" \
-H "Content-Type: application/json" \
-d '{"coverage_minimum_threshold": 90.0}'Expected: coverage_minimum_threshold is now 90.0 in the response.
Delete the rule (cleanup):
curl -s -X DELETE "http://gdk.local:3000/api/v4/projects/<PROJECT_ID>/approval_rules/<RULE_ID>" \
-H "PRIVATE-TOKEN: <TOKEN>"3. Verify service logic in Rails console
# The service checks threshold in require_coverage_approval?
# When coverage_minimum_threshold is set and pipeline coverage is below it,
# the approval rule will NOT have its approvals_required lowered to 0,
# meaning approval stays required.
# Verify the method exists and is gated:
service = Ci::SyncReportsToApprovalRulesService.new(Ci::Pipeline.last)
service.respond_to?(:execute, true)
# => true4. Run the specs
bundle exec rspec ee/spec/services/ci/sync_reports_to_approval_rules_service_spec.rb \
-e 'coverage_minimum_threshold'
# Expected: 11 examples, 0 failures
bundle exec rspec ee/spec/requests/api/project_approval_rules_spec.rb \
-e 'coverage_minimum_threshold'
# Expected: 2 examples, 0 failuresMR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.
- The change is backwards compatible. When
coverage_minimum_thresholdisnil, the existing relative coverage check is unchanged. - Threshold check is gated behind
coverage_minimum_thresholdfeature flag to protect the critical mergeability path. - Feature flag definition is introduced together with its first consumer to comply with the broken-master guideline.
- No N+1 queries introduced.
coverage_minimum_threshold_forusespick(single value query). - API changes are additive (new optional parameter), no breaking changes.
- API parameter descriptions standardized per reviewer feedback.
Related to #6284