|
| 1 | +# CI/CD Integration |
| 2 | + |
| 3 | +GitLint can be integrated into continuous integration workflows to ensure that all commits in your repository adhere to your team's commit message standards. This guide covers how to integrate GitLint with popular CI/CD platforms. |
| 4 | + |
| 5 | +## Why Integrate with CI/CD? |
| 6 | + |
| 7 | +While local Git hooks help developers maintain commit message quality during development, CI/CD integration offers additional benefits: |
| 8 | + |
| 9 | +1. **Catch errors early**: Validate commit messages before code is merged |
| 10 | +2. **Enforce standards**: Ensure all team members follow commit conventions |
| 11 | +3. **Centralized validation**: Apply consistent rules across all branches |
| 12 | +4. **PR validation**: Check commit messages in pull requests |
| 13 | +5. **Branch protection**: Require commit message validation for protected branches |
| 14 | + |
| 15 | +## GitHub Actions |
| 16 | + |
| 17 | +You can easily add GitLint validation to your GitHub Actions workflow: |
| 18 | + |
| 19 | +```yaml |
| 20 | +# .github/workflows/gitlint.yml |
| 21 | +name: Validate Commit Messages |
| 22 | + |
| 23 | +on: |
| 24 | + push: |
| 25 | + branches: [main, dev] |
| 26 | + pull_request: |
| 27 | + branches: [main] |
| 28 | + |
| 29 | +jobs: |
| 30 | + gitlint: |
| 31 | + runs-on: ubuntu-latest |
| 32 | + steps: |
| 33 | + - uses: actions/checkout@v3 |
| 34 | + with: |
| 35 | + fetch-depth: 0 # Fetch all history for all branches and tags |
| 36 | + |
| 37 | + - name: Set up Node.js |
| 38 | + uses: actions/setup-node@v3 |
| 39 | + with: |
| 40 | + node-version: '18' |
| 41 | + cache: npm |
| 42 | + |
| 43 | + - name: Install dependencies |
| 44 | + run: npm install |
| 45 | + |
| 46 | + - name: Validate latest commit message |
| 47 | + run: npx gitlint |
| 48 | + if: github.event_name == 'push' |
| 49 | + |
| 50 | + - name: Validate PR commit messages |
| 51 | + run: git log --pretty=%B ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }} | npx gitlint |
| 52 | + if: github.event_name == 'pull_request' |
| 53 | +``` |
| 54 | +
|
| 55 | +## GitLab CI |
| 56 | +
|
| 57 | +For GitLab CI, add a job to your `.gitlab-ci.yml` file: |
| 58 | + |
| 59 | +```yaml |
| 60 | +# .gitlab-ci.yml |
| 61 | +stages: |
| 62 | + - validate |
| 63 | + - build |
| 64 | + - test |
| 65 | +
|
| 66 | +gitlint: |
| 67 | + stage: validate |
| 68 | + image: node:18-alpine |
| 69 | + script: |
| 70 | + - npm install gitlint |
| 71 | + - | |
| 72 | + if [ "$CI_PIPELINE_SOURCE" == "merge_request_event" ]; then |
| 73 | + # For merge requests, check all commits in the MR |
| 74 | + git fetch origin $CI_MERGE_REQUEST_TARGET_BRANCH_NAME |
| 75 | + git log --pretty=%B FETCH_HEAD..$CI_COMMIT_SHA | npx gitlint |
| 76 | + else |
| 77 | + # For direct commits, check the latest commit |
| 78 | + git log --pretty=%B -n 1 | npx gitlint |
| 79 | + fi |
| 80 | +``` |
| 81 | + |
| 82 | +## CircleCI |
| 83 | + |
| 84 | +Add GitLint validation to your CircleCI configuration: |
| 85 | + |
| 86 | +```yaml |
| 87 | +# .circleci/config.yml |
| 88 | +version: 2.1 |
| 89 | +jobs: |
| 90 | + validate-commits: |
| 91 | + docker: |
| 92 | + - image: cimg/node:18.12 |
| 93 | + steps: |
| 94 | + - checkout |
| 95 | + - run: |
| 96 | + name: Install dependencies |
| 97 | + command: npm install gitlint |
| 98 | + - run: |
| 99 | + name: Validate commit messages |
| 100 | + command: | |
| 101 | + if [[ -n "$CIRCLE_PULL_REQUEST" ]]; then |
| 102 | + # For pull requests |
| 103 | + PR_NUMBER=${CIRCLE_PULL_REQUEST##*/} |
| 104 | + git fetch origin +refs/pull/$PR_NUMBER/merge |
| 105 | + git log --pretty=%B HEAD^..HEAD | npx gitlint |
| 106 | + else |
| 107 | + # For direct commits |
| 108 | + git log --pretty=%B -n 1 | npx gitlint |
| 109 | + fi |
| 110 | +
|
| 111 | +workflows: |
| 112 | + version: 2 |
| 113 | + build-test-deploy: |
| 114 | + jobs: |
| 115 | + - validate-commits |
| 116 | + # Other jobs... |
| 117 | +``` |
| 118 | + |
| 119 | +## Azure DevOps Pipelines |
| 120 | + |
| 121 | +For Azure DevOps, add a validation task to your pipeline: |
| 122 | + |
| 123 | +```yaml |
| 124 | +# azure-pipelines.yml |
| 125 | +trigger: |
| 126 | + - main |
| 127 | + - dev |
| 128 | +
|
| 129 | +pool: |
| 130 | + vmImage: ubuntu-latest |
| 131 | +
|
| 132 | +steps: |
| 133 | + - task: NodeTool@0 |
| 134 | + inputs: |
| 135 | + versionSpec: 18.x |
| 136 | + displayName: Install Node.js |
| 137 | +
|
| 138 | + - script: npm install gitlint |
| 139 | + displayName: Install dependencies |
| 140 | +
|
| 141 | + - script: | |
| 142 | + if [ -n "$(System.PullRequest.SourceBranch)" ]; then |
| 143 | + # For pull requests |
| 144 | + git fetch origin $(System.PullRequest.TargetBranch) |
| 145 | + git log --pretty=%B origin/$(System.PullRequest.TargetBranch)..HEAD | npx gitlint |
| 146 | + else |
| 147 | + # For direct commits |
| 148 | + git log --pretty=%B -n 1 | npx gitlint |
| 149 | + fi |
| 150 | + displayName: Validate commit messages |
| 151 | +``` |
| 152 | + |
| 153 | +## Customizing CI Validation |
| 154 | + |
| 155 | +For more advanced CI validation scenarios, you can create a custom script: |
| 156 | + |
| 157 | +```js |
| 158 | +// scripts/validate-commits.js |
| 159 | +const { execSync } = require('node:child_process') |
| 160 | +const { lintCommitMessage } = require('gitlint') |
| 161 | +
|
| 162 | +// Determine which commits to check based on CI environment |
| 163 | +function getCommitsToCheck() { |
| 164 | + if (process.env.GITHUB_EVENT_NAME === 'pull_request') { |
| 165 | + const base = process.env.GITHUB_BASE_REF |
| 166 | + const head = process.env.GITHUB_HEAD_REF |
| 167 | + return execSync(`git log --pretty=%B origin/${base}..origin/${head}`).toString() |
| 168 | + } |
| 169 | + else { |
| 170 | + // Default to checking the latest commit |
| 171 | + return execSync('git log --pretty=%B -n 1').toString() |
| 172 | + } |
| 173 | +} |
| 174 | + |
| 175 | +// Get and validate commits |
| 176 | +const commits = getCommitsToCheck().split('\n\ncommit ').filter(Boolean) |
| 177 | +let hasErrors = false |
| 178 | + |
| 179 | +commits.forEach((commit) => { |
| 180 | + const result = lintCommitMessage(commit) |
| 181 | + |
| 182 | + if (!result.valid) { |
| 183 | + console.error(`❌ Invalid commit message:`) |
| 184 | + console.error(commit.split('\n')[0]) |
| 185 | + result.errors.forEach(error => console.error(` - ${error}`)) |
| 186 | + hasErrors = true |
| 187 | + } |
| 188 | +}) |
| 189 | + |
| 190 | +if (hasErrors) { |
| 191 | + process.exit(1) |
| 192 | +} |
| 193 | +else { |
| 194 | + console.log('✅ All commit messages are valid') |
| 195 | +} |
| 196 | +``` |
| 197 | + |
| 198 | +## Best Practices for CI Integration |
| 199 | + |
| 200 | +1. **Fast feedback**: Configure validation as an early step in your CI pipeline |
| 201 | +2. **Clear error reporting**: Ensure validation failures provide actionable feedback |
| 202 | +3. **Skip certain commits**: Configure rules to ignore merge commits or automated commits |
| 203 | +4. **Documentation**: Document the commit message requirements in your repository |
| 204 | +5. **Block merges**: Consider making commit message validation a required check for protected branches |
| 205 | + |
| 206 | +## Troubleshooting |
| 207 | + |
| 208 | +### Common Issues |
| 209 | + |
| 210 | +**Issue**: CI validation passes locally but fails in CI |
| 211 | +**Solution**: Ensure your local and CI GitLint configurations match. Check for environment-specific settings. |
| 212 | + |
| 213 | +**Issue**: Merge commits failing validation |
| 214 | +**Solution**: Add merge commit patterns to your ignores list in GitLint configuration. |
| 215 | + |
| 216 | +**Issue**: Performance issues with large PRs |
| 217 | +**Solution**: Consider validating only the latest N commits or sampling commits. |
0 commit comments