Code Review & Collaboration in GitLab
This chapter explores the core principles and practical workflows of code review and collaboration within GitLab. You will learn how to transition from naive code changes to secure, peer-reviewed production deployments using GitLab's collaboration suite—including inline comments, structured discussion threads, interactive code suggestions, and draft merge requests.
1. The Paradigm of Modern Code Review
In high-performing DevOps teams, code review is not merely a gatekeeping step or a superficial syntax check. It is a collaborative process designed to improve software quality, security, and team cohesion before code is merged into a stable branch.
Why Do We Need Code Review?
Historically, teams relied heavily on the testing phase to catch defects. In modern DevOps practices, the code review phase acts as the primary defense mechanism. Catching bugs, architectural flaws, and security vulnerabilities during code review is significantly cheaper and faster than resolving them after they reach staging or production environments.
Code review serves four primary purposes:
- Preventing Bugs: Identifying logical errors, edge cases, and performance bottlenecks before they are compiled or interpreted.
- Knowledge Sharing: Disseminating domain knowledge and coding techniques across team members. It ensures that more than one person understands every piece of the codebase.
- Maintaining Coding Standards: Ensuring consistency in style, formatting, naming conventions, and architectural patterns across the entire repository.
- Catching Security Issues: Detecting hardcoded credentials, insecure dependencies, and injection vulnerabilities before they are exposed.
2. Inline Comments: Eliminating Ambiguity
When reviewing code, general feedback such as "This file has issues" or "Your security is weak" is unhelpful and slows down development. Modern collaboration tools solve this through inline comments.
The Core Concept of Inline Comments
Inline comments allow reviewers to attach feedback directly to a specific line or block of code within a merge request diff. This provides immediate context to the developer.
Naive vs. Better Feedback Approach
Benefits of Inline Comments
- Removes Ambiguity: Pinpoints the exact location of the concern.
- Speeds Up Fixes: The developer does not waste time searching for the context of the feedback.
- Precise Reviews: Keeps the conversation focused on granular, actionable code changes.
3. Structured Collaboration: Discussions and Threads
As multiple developers review a Merge Request (MR), conversations can quickly become chaotic if they are not properly structured. GitLab organizes these conversations into Discussions and Threads.
Discussions vs. Threads
- Discussion: A high-level conversation or comment stream attached to a merge request, commit, or file.
- Thread: A nested, structured conversation branch originating from a single inline comment. It groups all subsequent replies together.
Real-Life Analogy: Structured Messaging
Think of a busy chat channel (like Slack or Discord). If everyone posts in the main channel about five different topics, the conversation becomes unreadable. However, if a user posts a question and everyone else replies directly within a thread attached to that question, the main channel remains clean, and the context of that specific conversation is preserved.
Thread Resolution Workflow
A thread represents an open issue or question that must be resolved before the code is deemed safe to merge. The lifecycle of a thread follows a strict progression:
Rule of Thumb: A thread should only be marked as Resolved when either:
- The code has been successfully updated and verified.
- All participating team members reach a consensus that no change is required.
4. The Power of GitLab Suggestions
One of GitLab's most powerful collaborative features is the Suggestions engine. Instead of writing a comment explaining how to change a line of code, a reviewer can write the exact code replacement directly inside the comment.
The Suggestion Mechanism
Using a special Markdown syntax, reviewers can propose a code diff. The developer can then apply this change directly to the branch with a single click, automatically generating a commit without leaving the GitLab web interface.
Code Evolution: Naive vs. Decoupled Production Code
Consider a scenario where a developer hardcodes a sensitive API password.
Naive Code (Insecure)
# app.py
password = "super_secret_production_password_99"
print(password)
The Reviewer's Suggestion
The reviewer highlights the line and inserts a suggestion block:
```suggestion:-0+0
password = os.getenv("DB_PASSWORD")
#### Decoupled Production Code (Secure)
Once the suggestion is accepted, the code evolves to:
```python
# app.py
import os
password = os.getenv("DB_PASSWORD")
print(password)
Why this is better: The sensitive credential is no longer committed to version control. Instead, it is fetched dynamically from the environment at runtime. This approach is highly secure and aligns with industry best practices for containerized deployments (Docker, Kubernetes) and CI/CD pipelines.
Why Suggestions are a Game Changer
- Acts as Asynchronous Pair Programming: One developer writes the baseline code, and the reviewer refines it in real-time by injecting direct improvements.
- Reduces Back-and-Forth: Eliminates long discussion cycles explaining syntax or logic changes.
- One-Click Commits: Developers can accept, apply, and commit the change instantly.
5. Draft Merge Requests: Preventing Premature Reviews
In a continuous integration environment, developers often want to open a Merge Request early in the development cycle to run automated tests, share progress, or get early feedback. However, they may not want team members to spend time performing a formal review yet.
GitLab addresses this with Draft Merge Requests (formerly known as "WIP" or Work In Progress).
Key Use Cases for Draft MRs
- Unfinished Features: The developer is still writing the core logic but wants to back up their branch and trigger early CI pipeline checks.
- Dependency Blocks: The code is complete, but it cannot be merged until another team deploys a dependent service or database schema.
- Active Testing: The developer is actively experimenting with configurations and wants to prevent accidental merges.
6. Hands-On Lab Setup: Repository and SSH Configuration
This section guides you through setting up a repository, configuring SSH access on an Ubuntu instance, and preparing your local environment for the code review workflow.
Step 1: Create a New Project in GitLab
- Log in to your GitLab instance.
- Click the + icon in the top navigation bar and select New project/repository.
- Select Create blank project.
- Configure the project details:
- Project name:
day-5-code-review-and-collaboration - Visibility Level:
Public
- Project name:
- Click Create project.
Step 2: Configure SSH Authentication on Ubuntu
To securely clone and push changes to your GitLab repository, set up an SSH key pair.
-
Open your terminal on your Ubuntu machine and generate a new SSH key pair:
BASHssh-keygen -t ed25519 -C "your_email@example.com"(Press Enter to accept the default file location and bypass the passphrase option if desired).
-
Print and copy your public SSH key:
BASHcat ~/.ssh/id_ed25519.pub -
Add the key to GitLab:
- Click on your profile avatar in the bottom-left corner and select Preferences.
- Navigate to SSH Keys in the left sidebar.
- Click Add new key.
- Paste your public key into the Key text area.
- Click Add key.
Step 3: Clone the Repository
Go back to your project homepage, copy the SSH clone URL, and run the following commands in your terminal:
# Clone the repository
git clone git@gitlab.com:your-username/day-5-code-review-and-collaboration.git
# Navigate into the project directory
cd day-5-code-review-and-collaboration
7. Simulating the Naive/Insecure Code Implementation
To understand the code review process, we will first establish a baseline file on the main branch, create a feature branch, and commit insecure code to it.
Step 1: Create the Base File on main
Create a simple Python file on the default main branch and push it to GitLab.
# Create the app.py file with a basic print statement
echo 'print("Hello World")' > app.py
# Stage the file
git add app.py
# Commit the changes
git commit -m "Initial commit: Add base app.py"
# Push to the main branch
git push origin main
Step 2: Create a Feature Branch
Create and switch to a new branch dedicated to implementing a new feature.
git checkout -b feature-review-demo
Step 3: Introduce Insecure Code
Modify app.py to simulate a common developer mistake: hardcoding a sensitive credential.
# Overwrite app.py with insecure code
cat << 'EOF' > app.py
password = "super_secret_production_password_99"
print(password)
EOF
Stage, commit, and push this feature branch to GitLab:
git add app.py
git commit -m "Add password configuration logic"
git push origin feature-review-demo
8. Step-by-Step Code Review Workflow in GitLab
With the insecure code pushed to our feature branch, we will now initiate the code review process using a Draft Merge Request.
Step 1: Create a Draft Merge Request
- Navigate to your GitLab repository in the web browser.
- You should see a prompt saying: You pushed to feature-review-demo... Create merge request. Click it.
- In the Title field, prefix the title with
Draft:(e.g.,Draft: Implement password configuration logic). - Scroll to the bottom and click Create merge request.
Notice that the Merge button is disabled and displays a warning: Merge blocked: merge request is in draft status. This prevents incomplete code from accidentally entering the main branch.
Step 2: Transition the MR to "Ready"
Once you are ready for your team to review the changes:
- Click the Mark as ready button at the top-right of the Merge Request page.
- The
Draft:prefix will be removed from the title, and the merge block will be lifted.
Step 3: Assign a Reviewer
To assign the review task to a team member (or yourself for this simulation):
- Locate the Reviewers section in the right sidebar of the MR.
- Click Edit.
- Select your user account to assign yourself as the reviewer.
9. Applying Inline Comments and Interactive Suggestions
Now, acting as the reviewer, we will inspect the changes, leave an inline comment, and provide interactive suggestions to fix the security issue.
Step 1: Add an Inline Comment
- Click on the Changes tab at the top of the Merge Request page to view the code diff.
- Hover over line 1 of
app.py(password = "super_secret_production_password_99"). - Click the Comment icon (speech bubble) that appears next to the line number.
- In the comment box, type:
TEXT
Hardcoding passwords is insecure. We should use environment variables instead. - Click Add comment now. This action starts a new discussion thread.
Step 2: Inject Interactive Suggestions
Instead of just pointing out the error, let's provide the exact code fix using GitLab's Suggestions feature.
- Click the Edit button on your newly created comment (or start a new comment on line 1).
- In the comment markdown toolbar, click the Insert suggestion icon (represented by a small page with a green plus/red minus sign, or write the markdown manually).
- Modify the suggestion block to replace the hardcoded password with an environment variable lookup:
```suggestion:-0+0
password = os.getenv("DB_PASSWORD")
4. Click **Save comment**.
- password = "super_secret_production_password_99"
- password = os.getenv("DB_PASSWORD")
---
### Step 3: Suggesting Dependencies (Importing the `os` Module)
The `os.getenv()` function requires the `os` module to be imported. Let's add another suggestion at the very top of the file to import this dependency.
1. Hover over the empty space above line 1 in the diff view and click the comment icon.
2. Insert a suggestion block to add the import statement:
```markdown
```suggestion:-0+0
import os
3. Click **Add comment now**.
---
### Step 4: Applying the Suggestions (Developer Action)
Now, acting as the developer:
1. Review the suggestions provided by the reviewer.
2. On the first suggestion (importing `os`), click **Apply suggestion**. You can optionally add a custom commit message, such as `Import os module`.
3. On the second suggestion (using `os.getenv`), click **Apply suggestion** with the commit message `Use environment variables for password configuration`.
GitLab automatically applies these changes, commits them directly to your `feature-review-demo` branch, and updates the Merge Request.
---
## 10. Thread Resolution and Merging to Production
Once the suggestions are applied, GitLab automatically detects that the suggested code changes have been implemented and resolves the associated discussion threads.
Thread 1 (Line 1: import os) --------> [Applied] --------> Thread Resolved Automatically Thread 2 (Line 2: os.getenv) --------> [Applied] --------> Thread Resolved Automatically
### Step 1: Verify Thread Resolution
1. Navigate back to the **Overview** tab of your Merge Request.
2. Scroll down to verify that all discussion threads are marked as **Resolved**.
3. If any threads remain open, manually review them and click **Resolve thread** once resolved.
---
### Step 2: Merge the Code
With all security issues resolved and all threads closed, the code is ready for production.
1. Ensure the checkbox **Delete source branch** is checked. This keeps your repository clean by deleting the temporary `feature-review-demo` branch after merging.
2. Click the green **Merge** button.
---
### Step 3: Verify the Production Code
Navigate to the repository file browser on the `main` branch and open `app.py`. The final, secure code is now successfully merged:
```python
import os
password = os.getenv("DB_PASSWORD")
print(password)
11. Summary and Key Takeaways
- Shift-Left Security: Catching security vulnerabilities (like hardcoded credentials) during the code review phase is significantly more efficient than catching them during testing or post-deployment.
- Contextual Feedback: Inline comments eliminate ambiguity by attaching feedback directly to the affected lines of code.
- Structured Discussions: Threads keep conversations organized, ensuring that every identified issue is tracked and resolved before merging.
- Actionable Suggestions: The Suggestions feature acts as asynchronous pair programming, allowing reviewers to write code fixes that developers can commit with a single click.
- Draft Merge Requests: Marking an MR as a draft prevents premature reviews and accidental merges while allowing developers to run early CI/CD pipelines.
- Clean Repository Hygiene: Automatically deleting the source branch after a successful merge prevents branch clutter and keeps the repository organized.