Comprehensive Branch Protection And PR Enforcement Strategy For Shokken-Xin
Introduction
In this article, we'll dive into implementing a comprehensive branch protection and Pull Request (PR) enforcement strategy for the Shokken-Xin repository. This strategic move is designed to enhance code quality, maintain a clean Git history, and pave the way for automated releases. We'll cover everything from GitFlow branch structure to automated branch cleanup, ensuring a robust and efficient development workflow. So, if you're looking to level up your repository management, you're in the right place, guys!
Overview: Enhancing Code Quality and Automation
The primary goal here is to establish a robust framework for managing the Shokken-Xin repository. This involves implementing branch protection rules, enforcing PR title conventions, and automating branch cleanup. By doing so, we aim to improve code quality, maintain a clean Git history, and enable seamless automated releases. This comprehensive approach will not only benefit the current development practices but also ensure the repository is well-prepared for future growth and collaboration. Imagine a codebase that's not just functional but also a joy to navigate and contribute to – that's the vision we're working towards. So, let’s get started and make this repository shine!
Current State: A Solid Foundation
Currently, the Shokken-Xin project operates with a single developer, adhering to professional development practices. There are extensive CI/CD workflows already in place, ensuring a high standard of code quality with a test coverage exceeding 90%. However, there are a few areas we can improve. Notably, a develop
branch is missing, although it's referenced in the CI configurations. Additionally, no branch protection rules are currently configured. These gaps present an opportunity to implement a more structured and secure development process. By addressing these points, we can build upon the existing solid foundation and create an even more robust and efficient workflow. It’s like taking a well-maintained car and adding some performance upgrades – it’s already good, but we can make it great!
Proposed Branch Protection Strategy: A Multi-Faceted Approach
1. GitFlow Branch Structure: Organizing the Chaos
At the heart of our strategy lies the GitFlow branching model. This model provides a structured framework for managing different stages of development, from feature implementation to hotfixes and releases. By adopting GitFlow, we can ensure a clear and organized workflow, making it easier to track changes and manage releases. The key branches in this structure include:
master
(main/production branch): This branch represents the stable, production-ready code.develop
(integration branch): This is where ongoing development and feature integration occur.feature/*
(feature development): These branches are used for developing new features.hotfix/*
(emergency fixes): These branches are dedicated to addressing critical issues in the production code.release/*
(release preparation): These branches are used for preparing releases, including final testing and version updates.
This structured approach not only streamlines the development process but also ensures that each type of change has its designated space, reducing the risk of conflicts and making it easier to manage the codebase. It's like having separate lanes on a highway – everything flows more smoothly and efficiently. So, let’s dive deeper into how we'll protect these crucial branches.
2. Master Branch Protection Rules: Fortifying the Core
The master
branch is the backbone of our project, representing the production-ready code. Protecting this branch is paramount to maintaining stability and preventing accidental disruptions. To achieve this, we'll implement a series of robust protection rules. These rules are designed to ensure that only thoroughly reviewed and tested code makes its way into the master
branch. It’s like building a fortress around our most valuable asset, ensuring it's safe and secure.
Essential Rules:
- ✅ Require pull request reviews: We'll mandate at least one review for every pull request (PR) before it can be merged. Self-reviews are allowed, ensuring a basic level of scrutiny. This adds an extra layer of quality control, as another set of eyes can often catch issues that the original author might have missed. It’s like having a second opinion on a critical decision, ensuring we’re making the right move.
- âś… Require status checks to pass before merging: Before a PR can be merged, it must pass all required status checks. This includes:
- CI - Code Quality & Tests: Ensuring the code meets our quality standards and passes all tests.
- Platform Builds: Verifying that the code builds successfully on all target platforms. This step is crucial for ensuring that the changes not only work in isolation but also integrate seamlessly with the rest of the codebase. It’s like a final exam before graduation, ensuring everything is up to par.
- âś… Require branches to be up to date before merging: This rule ensures that the branch being merged is current with the
master
branch, reducing the risk of conflicts and integration issues. It’s like making sure everyone is on the same page before a big meeting, ensuring a smooth and productive discussion. - ✅ Require conversation resolution before merging: All discussions and issues raised in the PR must be resolved before merging. This ensures that all concerns are addressed and that the final code is well-vetted. It’s like clearing the air before moving forward, ensuring everyone is in agreement and on board.
- ✅ Dismiss stale PR approvals when new commits are pushed: If new commits are added to a PR after it has been approved, the approvals are dismissed. This ensures that reviewers have the opportunity to review the latest changes before the PR is merged. It’s like a fresh pair of eyes on the final version, ensuring nothing slips through the cracks.
- ✅ Include administrators in restrictions: This rule can be disabled for emergencies but generally ensures that administrators are also subject to the branch protection rules. This prevents accidental overrides and ensures consistent enforcement of the rules. It’s like leading by example, ensuring everyone follows the same standards.
Security & Quality:
- ✅ Require linear history: This rule prevents merge commits, ensuring a clean and easy-to-follow history. This makes it easier to track changes and understand the evolution of the codebase. It’s like having a clear and concise timeline of events, making it easier to understand the story.
- ✅ Enforce squash merging: Squash merging combines all commits in a PR into a single commit, resulting in a cleaner history. This simplifies the commit history, making it easier to understand and manage. It’s like summarizing a long report into key takeaways, making the information more accessible.
- âś… No force pushes allowed: Force pushing can overwrite history and cause significant issues. This rule prevents force pushes to the
master
branch, safeguarding the integrity of the history. It’s like a safety lock on a delicate mechanism, preventing accidental damage. - ✅ No deletions allowed: This rule prevents accidental deletion of the
master
branch, ensuring its availability. It’s like having a backup key to a critical resource, ensuring it’s always accessible.
Access Control:
- Restrict who can push: We'll restrict direct pushes to the
master
branch, allowing changes only via PRs. This enforces the review process and ensures that all changes are thoroughly vetted. It’s like a controlled entry point to a secure facility, ensuring only authorized personnel can access. - Allow specific actors to bypass: We'll allow GitHub Actions to bypass these rules for automated releases. This enables seamless automation while maintaining overall security. It’s like having an express lane for authorized vehicles, ensuring smooth operations without compromising security.
3. Develop Branch Protection Rules: Safeguarding Integration
The develop
branch is where the magic happens – it's the integration hub for new features and improvements. Protecting this branch is crucial for maintaining a stable development environment. We'll implement a set of rules similar to those for the master
branch, but with a few key differences tailored to the development workflow. Think of it as a well-guarded workshop where ideas are forged and refined.
Essential Rules:
- âś… Require pull request reviews: Similar to the
master
branch, we'll require at least one review for every PR, with self-reviews allowed. This ensures that all changes are reviewed before being integrated into thedevelop
branch. It’s like a peer review process for research papers, ensuring the quality and validity of the work. - ✅ Require status checks: PRs must pass all required status checks before merging:
- CI - Code Quality & Tests: Ensuring the code meets our quality standards and passes all tests.
- All pre-commit hooks (ktlint, detekt, konsist, coverage): Verifying that the code adheres to our coding standards and meets the required coverage thresholds.
These checks act as quality gates, preventing substandard code from entering the
develop
branch. It’s like a series of checkpoints on a production line, ensuring each product meets the required specifications.
- ✅ Require conversation resolution: All discussions and issues raised in the PR must be resolved before merging. This ensures that all concerns are addressed and that the final code is well-vetted. It’s like a collaborative problem-solving session, ensuring everyone is on the same page before moving forward.
- âś… Dismiss stale PR approvals: Similar to the
master
branch, approvals are dismissed when new commits are pushed. This ensures that reviewers have the opportunity to review the latest changes. It’s like a final read-through before publishing a document, ensuring everything is accurate and up-to-date.
Quality Gates:
- âś… Enforce coverage thresholds: We'll enforce specific coverage thresholds to ensure comprehensive testing:
- 90% overall coverage
- 95% for the domain layer
- 90% for the data layer
- 80% for the presentation layer These thresholds provide a quantifiable measure of code quality and ensure that critical areas are thoroughly tested. It’s like setting performance targets for a team, ensuring everyone is working towards the same goals.
- âś… Enforce squash merging: Squash merging is enforced to maintain a clean and linear history, similar to the
master
branch. This simplifies the commit history and makes it easier to track changes. It’s like organizing a messy desk into neat piles, making it easier to find what you need. - ✅ No force pushes: Force pushes are prohibited to prevent accidental overwrites and maintain the integrity of the history. It’s like a safety mechanism on a delicate machine, preventing accidental damage.
- âś… No deletions: Accidental deletion of the
develop
branch is prevented to ensure its availability. It’s like having a backup of an important file, ensuring it’s always accessible.
4. PR Title Enforcement: Standardizing Communication
Consistent and informative PR titles are essential for maintaining a clear and organized commit history. To ensure this, we'll implement PR title enforcement using the amannn/action-semantic-pull-request
GitHub Action. This action validates PR titles against the Conventional Commits format, promoting consistency and clarity. Think of it as a grammar checker for your code contributions, ensuring everything is well-written and easy to understand.
Implementation:
We'll use the amannn/action-semantic-pull-request
GitHub Action to enforce the Conventional Commits format. This action checks PR titles against a predefined set of types, ensuring they adhere to the standard. It’s like having a template for reports, ensuring all reports follow the same structure and format.
Configuration:
The following YAML configuration will be used:
name: "Lint PR"
on:
pull_request_target:
types:
- opened
- edited
- synchronize
permissions:
pull-requests: read
jobs:
main:
name: Validate PR title
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Clean up stale branches
uses: phpdocker-io/github-actions-delete-abandoned-branches@v2
with:
github_token: ${{ github.token }}
last_commit_age_days: 30
ignore_branches: master,main,develop,release/*,hotfix/*
dry_run: false
This configuration defines a GitHub Action that runs on pull requests, validating the PR title against the Conventional Commits format. The action is triggered when a PR is opened, edited, or synchronized. It uses a predefined set of types (e.g., fix
, feat
, docs
) and enforces the format. It’s like setting up a rule for email subject lines, ensuring they are informative and easy to categorize.
Benefits:
- Ensures PR titles follow Conventional Commits format: This promotes consistency and makes it easier to understand the purpose of each PR. It’s like having a common language for describing changes, making it easier for everyone to understand.
- Enables automated changelog generation with Release Please: Conventional Commits format is compatible with Release Please, enabling automated changelog generation. This saves time and effort in creating release notes. It’s like having a tool that automatically generates summaries of changes, making it easier to track progress.
- Maintains consistent commit history: Consistent PR titles contribute to a cleaner and more organized commit history. This makes it easier to track changes and understand the evolution of the codebase. It’s like having a well-organized filing system, making it easier to find what you need.
- Supports breaking changes with
!
notation: The Conventional Commits format allows indicating breaking changes with the!
notation, making them easily identifiable. This helps in managing and communicating breaking changes effectively. It’s like using a warning sign to highlight potential issues, ensuring everyone is aware of the risks.
5. Repository Settings Configuration: Laying the Groundwork
Configuring the repository settings correctly is crucial for enforcing our branch protection strategy. We'll adjust several settings to align with our goals, ensuring a smooth and efficient workflow. Think of it as setting the stage for a performance, ensuring all the elements are in place for a successful show.
Required GitHub Settings:
- Settings → General → Pull Requests:
- âś… Allow squash merging: This is essential for maintaining a clean and linear history.
- âś… Default to PR title for squash merge commits: This ensures that commit messages are consistent and informative.
- âś… Automatically delete head branches: This helps in keeping the repository clean by removing merged branches.
- ❌ Allow merge commits (disabled): We'll disable merge commits to enforce a linear history.
- ❌ Allow rebase merging (disabled): Rebase merging is also disabled to maintain a consistent history.
These settings ensure that our branch protection rules are effectively enforced and that the repository maintains a clean and organized history. It’s like setting the rules of a game before it starts, ensuring fair play and a clear understanding of the objectives.
6. Stale Branch Cleanup Strategy: Keeping Things Tidy
Over time, repositories can accumulate a large number of stale branches, cluttering the codebase and making it harder to navigate. To address this, we'll implement a stale branch cleanup strategy, automating the removal of branches that are no longer needed. Think of it as decluttering your workspace, ensuring you have a clean and efficient environment.
Automated Cleanup Action:
We'll use a GitHub Action to automate the cleanup process. The following YAML configuration defines a workflow that runs weekly, identifying and deleting stale branches:
name: Branch Cleanup
on:
schedule:
- cron: '0 0 * * 0' # Weekly on Sunday
workflow_dispatch:
jobs:
cleanup:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Clean up stale branches
uses: phpdocker-io/github-actions-delete-abandoned-branches@v2
with:
github_token: ${{ github.token }}
last_commit_age_days: 30
ignore_branches: master,main,develop,release/*,hotfix/*
dry_run: false
This workflow is scheduled to run every Sunday, using a cron expression. It uses the phpdocker-io/github-actions-delete-abandoned-branches@v2
action to identify and delete stale branches. The action is configured to ignore protected branches (e.g., master
, develop
) and only delete branches that are older than 30 days. It’s like setting a regular cleaning schedule for your house, ensuring it stays tidy and organized.
Cleanup Criteria:
- 30+ days since last commit
- No open pull requests
- Not a protected branch
- Merged branches deleted immediately (auto-delete)
These criteria ensure that only truly stale branches are removed, preventing accidental deletion of active branches. It’s like having a checklist before throwing something away, ensuring you don’t discard anything valuable.
7. CODEOWNERS Configuration: Defining Responsibilities
The CODEOWNERS
file is a powerful tool for defining code ownership and ensuring that changes are reviewed by the appropriate individuals or teams. We'll create a CODEOWNERS
file to specify ownership for critical paths and ensure proper review requirements. Think of it as creating a seating chart for a meeting, ensuring the right people are in the room to make decisions.
Create .github/CODEOWNERS
:
# Global owner
* @endian-dev
# Domain layer requires careful review
*/domain/ @endian-dev
**/domain/ @endian-dev
# CI/CD workflows
.github/workflows/ @endian-dev
# Build configuration
*.gradle.kts @endian-dev
gradle.properties @endian-dev
This configuration specifies that @endian-dev
is the global owner for the repository, meaning they are responsible for reviewing all changes. It also defines specific ownership for the domain layer, CI/CD workflows, and build configuration files. This ensures that changes to these critical areas are reviewed by the appropriate expert. It’s like assigning roles and responsibilities in a project, ensuring everyone knows their part and who to consult for specific issues.
8. Implementation Plan: A Step-by-Step Guide
To ensure a smooth implementation, we'll follow a step-by-step plan, breaking down the process into manageable tasks. This approach minimizes the risk of errors and ensures that all components are correctly configured. Think of it as a recipe for success, ensuring you follow the instructions carefully to achieve the desired outcome.
-
Create develop branch from master
git checkout master git pull origin master git checkout -b develop git push -u origin develop
This step creates the
develop
branch, which will serve as the integration hub for new features and improvements. It’s like setting up the foundation for a new building, providing a solid base for future construction. -
Configure repository settings
- Enable squash merging only
- Set PR title as the default commit message
- Enable auto-delete head branches
This step configures the repository settings to align with our branch protection strategy. It’s like setting the preferences in a software application, customizing it to your needs.
-
Add PR title validation workflow
- Create
.github/workflows/lint-pr.yml
- Add semantic-pull-request action
This step implements PR title validation, ensuring that all PR titles follow the Conventional Commits format. It’s like adding a quality control step to a manufacturing process, ensuring each product meets the required standards.
- Create
-
Configure branch protection rules
- Apply rules to master and develop
- Enable required status checks
- Configure review requirements
This step applies the branch protection rules to the
master
anddevelop
branches, safeguarding these critical branches. It’s like installing a security system in your house, protecting it from unauthorized access. -
Add stale branch cleanup workflow
- Create
.github/workflows/branch-cleanup.yml
- Test with dry-run first
This step implements the stale branch cleanup strategy, automating the removal of stale branches. It’s like setting up a regular maintenance schedule for your car, ensuring it stays in good condition.
- Create
-
Create CODEOWNERS file
- Define ownership for critical paths
- Ensure proper review requirements
This step creates the
CODEOWNERS
file, defining code ownership and ensuring that changes are reviewed by the appropriate individuals. It’s like assigning roles and responsibilities in a team, ensuring everyone knows their part.
9. GitFlow Workflow with Protected Branches: Putting It All Together
With the branch protection strategy in place, we'll follow the GitFlow workflow for feature development, hotfixes, and releases. This ensures a structured and efficient development process, minimizing the risk of conflicts and errors. Think of it as following a well-defined roadmap, ensuring you reach your destination smoothly and efficiently.
Feature Development:
git checkout -b feature/new-feature develop
# Make changes
git push origin feature/new-feature
# Create PR to develop with title: "feat: add new feature"
This workflow outlines the steps for developing new features, including creating a feature branch, making changes, and creating a PR to the develop
branch. It’s like following a recipe for a new dish, ensuring you follow the instructions carefully to achieve the desired flavor.
Hotfix Workflow:
git checkout -b hotfix/critical-fix master
# Make fix
git push origin hotfix/critical-fix
# Create PR to master with title: "fix: resolve critical issue"
# After merge, cherry-pick to develop
This workflow outlines the steps for addressing critical issues in the production code, including creating a hotfix branch, making the fix, and creating a PR to the master
branch. It’s like performing emergency repairs on a critical system, ensuring it’s back up and running as quickly as possible.
Release Workflow:
git checkout -b release/1.2.0 develop
# Version bumps and final testing
git push origin release/1.2.0
# Create PR to master
# After merge, back-merge to develop
This workflow outlines the steps for preparing releases, including creating a release branch, performing final testing, and creating a PR to the master
branch. It’s like preparing for a product launch, ensuring everything is ready for the big day.
10. Integration with Release Please: Automating Releases
The combination of squash merging, PR titles as commit messages, Conventional Commits format, and Release Please automation enables a seamless release process. This integration automates changelog generation, semantic versioning, release PR creation, and version bumping, saving time and effort. Think of it as having a robot assistant for releases, handling all the tedious tasks automatically.
This powerful combination streamlines the release process, ensuring consistency and accuracy. It’s like having a well-oiled machine for releases, ensuring everything runs smoothly and efficiently.
11. Benefits: The Big Picture
The benefits of implementing this comprehensive branch protection and PR strategy are numerous, impacting various aspects of the development workflow. From code quality to automation and scalability, this strategy lays a solid foundation for future growth and collaboration. Think of it as investing in the future of your project, ensuring it’s well-prepared for success.
- Clean History: Linear, easy-to-follow commit history
- Automated Releases: Changelog and version management
- Code Quality: Enforced through required checks
- Consistency: Standardized commit messages
- Safety: Protected branches prevent accidents
- Scalability: Ready for team growth
12. Solo Developer Considerations: Tailoring the Strategy
Even for solo developers, implementing a robust branch protection strategy is beneficial. While self-review is explicitly allowed and admin bypass is available for emergencies, the automation and consistent workflow enforce best practices and prepare the codebase for future collaboration. Think of it as setting up a well-organized workspace for yourself, ensuring you can work efficiently and effectively.
- Self-review is explicitly allowed
- Admin bypass available for emergencies
- Automation reduces manual overhead
- Consistent workflow enforces best practices
- Prepares codebase for future collaboration
Acceptance Criteria: Measuring Success
To ensure that the implementation is successful, we'll define a set of acceptance criteria. These criteria provide a clear benchmark for measuring progress and verifying that all components are correctly configured. Think of it as setting goals for a project, ensuring everyone is working towards the same objectives.
- [ ] Develop branch created from master
- [ ] Branch protection rules applied to master and develop
- [ ] PR title validation workflow active
- [ ] Repository configured for squash-only merging
- [ ] Stale branch cleanup automation implemented
- [ ] CODEOWNERS file created
- [ ] All CI checks passing with the new configuration
- [ ] Documentation updated to reflect the new workflow
References: Further Reading
For further information and detailed documentation, please refer to the following resources:
- Conventional Commits Specification
- GitHub Branch Protection Documentation
- Release Please Documentation
- amannn/action-semantic-pull-request
Conclusion: A Solid Foundation for the Future
Implementing a comprehensive branch protection and PR enforcement strategy for the Shokken-Xin repository is a significant step towards enhancing code quality, streamlining development workflows, and enabling automated releases. By adopting GitFlow, enforcing PR title conventions, and automating branch cleanup, we create a robust and efficient development environment. This strategy not only benefits the current development practices but also ensures the repository is well-prepared for future growth and collaboration. So, let's get started and build a solid foundation for the future of Shokken-Xin!