Introduction

In today’s fast-paced software development landscape, maintaining high code quality is essential for delivering reliable applications. Lint checking plays a critical role in this process by identifying potential errors and inconsistencies before they become problems. In this guide, we will explore lint checking, its importance, and how to implement it using Docker, PHP 8, and PHP CodeSniffer alongside GitHub pre-commit hooks. By the end, you’ll learn how to seamlessly integrate these tools into your workflow to improve code quality and maintainability.

Understanding Lint Checking

Lint checking involves analyzing code to detect potential errors, stylistic inconsistencies, and deviations from defined coding standards. By integrating lint checks into your workflow, you can catch issues early, reduce bugs, and ensure that your code remains maintainable and readable.

Why is Lint Checking Important?

One of the critical functions of lint checking is to ensure that fatal errors never make their way to remote branches. Careless mistakes, such as syntax errors, should not be tolerated in any production-ready code. Linting acts as a safeguard, catching these errors at the local level, thereby preventing them from disrupting the collaborative efforts of the development team.

The importance of lint checking can be summarized in three key areas:

  1. Enhancing Code Quality: Regular lint checks help catch errors early, reducing the likelihood of bugs slipping into production.
  2. Enforcing Coding Standards: Consistent code style is essential for team collaboration. Linting helps ensure everyone adheres to the same coding standards.
  3. Facilitating Onboarding: New developers can quickly understand existing codebases that follow consistent style guidelines, making onboarding smoother.

Moreover, unresolved conflicts, typically indicated by markers like <<<< ===== >>>>>, must also be addressed before code is pushed to remote repositories. Lint checking enforces discipline, ensuring that such issues are resolved locally, maintaining the integrity of the shared codebase.

Setting up your environment

Before we dive in, ensure you have the following tools installed:

  1. Docker: A platform for developing, shipping, and running applications in containers.
  2. PHP Linter: A tool to analyze PHP code for syntax errors and coding standards.
  3. GitHub Hooks (pre-commit): A Git feature that allows you to run scripts automatically before committing code.
Step 1: Setting Up Your Project

We will follow a basic directory structure that contains the following files and folder:

  • app folder: This folder contains a Git-initialized project.
  • docker-compose.yml: This file defines the services used by our Docker container.
  • Dockerfile: This file defines the custom services needed for our project.
Step 2: Setting Up Your Docker-Compose File

In this docker-compose.yml file, we will use it to build a PHP 8 image in our example. The file sets up a Docker environment that automatically installs the necessary dependencies and runs PHP CodeSniffer to lint your code. It mounts your project directory into the container and, after building the image, installs dependencies with Composer. The setup ensures that your code is checked against the PSR-12 coding standard. To get started, simply run docker-compose up, and the linting process will automatically apply to your PHP files.

version: '3.8'

services:
  php:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: php-linter
    volumes:
      - ./:/app
    working_dir: /app
    command: >
      bash -c "composer install && phpcs --standard=PSR12 /app"
    networks:
      - linter-network

networks:
  linter-network:
    driver: bridge

services:

  • php: Defines the PHP service that builds the Docker image from the provided Dockerfile.
  • volumes: Mounts the current directory (./) to /app in the container so that the code inside your local directory is accessible inside the container.
  • command: Installs dependencies using composer install and runs PHP CodeSniffer using the PSR-12 coding standard on the /app directory.
  • networks: Uses a custom bridge network to isolate the container (optional, for organization).
Step 3: Setting Up Your DockerFile

Docker allows you to run applications in isolated environments. To start, create or modify a Dockerfile in your project directory:

# Dockerfile
FROM php:8.0-cli

# Install the dependencies
RUN apt-get update && apt-get install -y \
    git \
    unzip \
    curl

# Install Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

# Add Composer global bin to the PATH
ENV PATH="/root/.composer/vendor/bin:${PATH}"

# Verify PHP CodeSniffer is installed
RUN phpcs --version

# Set the working directory
WORKDIR /app

# Copy your PHP application code to the Docker image
COPY . .
  • Base Image: Uses the official php:8.1-cli Docker image.
  • Install System Dependencies: Installs the necessary tools for PHP and Composer.
  • Install Composer: Installs Composer using an official Composer Docker image.
  • Install PHP CodeSniffer: Installs PHPCS globally using Composer.
  • PATH Update: Adds Composer’s global binary directory to the system’s PATH.
  • Verify Installation: Ensures PHPCS is installed correctly by running phpcs –version.
  • CMD: The container runs PHPCS with the PSR-12 standard by default when started.

Build Your Docker Image

Run the following command to build your Docker image:

docker-compose up --build
Step 4: Setting Up GitHub Pre-commit Hooks

Git hooks allow you to automate tasks during the Git workflow. Here’s how to set up a pre-commit hook to run lint checks:

  • Navigate to a git-initialized project > locate the .git folder > open the hooks folder.

In this example, we will create a straightforward script that filters out errors before they can be committed:

#!/bin/bash

echo "Listing all changed PHP files:"

# Check for PHP syntax errors using phpcs
syntax_error_found=false

for file in $(git diff --cached --name-only --diff-filter=ACMRT | grep "\.php$"); do
    echo "Checking syntax for $file..."
    if ! phpcs --standard=PSR2 "$file" > /dev/null; then
        echo "Syntax errors found in $file. Commit aborted."
        syntax_error_found=true
    fi
done

# Check for code conflicts
if git diff --name-only --diff-filter=U | grep -q '.'; then
    echo "Code conflicts detected. Please resolve them before committing."
    exit 1
fi

# Exit if syntax errors were found
if [ "$syntax_error_found" = true ]; then
    exit 1
fi

# pre-commit hook
echo "Pre-commit hook executed successfully."
exit 0
  • Syntax Check with phpcs:
    • The script iterates over all staged PHP files and runs phpcs on each one.
    • If phpcs finds syntax errors, it sets a flag (syntax_error_found) to true and prints an error message.
  • Conflict Check:
    • Before allowing a commit, the script checks for any unmerged files using git diff –name-only –diff-filter=U. If any are found, it aborts the commit and prompts the user to resolve conflicts.
  • Exit Status:
    • The script checks the syntax_error_found flag before allowing the commit to proceed, exiting with a non-zero status if errors were found.

2. Lastly, ensure that the pre-commit script works by making it an executable file.

chmod +x .git/hooks/pre-commit
Step 5: Testing the Setup
  1. Make a change in your PHP files that violates the PSR-12 standard.
  2. Try to commit the changes:
git add .
git commit -m "Testing lint check"

Conclusion

Lint checking is an essential practice that not only enhances code quality but also streamlines collaboration among developers. By implementing linting in your projects, you can catch errors early, enforce coding standards, and create a more maintainable codebase. Start incorporating lint checking today and witness the positive impact on your development process!