Skip to main content

11 - Automatic Code Review with Copilot

Automatic reviews in under 30 seconds: auto-review configuration, custom instructions for organizational standards, and one-click implementable suggestions.

What do you think about this article?

At a Glance

Automatic reviews in under 30 seconds: auto-review configuration, custom instructions for organizational standards, and one-click implementable suggestions.

Automatic Code Review with GitHub Copilot

Code review is one of the pillars of software quality, but it is also one of the most expensive processes in terms of time and resources. In many teams, Pull Requests remain waiting for review for hours or even days, slowing down the entire development cycle. GitHub Copilot Code Review addresses this problem by providing AI-powered reviews that complete the analysis in less than 30 seconds.

In this article we will explore how to configure automatic review, how the analysis process works, how to customize review rules to meet the team's standards, and how to integrate the AI review with human review to maximize code quality.

Series Overview

#ArticleFocus
1Foundation and MindsetSetup and mindset
2Ideation and RequirementsFrom idea to MVP
3Backend ArchitectureAPI and database
4Frontend StructureUI and components
5Prompt EngineeringPrompts and MCP Agents
6Testing and QualityUnit, integration, E2E
7DocumentationREADME, API docs, ADR
8Deploy and DevOpsDocker, CI/CD
9EvolutionScalability and maintenance
10Coding AgentAutonomous development
11You are here → Code ReviewAI-powered review
12Copilot Edits and Agent ModeMulti-file editing
13GitHub SparkAI-native micro-apps
14Copilot Spaces and MemoryShared context
15AI ModelsMulti-model and selection
16CustomizationCustom instructions
17Enterprise and BusinessOrganizational adoption
18Extensions and MarketplaceCopilot Extensions
19SecuritySecurity and compliance

Why Automatic Code Review

Manual code review presents several challenges that impact team productivity and software quality. Understanding these problems helps appreciate the value of automatic review.

Problems with Traditional Code Review

ProblemImpactFrequency
Wait time PRs blocked for hours/days, context switching for the reviewer Very frequent
Inconsistency Different reviewers have different standards, subjective feedback Frequent
Review fatigue After the third PR, attention drops and changes are approved without checking Frequent
Partial coverage The reviewer focuses on logic and overlooks security, performance, edge cases Very frequent
Bottleneck Few senior reviewers become a bottleneck for the entire team Frequent in small teams
Knowledge gaps The reviewer is not familiar with that part of the codebase Occasional

Copilot's automatic review does not replace human review, but complements it. The AI handles mechanical checks (style, patterns, common bugs, security), freeing the human reviewer to focus on aspects that require judgment: architecture, design, readability, and correctness of business logic.

Task Division: AI vs Human

AspectCopilot Code ReviewHuman Review
Style and formattingExcellentNot necessary
Known bug patternsExcellentComplementary
Security vulnerabilitiesGoodEssential for complex cases
Performance issuesGood for known patternsEssential for optimizations
Logical correctnessLimitedEssential
Architectural decisionsNot applicableEssential
Naming and readabilityGoodComplementary
Test coverageGoodComplementary
Speed< 30 seconds15-60 minutes
ConsistencyAlways the sameVariable
Availability24/7Working hours

Configuring Automatic Review

Configuring automatic review is done at the repository or organization level. There are different activation strategies, from reviewing all PRs to selective review based on branches or paths.

Automatic Review for All PRs

The simplest configuration activates Copilot review on every Pull Request opened in the repository. This mode is ideal for teams that want an automatic first level of control on all code.

Configuration - Global automatic review
# In the repository Settings page:
# 1. Go to Settings > Code review > Copilot
# 2. Select "Automatic" under "Copilot code review"
# 3. Choose the trigger:
#    - "All pull requests" - automatic review on every PR
#    - "When requested" - only when manually requested

# To enable via GitHub API:
# PATCH /repos/{{ '{' }}owner}/{{ '{' }}repo}
# {{ '{' }}
#   "copilot_code_review": {{ '{' }}
#     "automatic": true,
#     "trigger": "all_pull_requests"
#   }
# }

# At the organization level (for all repositories):
# Organization Settings > Copilot > Policies > Code Review
# Enable: "Automatic code review for all repositories"

Selective Review: Branches and Paths

In large projects, you may want to activate automatic review only for certain situations: PRs targeting the main branch, changes to critical paths, or contributions from specific teams.

Configuration - Selective review with GitHub Actions
# .github/workflows/copilot-review.yml
name: Request Copilot Code Review

on:
  pull_request:
    types: [opened, synchronize]
    branches:
      - main
      - release/*
    paths:
      - 'src/**'
      - 'lib/**'
      - '!src/**/*.test.ts'
      - '!src/**/*.spec.ts'
      - '!docs/**'

jobs:
  request-review:
    runs-on: ubuntu-latest
    steps:
      - name: Request Copilot Review
        uses: actions/github-script@v7
        with:
          script: |
            // Request review only if the PR has more than 10 modified lines
            const {{ '{' }} data: files } = await github.rest.pulls.listFiles({{ '{' }}
              owner: context.repo.owner,
              repo: context.repo.repo,
              pull_number: context.payload.pull_request.number
            });

            const totalChanges = files.reduce((sum, f) =>
              sum + f.additions + f.deletions, 0);

            if (totalChanges > 10) {{ '{' }}
              await github.rest.pulls.requestReviewers({{ '{' }}
                owner: context.repo.owner,
                repo: context.repo.repo,
                pull_number: context.payload.pull_request.number,
                reviewers: ['copilot']  // Request review from Copilot
              });
              console.log(`Requested Copilot review for PR #${{ '{' }}context.payload.pull_request.number}`);
            } else {{ '{' }}
              console.log(`Skipped: only ${{ '{' }}totalChanges} lines changed`);
            }

Support for Draft PRs

Copilot can also analyze Draft Pull Requests, allowing you to receive early feedback before the PR is ready for human review. This accelerates the feedback cycle and reduces the number of iterations needed.

Strategies for Draft PRs

StrategyWhen to Use ItAdvantage
Early review PR in early development stage Identify structural problems before completing the work
Iterative review Complex PR with many changes Receive feedback on each push, correct incrementally
Pre-review Before requesting human review Resolve mechanical issues before human review

How the Review Works

When Copilot analyzes a Pull Request, it performs a series of in-depth checks on the modified code. The process is designed to be fast (less than 30 seconds) while covering a broad spectrum of potential issues.

Analysis Process

  1. Context gathering: Copilot reads the PR diff, context files (copilot-instructions.md), and the project structure
  2. Category analysis: Each change is analyzed across different problem categories (bugs, security, performance, style)
  3. Comment generation: For each issue found, Copilot generates an inline comment with a problem description and suggested fix
  4. Code suggestion: When possible, a replacement code block is provided with the "Implement suggestion" button
  5. Summary: A general comment summarizes the main findings and the risk level

Review Categories

Copilot analyzes the code through different lenses, each focused on a specific aspect of software quality.

Code Review Analysis Categories

CategoryWhat It VerifiesIssue ExamplesSeverity
Bugs and Correctness Logic errors, null reference, off-by-one, race condition Array index out of bounds, missing null handling Critical
Security Common vulnerabilities: injection, XSS, CSRF, auth bypass Concatenated SQL, unsanitized input, secrets in code Critical
Performance N+1 queries, inefficient loops, memory leaks, missing indexes SELECT * in loop, non-memoized array, unremoved event listener High
Best Practices Violated patterns, anti-patterns, non-idiomatic code Callback hell, God class, Single Responsibility violation Medium
Code Quality Naming, complexity, duplication, readability Variables with generic names, functions too long, duplicate code Medium
Documentation Missing comments, outdated docs, incomplete JSDoc Public function without JSDoc, outdated README Low
Testing Missing coverage, fragile tests, excessive mocking New function without test, test that verifies implementation Medium

The "Implement Suggestion" Button

One of the most powerful features of Copilot's review is the "Implement suggestion" button. When Copilot identifies a problem and proposes a fix, the button allows you to apply the change with a single click, automatically creating a commit on the PR.

Suggestion Workflow

  1. Copilot identifies a problem in the code
  2. Generates an inline comment with the problem description
  3. Proposes a replacement code block
  4. The PR author can click "Implement suggestion"
  5. GitHub automatically creates a commit with the fix
  6. The PR is updated with the change
  7. If continuous review is enabled, Copilot re-evaluates the code

Continuous Review

When you enable continuous review, Copilot automatically analyzes every new push to the PR. This means that every time the author adds commits to respond to review comments or to continue development, Copilot re-evaluates the changes and provides new feedback.

Advantages of Continuous Review

  • Immediate feedback on every push
  • Verifies that fixes actually resolve the problems
  • Detects new problems introduced during corrections
  • Reduces the human review time required
  • Keeps the PR always "review-ready"

Configuration

  • Activation: Settings > Copilot > Continuous Review
  • Trigger: every push (default) or only significant pushes
  • Throttling: max 1 review every 5 minutes per PR
  • Scope: only files modified since the last review
  • Notifications: summary comment for each cycle

Custom Review Instructions

One of the most important features is the ability to customize review rules to align them with the specific standards of the team and the organization. Custom review instructions allow you to define what Copilot should look for and how it should evaluate the code.

Configuring the Instructions

Custom instructions are defined in a configuration file in the repository. Copilot reads them before each review and uses them as a guide for the analysis.

.github/copilot-review-instructions.md - Complete example
# Copilot Code Review Instructions

## Team Code Standards

### TypeScript
- Use `strict: true` in tsconfig.json
- Never use `any`: prefer `unknown` with type guard
- Prefer `interface` over `type` for objects
- Use `readonly` for properties that must not change
- Always enumerate cases in switch on union type
- Use optional chaining (`?.`) instead of manual null checks
- Prefer `const` over `let`, never `var`

### Naming Conventions
- Classes and interfaces: PascalCase (e.g. `UserService`, `IUserRepository`)
- Variables and functions: camelCase (e.g. `getUserById`, `isActive`)
- Constants: UPPER_SNAKE_CASE (e.g. `MAX_RETRY_COUNT`)
- Files: kebab-case (e.g. `user-service.ts`)
- Tests: [name].test.ts or [name].spec.ts
- Booleans: prefix is/has/should (e.g. `isActive`, `hasPermission`)

### Error Handling
- Use custom error classes (AppError, NotFoundError, etc.)
- Do not catch errors without re-throwing or logging them
- Include context in the error: `throw new NotFoundError('User', userId)`
- Do not use try/catch for flow control
- All API endpoints must have an error handler

### Security (HIGH PRIORITY)
- Never concatenate user input in SQL queries
- Validate ALL inputs with class-validator
- Sanitize HTML output to prevent XSS
- Verify authorization for every protected endpoint
- Do not expose stack traces or internal details in API responses
- Rate limiting on public endpoints
- Secrets only via environment variables

### Performance
- Avoid N+1 queries: use include/eager loading
- Mandatory pagination for lists: max 100 items
- Caching for frequently accessed data
- Async/await for I/O operations
- Avoid blocking synchronous operations

### Tests
- Every new public function must have at least one test
- Tests must be independent (no execution order)
- Mock only external dependencies (database, API, file system)
- Descriptive names: "should [action] when [condition]"
- At least one test for the error case

### Angular (Frontend)
- Use standalone components
- Signals for state management
- OnPush change detection for all components
- Lazy loading for non-critical routes
- No `subscribe()` in templates: use async pipe or toSignal

Language-Specific Rules

Instructions can be specified per language, allowing you to have different standards for backend and frontend, or for different languages in the same project.

Language-specific instructions
# Language-specific rules

## Python (ML Backend)
- Type hints mandatory for all parameters and return
- Google style docstring for every public function
- Use `dataclasses` or `pydantic` for data objects
- Black formatting (line length 88)
- Imports sorted with isort

## SQL (Migrations)
- Never DROP TABLE without a documented backup plan
- ALTER TABLE must be reversible
- Index for every foreign key
- Column names in snake_case
- SQL comment for each migration explaining the "why"

## YAML/Config
- Comments for every non-obvious section
- Secrets referenced via variables, never hardcoded values
- Schema validation for configuration files

Architectural Patterns to Verify

Instructions for architectural patterns
# Architectural Patterns

## Layered Architecture
The project follows a layered architecture:
- Controller → Service → Repository
- Controllers MUST NOT access repositories directly
- Repositories MUST NOT contain business logic
- Each layer communicates only with the layer immediately below

## Dependency Injection
- All dependencies injected via constructor
- Interfaces for dependencies (IUserService, IUserRepository)
- No manual singleton pattern: use the DI container

## Event-Driven Communication
- Cross-service communication via events
- Events must be immutable
- Each event has a unique type and a typed payload
- Event handlers must be idempotent

## VERIFY:
- If a controller calls a repository directly: ERROR
- If a service instantiates a dependency directly: WARNING
- If a SQL query appears outside a repository: ERROR
- If business logic appears in a controller: WARNING

Practical Review Examples

To better understand how Copilot analyzes code, let us look at some concrete examples of problems that automatic review identifies and the suggestions it proposes.

Example 1: SQL Injection Vulnerability

Code in the PR - SQL Injection Vulnerability
// File: src/repositories/user.repository.ts
// Line added in the PR:

async findByName(name: string): Promise<User[]> {{ '{' }}
  const query = `SELECT * FROM users WHERE name LIKE '%${{ '{' }}name}%'`;
  return this.db.raw(query);
}

Copilot Comment

Severity: Critical - SQL Injection Vulnerability

The name parameter is interpolated directly into the SQL query without sanitization. An attacker could inject arbitrary SQL code.

Suggestion: Use parameterized queries to prevent SQL injection.

Fix suggested by Copilot
async findByName(name: string): Promise<User[]> {{ '{' }}
  return this.db.query(
    'SELECT * FROM users WHERE name LIKE $1',
    [`%${{ '{' }}name}%`]
  );
}

Example 2: Performance - N+1 Query

Code in the PR - N+1 Query
// File: src/services/order.service.ts

async getOrdersWithDetails(userId: string): Promise<OrderDetail[]> {{ '{' }}
  const orders = await this.orderRepo.findByUserId(userId);

  const result = [];
  for (const order of orders) {{ '{' }}
    const items = await this.itemRepo.findByOrderId(order.id);
    const customer = await this.customerRepo.findById(order.customerId);
    result.push({{ '{' }} ...order, items, customer });
  }

  return result;
}

Copilot Comment

Severity: High - N+1 Query Pattern

This code executes 2N+1 database queries (1 for orders + N for items + N for customers). With 100 orders, that means 201 database queries. This will significantly degrade performance as data grows.

Suggestion: Use eager loading or batch queries to reduce to 3 total queries.

Fix suggested by Copilot
async getOrdersWithDetails(userId: string): Promise<OrderDetail[]> {{ '{' }}
  const orders = await this.orderRepo.findByUserId(userId);

  if (orders.length === 0) return [];

  const orderIds = orders.map(o => o.id);
  const customerIds = [...new Set(orders.map(o => o.customerId))];

  // Batch query: 3 total queries instead of 2N+1
  const [allItems, allCustomers] = await Promise.all([
    this.itemRepo.findByOrderIds(orderIds),
    this.customerRepo.findByIds(customerIds)
  ]);

  const itemsByOrder = new Map();
  for (const item of allItems) {{ '{' }}
    if (!itemsByOrder.has(item.orderId)) {{ '{' }}
      itemsByOrder.set(item.orderId, []);
    }
    itemsByOrder.get(item.orderId).push(item);
  }

  const customersById = new Map(
    allCustomers.map(c => [c.id, c])
  );

  return orders.map(order => ({{ '{' }}
    ...order,
    items: itemsByOrder.get(order.id) || [],
    customer: customersById.get(order.customerId)
  }));
}

Example 3: Best Practice - Error Handling

Code in the PR - Inadequate error handling
// File: src/controllers/payment.controller.ts

async processPayment(req: Request, res: Response) {{ '{' }}
  try {{ '{' }}
    const result = await this.paymentService.charge(
      req.body.amount,
      req.body.cardToken
    );
    res.json(result);
  } catch (e) {{ '{' }}
    console.log(e);
    res.status(500).json({{ '{' }} error: 'Something went wrong' });
  }
}

Copilot Comment

Severity: Medium - Multiple Issues

  1. Unvalidated input: req.body.amount and req.body.cardToken are not validated. Malformed input could cause errors in the payment service.
  2. Error swallowing: console.log is not structured logging. In production this message could be lost.
  3. Generic error: All errors return 500, even when the error is invalid input (400) or a declined payment (402).
  4. Internal details exposed: The original error is logged but the response message is too generic to be useful to the client.
Fix suggested by Copilot
async processPayment(req: Request, res: Response) {{ '{' }}
  // Input validation
  const {{ '{' }} amount, cardToken } = req.body;

  if (!amount || typeof amount !== 'number' || amount <= 0) {{ '{' }}
    return res.status(400).json({{ '{' }}
      error: 'Invalid amount',
      detail: 'Amount must be a positive number'
    });
  }

  if (!cardToken || typeof cardToken !== 'string') {{ '{' }}
    return res.status(400).json({{ '{' }}
      error: 'Invalid card token',
      detail: 'Card token is required'
    });
  }

  try {{ '{' }}
    const result = await this.paymentService.charge(amount, cardToken);
    res.json(result);
  } catch (error) {{ '{' }}
    logger.error('Payment processing failed', {{ '{' }}
      amount,
      error: error.message,
      stack: error.stack,
      requestId: req.id
    });

    if (error instanceof PaymentDeclinedError) {{ '{' }}
      return res.status(402).json({{ '{' }}
        error: 'Payment declined',
        detail: error.declineReason
      });
    }

    if (error instanceof ValidationError) {{ '{' }}
      return res.status(400).json({{ '{' }}
        error: 'Validation error',
        detail: error.message
      });
    }

    res.status(500).json({{ '{' }}
      error: 'Internal server error',
      requestId: req.id  // For debugging without exposing details
    });
  }
}

Available Plans

Copilot's automatic code review is not available on all plans. Here is an overview of the features available for each plan.

Availability by Plan

FeatureIndividualBusinessEnterprise
On-demand review Not available Available Available
Automatic review Not available Available Available
Continuous review Not available Available Available
Custom review instructions Not available Available Available
Organization policies Not applicable Basic Advanced
Audit log Not available Basic Complete
Review metrics Not available Basic Advanced with dashboard
Codebase fine-tuning Not available Not available Available

Integration with the Existing PR Workflow

Copilot's review integrates naturally into the team's existing PR workflow. Here is how to configure a review process that combines AI and human effectively.

Recommended Workflow

Integrated Review Process

  1. PR Opened: The developer opens the PR with description and context
  2. AI Review (30 sec): Copilot automatically analyzes and leaves comments
  3. Quick Fixes: The author applies mechanical suggestions with "Implement suggestion"
  4. Updated AI Review: Copilot re-evaluates after fixes (if continuous review is enabled)
  5. Human Review: The human reviewer focuses on architecture, logic, and design
  6. Iteration: Any changes requested by the human reviewer
  7. Approval and Merge: PR approved by at least one human reviewer
Example - Branch protection rules with Copilot review
# Recommended Branch Protection Rules to integrate Copilot

# Settings > Branches > Branch protection rules > main

# Mandatory rules:
# 1. Require pull request reviews: 1 reviewer minimum
# 2. Require review from Code Owners: enabled
# 3. Dismiss stale reviews: enabled (when new pushes invalidate reviews)
# 4. Require status checks: enabled
#    - Required checks:
#      - ci/build (CI pipeline)
#      - ci/test (test suite)
#      - security/codeql (static analysis)
# 5. Require Copilot code review: enabled (optional)
#
# Note: Copilot review can be required as a mandatory check,
# but it is recommended NOT to make it blocking
# to avoid false positives that slow down merging.
#
# Recommended strategy:
# - Copilot review: mandatory but not blocking
# - Human reviewer: mandatory and blocking
# - CI/CD checks: mandatory and blocking

Combining AI and Human Review

Responsibilities in the Review Process

WhoWhat to VerifyWhen
Copilot (Automatic) Common bugs, vulnerabilities, style, anti-patterns, performance patterns Immediately when the PR is opened
CI/CD Pipeline Build, tests, linting, coverage, security scan In parallel with the AI review
Code Owner Architecture, design, domain correctness, impact on other modules After AI review and CI are green
Tech Lead Architectural decisions, trade-offs, alignment with roadmap Only for PRs with architectural impact
Security Team Complex vulnerabilities, compliance, data handling Only for PRs that touch auth, payment, PII

Metrics and Reporting

Measuring the impact of automatic review is essential to justify the investment and optimize the process. GitHub provides dedicated metrics to evaluate the effectiveness of Copilot's review.

Key Metrics

MetricWhat It MeasuresIdeal TargetHow to Improve It
Average time to first review From PR opening to first comment < 5 minutes Enable automatic review
Accepted suggestions % of Copilot suggestions applied 40-60% Improve custom instructions
Review cycles Number of iterations before merge < 3 Mechanical fixes before human review
Time to merge From PR opening to merge < 24 hours Reduce wait with AI review + clear process
Post-review bugs in production Bugs found after merge < 2% Analyze escaped bugs and update instructions
False positives Suggestions ignored because they were incorrect < 20% Refine custom instructions and context

Review Dashboard

For Enterprise teams, GitHub offers a dedicated dashboard that aggregates review metrics across the entire team and organization. This dashboard allows you to identify trends, areas for improvement, and the overall impact of AI on code quality.

Team Metrics

  • Average review time per repository
  • Suggestion distribution by category
  • Top issues found by AI review
  • Weekly trend of review cycles
  • Before/after Copilot comparison

Individual Metrics

  • Suggestions accepted per developer
  • Recurring issues per developer
  • Response time to comments
  • Reduction in iterations over time
  • Suggested areas for improvement

Best Practices to Maximize Quality

To get the most out of automatic review, it is important to follow some best practices that improve the quality of feedback and reduce false positives.

Operational Best Practices

PracticeWhyHow
Keep instructions up to date Outdated instructions generate false positives Quarterly review of the copilot-review-instructions.md file
Small and focused PRs Copilot analyzes small, coherent diffs better Max 400 lines per PR, one concept per PR
Detailed PR description Context improves analysis quality PR template with "what" and "why" sections
Apply mechanical fixes right away Frees the human reviewer for important issues Use "Implement suggestion" before requesting human review
Feedback loop Copilot improves with more precise instructions When a suggestion is wrong, update the instructions
Do not ignore warnings Today's warnings are tomorrow's bugs Fix or document why the warning is a false positive

Mistakes to Avoid

  • Making AI review blocking without refined instructions
  • Systematically ignoring suggestions
  • Not customizing instructions for the project
  • Relying solely on AI review without human review
  • Huge PRs that confuse the analysis
  • Not providing context in the PR description

Winning Strategies

  • AI for the first pass, human for the second
  • Specific instructions for each area of the codebase
  • PR templates that guide both the author and the AI
  • Retrospectives on ignored suggestions
  • Clear escalation for security issues
  • Weekly metrics to track improvement

Summary and Next Steps

Automatic code review with Copilot transforms a traditionally slow and inconsistent process into a fast, comprehensive, and always-available first level of analysis. It does not replace human review, but makes it more efficient by allowing reviewers to focus on aspects that require human judgment.

Key Takeaways

  1. Speed: Review in less than 30 seconds, immediate feedback on every push.
  2. Consistency: Same standards applied to all PRs, 24/7, without review fatigue.
  3. Customization: Custom instructions align the review to team standards.
  4. Integration: Fits naturally into the existing PR workflow, complementing human review.
  5. Measurability: Concrete metrics to evaluate and improve the review process.

Series Progress

#ArticleStatus
1Foundation and MindsetCompleted
2Ideation and RequirementsCompleted
3Backend ArchitectureCompleted
4Frontend StructureCompleted
5Prompt EngineeringCompleted
6Testing and QualityCompleted
7DocumentationCompleted
8Deploy and DevOpsCompleted
9EvolutionCompleted
10Coding AgentCompleted
11Code ReviewCompleted
12Copilot Edits and Agent ModeNext
13GitHub SparkComing soon
14Copilot Spaces and MemoryComing soon
15AI ModelsComing soon
16CustomizationComing soon
17Enterprise and BusinessComing soon
18Extensions and MarketplaceComing soon
19SecurityComing soon

In the next article we will explore Copilot Edits and Agent Mode, discovering how to use multi-file editing, the agent mode with auto-healing, Plan Mode for complex tasks, and Next Edit Suggestions for fluid and productive editing.

Try These Tools

Free developer tools related to this topic.

Commenti

Caricamento commenti...

Sign in to comment

Discuss this article in the community

Join the Telegram group to discuss with other developers, ask questions and share your experiences.

Did you like this article?

Explore other content on the blog or discover my projects