code-quality-gates

Code Quality Gates — Expert Decisions

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "code-quality-gates" with this command: npx skills add kaakati/rails-enterprise-dev/kaakati-rails-enterprise-dev-code-quality-gates

Code Quality Gates — Expert Decisions

Expert decision frameworks for quality gate choices. Claude knows linting tools — this skill provides judgment calls for threshold calibration and rule selection.

Decision Trees

Which Quality Gates for Your Project

Project stage? ├─ Greenfield (new project) │ └─ Enable ALL gates from day 1 │ • SwiftLint (strict) │ • SwiftFormat │ • SWIFT_TREAT_WARNINGS_AS_ERRORS = YES │ • Coverage > 80% │ ├─ Brownfield (legacy, no gates) │ └─ Adopt incrementally: │ 1. SwiftLint with --baseline (ignore existing) │ 2. Format new files only │ 3. Gradually increase thresholds │ └─ Existing project with some gates └─ Team size? ├─ Solo/Small (1-3) → Lint + Format sufficient └─ Medium+ (4+) → Full pipeline • Add coverage gates • Add static analysis • Add security scanning

Coverage Threshold Selection

What type of code? ├─ Domain/Business Logic │ └─ 90%+ coverage required │ • Business rules must be tested │ • Silent bugs are expensive │ ├─ Data Layer (Repositories, Mappers) │ └─ 85% coverage │ • Test mapping edge cases │ • Test error handling │ ├─ Presentation (ViewModels) │ └─ 70-80% coverage │ • Test state transitions │ • Skip trivial bindings │ └─ Views (SwiftUI) └─ Don't measure coverage • Snapshot tests or manual QA • Unit testing views has poor ROI

SwiftLint Rule Strategy

Starting fresh? ├─ YES → Enable opt_in_rules aggressively │ └─ Easier to disable than enable later │ └─ NO → Adopting on existing codebase └─ Use baseline approach: 1. Run: swiftlint lint --reporter json > baseline.json 2. Configure: baseline_path: baseline.json 3. New violations fail, existing ignored 4. Chip away at baseline over time

NEVER Do

Threshold Anti-Patterns

NEVER set coverage to 100%:

❌ Blocks legitimate PRs, encourages gaming

MIN_COVERAGE: 100

✅ Realistic threshold with room for edge cases

MIN_COVERAGE: 80

NEVER use zero-tolerance for warnings initially on legacy code:

❌ 500 warnings = blocked pipeline forever

SWIFT_TREAT_WARNINGS_AS_ERRORS = YES # On day 1 of legacy project

✅ Incremental adoption

1. First: just report warnings

SWIFT_TREAT_WARNINGS_AS_ERRORS = NO

2. Then: require no NEW warnings

swiftlint lint --baseline existing-violations.json

3. Finally: zero tolerance (after cleanup)

SWIFT_TREAT_WARNINGS_AS_ERRORS = YES

NEVER skip gates on "urgent" PRs:

❌ Creates precedent, gates become meaningless

if: github.event.pull_request.labels.contains('urgent') run: echo "Skipping quality gates"

✅ Gates are non-negotiable

If code can't pass gates, it shouldn't ship

SwiftLint Anti-Patterns

NEVER disable rules project-wide without documenting why:

❌ Mystery disabled rules

disabled_rules:

  • force_unwrapping
  • force_cast
  • line_length

✅ Document the reasoning

disabled_rules:

line_length: Configured separately with custom thresholds

force_unwrapping: Using force_unwrapping opt-in rule instead (stricter)

NEVER use inline disables without explanation:

// ❌ No context // swiftlint:disable force_unwrapping let value = optionalValue! // swiftlint:enable force_unwrapping

// ✅ Explain why exception is valid // swiftlint:disable force_unwrapping // Reason: fatalError path for corrupted bundle resources that should crash let value = optionalValue! // swiftlint:enable force_unwrapping

NEVER silence all warnings in a file:

// ❌ Nuclear option hides real issues // swiftlint:disable all

// ✅ Disable specific rules for specific lines // swiftlint:disable:next identifier_name let x = calculateX() // Math convention

CI Anti-Patterns

NEVER run expensive gates first:

❌ Slow feedback — tests run even if lint fails

jobs: test: # 10 minutes ... lint: # 30 seconds ...

✅ Fast feedback — fail fast on cheap checks

jobs: lint: runs-on: macos-14 steps: [swiftlint, swiftformat]

build: needs: lint # Only if lint passes ...

test: needs: build # Only if build passes ...

NEVER run quality gates only on PR:

❌ Main branch can have violations

on: pull_request: branches: [main]

✅ Protect main branch too

on: push: branches: [main, develop] pull_request: branches: [main, develop]

Essential Configurations

Minimal SwiftLint (Start Here)

.swiftlint.yml — Essential rules only

excluded:

  • Pods
  • .build
  • DerivedData

Most impactful opt-in rules

opt_in_rules:

  • force_unwrapping # Catches crashes
  • implicitly_unwrapped_optional
  • empty_count # Performance
  • first_where # Performance
  • contains_over_first_not_nil
  • fatal_error_message # Debugging

Sensible limits

line_length: warning: 120 error: 200 ignores_urls: true ignores_function_declarations: true

function_body_length: warning: 50 error: 80

cyclomatic_complexity: warning: 10 error: 15

type_body_length: warning: 300 error: 400

file_length: warning: 500 error: 800

Minimal SwiftFormat

.swiftformat — Essentials only

--swiftversion 5.9 --exclude Pods,.build,DerivedData

--indent 4 --maxwidth 120 --wraparguments before-first --wrapparameters before-first

Non-controversial rules

--enable sortedImports --enable trailingCommas --enable redundantSelf --enable redundantReturn --enable blankLinesAtEndOfScope

Disable controversial rules

--disable acronyms --disable wrapMultilineStatementBraces

Xcode Build Settings (Quality Enforced)

QualityGates.xcconfig

// Fail on warnings SWIFT_TREAT_WARNINGS_AS_ERRORS = YES GCC_TREAT_WARNINGS_AS_ERRORS = YES

// Strict concurrency (Swift 6 prep) SWIFT_STRICT_CONCURRENCY = complete

// Static analyzer RUN_CLANG_STATIC_ANALYZER = YES CLANG_STATIC_ANALYZER_MODE = deep

CI Patterns

GitHub Actions (Minimal Effective)

name: Quality Gates

on: push: branches: [main] pull_request: branches: [main]

jobs:

Fast gates first

lint: runs-on: macos-14 steps: - uses: actions/checkout@v4 - run: brew install swiftlint swiftformat - run: swiftlint lint --strict --reporter github-actions-logging - run: swiftformat . --lint

Build only if lint passes

build: needs: lint runs-on: macos-14 steps: - uses: actions/checkout@v4 - name: Build with strict warnings run: | xcodebuild build
-scheme App
-destination 'platform=iOS Simulator,name=iPhone 15'
SWIFT_TREAT_WARNINGS_AS_ERRORS=YES

Test only if build passes

test: needs: build runs-on: macos-14 steps: - uses: actions/checkout@v4 - name: Test with coverage run: | xcodebuild test
-scheme App
-destination 'platform=iOS Simulator,name=iPhone 15'
-enableCodeCoverage YES
-resultBundlePath TestResults.xcresult

  - name: Check coverage threshold
    run: |
      COVERAGE=$(xcrun xccov view --report --json TestResults.xcresult | \
        jq '.targets[] | select(.name | contains("App")) | .lineCoverage * 100')
      echo "Coverage: ${COVERAGE}%"
      if (( $(echo "$COVERAGE < 80" | bc -l) )); then
        echo "❌ Coverage below 80%"
        exit 1
      fi

Pre-commit Hook (Local Enforcement)

#!/bin/bash

.git/hooks/pre-commit

echo "Running pre-commit quality gates..."

SwiftLint (fast)

if ! swiftlint lint --strict --quiet 2>/dev/null; then echo "❌ SwiftLint failed" exit 1 fi

SwiftFormat check (fast)

if ! swiftformat . --lint 2>/dev/null; then echo "❌ Code formatting issues. Run: swiftformat ." exit 1 fi

echo "✅ Pre-commit checks passed"

Threshold Calibration

Finding the Right Coverage Threshold

Step 1: Measure current coverage $ xcodebuild test -enableCodeCoverage YES ... $ xcrun xccov view --report TestResults.xcresult

Step 2: Set threshold slightly below current Current: 73% → Set threshold: 70% Prevents regression without blocking

Step 3: Ratchet up over time Week 1: 70% Week 4: 75% Week 8: 80% Stop at: 80-85% (diminishing returns above)

SwiftLint Warning Budget

Start permissive, tighten over time

Week 1

MAX_WARNINGS: 100

Week 4

MAX_WARNINGS: 50

Week 8

MAX_WARNINGS: 20

Target (after cleanup sprint)

MAX_WARNINGS: 0

Quick Reference

Gate Priority Order

Priority Gate Time ROI

1 SwiftLint ~30s High — catches bugs

2 SwiftFormat ~15s Medium — consistency

3 Build (0 warnings) ~2-5m High — compiler catches issues

4 Unit Tests ~5-15m High — catches regressions

5 Coverage Check ~1m Medium — enforces testing

6 Static Analysis ~5-10m Medium — deep issues

Red Flags

Smell Problem Fix

Gates disabled for "urgent" PR Culture problem Gates are non-negotiable

100% coverage requirement Gaming metrics 80-85% is optimal

All SwiftLint rules enabled Too noisy Curate impactful rules

Pre-commit takes > 30s Devs skip it Only fast checks locally

Different rules in CI vs local Surprises Same config everywhere

SwiftLint Rules Worth Enabling

Rule Why

force_unwrapping

Prevents crashes

implicitly_unwrapped_optional

Prevents crashes

empty_count

Performance (O(1) vs O(n))

first_where

Performance

fatal_error_message

Better crash logs

unowned_variable_capture

Prevents crashes

unused_closure_parameter

Code hygiene

SwiftLint Rules to Avoid

Rule Why Avoid

explicit_type_interface

Swift has inference for a reason

file_types_order

Team preference varies

prefixed_toplevel_constant

Outdated convention

extension_access_modifier

Rarely adds value

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

flutter conventions & best practices

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

ruby oop patterns

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

rails localization (i18n) - english & arabic

No summary provided by upstream source.

Repository SourceNeeds Review