> ## Documentation Index
> Fetch the complete documentation index at: https://lunr-f6858e75.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# CI/CD integration

> Automate release note generation in your CI/CD pipelines

## Overview

HelixCommit integrates seamlessly with CI/CD platforms to automate release note generation. Whether you're using GitHub Actions, GitLab CI, Jenkins, or another platform, you can generate release notes automatically on every release.

<CardGroup cols={2}>
  <Card title="GitHub Actions" icon="github">
    Native integration with GitHub's CI/CD platform
  </Card>

  <Card title="GitLab CI" icon="gitlab">
    Automated pipelines for GitLab repositories
  </Card>

  <Card title="Jenkins" icon="jenkins">
    Flexible integration with Jenkins pipelines
  </Card>

  <Card title="CircleCI" icon="circle">
    Cloud-based CI/CD automation
  </Card>
</CardGroup>

## GitHub Actions

### Basic workflow

Automatically generate release notes when creating a release:

```yaml .github/workflows/release-notes.yml theme={}
name: Generate Release Notes

on:
  release:
    types: [created]

jobs:
  generate-notes:
    runs-on: ubuntu-latest
    permissions:
      contents: write
      
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0  # Full history for tags
      
      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.11'
      
      - name: Install HelixCommit
        run: pip install helixcommit
      
      - name: Generate release notes
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          helixcommit generate \
            --unreleased \
            --format markdown \
            --out RELEASE_NOTES.md
      
      - name: Update release
        uses: softprops/action-gh-release@v1
        with:
          body_path: RELEASE_NOTES.md
```

<Tip>
  GitHub Actions automatically provides `GITHUB_TOKEN` with appropriate permissions. No need to create a separate token!
</Tip>

### With AI summarization

Add AI-powered summaries to your release notes:

```yaml .github/workflows/release-notes-ai.yml theme={}
name: Generate AI Release Notes

on:
  release:
    types: [created]

jobs:
  generate-notes:
    runs-on: ubuntu-latest
    permissions:
      contents: write
      
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
      
      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.11'
      
      - name: Install HelixCommit
        run: pip install helixcommit
      
      - name: Generate AI-powered release notes
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
        run: |
          helixcommit generate \
            --unreleased \
            --use-llm \
            --openai-model gpt-4o-mini \
            --format markdown \
            --out RELEASE_NOTES.md
      
      - name: Update release
        uses: softprops/action-gh-release@v1
        with:
          body_path: RELEASE_NOTES.md
```

<Info>
  Add `OPENAI_API_KEY` to your repository secrets at Settings → Secrets and variables → Actions
</Info>

### With caching

Speed up subsequent runs with caching:

```yaml .github/workflows/release-notes-cached.yml theme={}
name: Generate Release Notes (Cached)

on:
  release:
    types: [created]

jobs:
  generate-notes:
    runs-on: ubuntu-latest
    permissions:
      contents: write
      
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
      
      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.11'
      
      - name: Cache HelixCommit data
        uses: actions/cache@v3
        with:
          path: .helixcommit-cache
          key: helixcommit-${{ github.sha }}
          restore-keys: |
            helixcommit-
      
      - name: Install HelixCommit
        run: pip install helixcommit
      
      - name: Generate release notes
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          HELIXCOMMIT_GH_CACHE: 1
        run: |
          helixcommit generate \
            --unreleased \
            --format markdown \
            --out RELEASE_NOTES.md
      
      - name: Update release
        uses: softprops/action-gh-release@v1
        with:
          body_path: RELEASE_NOTES.md
```

### On tag push

Generate notes when pushing a new tag:

```yaml .github/workflows/release-on-tag.yml theme={}
name: Release on Tag

on:
  push:
    tags:
      - 'v*'

jobs:
  release:
    runs-on: ubuntu-latest
    permissions:
      contents: write
      
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
      
      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.11'
      
      - name: Install HelixCommit
        run: pip install helixcommit
      
      - name: Get previous tag
        id: previoustag
        run: echo "tag=$(git describe --tags --abbrev=0 HEAD^)" >> $GITHUB_OUTPUT
      
      - name: Generate release notes
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          helixcommit generate \
            --since-tag ${{ steps.previoustag.outputs.tag }} \
            --until-tag ${{ github.ref_name }} \
            --format markdown \
            --out RELEASE_NOTES.md
      
      - name: Create GitHub Release
        uses: softprops/action-gh-release@v1
        with:
          tag_name: ${{ github.ref_name }}
          name: Release ${{ github.ref_name }}
          body_path: RELEASE_NOTES.md
```

## GitLab CI

### Basic pipeline

```yaml .gitlab-ci.yml theme={}
generate_release_notes:
  stage: release
  image: python:3.11
  only:
    - tags
  script:
    - pip install helixcommit
    - |
      helixcommit generate \
        --since-tag $(git describe --tags --abbrev=0 HEAD^) \
        --until-tag $CI_COMMIT_TAG \
        --format markdown \
        --out RELEASE_NOTES.md
  artifacts:
    paths:
      - RELEASE_NOTES.md
    expire_in: 1 week
```

### With GitHub integration

```yaml .gitlab-ci.yml theme={}
generate_release_notes:
  stage: release
  image: python:3.11
  only:
    - tags
  variables:
    GITHUB_TOKEN: $GITHUB_TOKEN
  script:
    - pip install helixcommit
    - |
      helixcommit generate \
        --since-tag $(git describe --tags --abbrev=0 HEAD^) \
        --until-tag $CI_COMMIT_TAG \
        --format markdown \
        --format html \
        --out RELEASE_NOTES.md
    - |
      helixcommit generate \
        --since-tag $(git describe --tags --abbrev=0 HEAD^) \
        --until-tag $CI_COMMIT_TAG \
        --format html \
        --out RELEASE_NOTES.html
  artifacts:
    paths:
      - RELEASE_NOTES.md
      - RELEASE_NOTES.html
```

### With AI features

```yaml .gitlab-ci.yml theme={}
generate_ai_release_notes:
  stage: release
  image: python:3.11
  only:
    - tags
  variables:
    OPENAI_API_KEY: $OPENAI_API_KEY
    GITHUB_TOKEN: $GITHUB_TOKEN
  script:
    - pip install helixcommit
    - |
      helixcommit generate \
        --unreleased \
        --use-llm \
        --openai-model gpt-4o-mini \
        --format markdown \
        --out RELEASE_NOTES.md
  artifacts:
    paths:
      - RELEASE_NOTES.md
  cache:
    key: helixcommit-cache
    paths:
      - .helixcommit-cache/
```

## Jenkins

### Declarative pipeline

```groovy Jenkinsfile theme={}
pipeline {
    agent any
    
    environment {
        GITHUB_TOKEN = credentials('github-token')
        OPENAI_API_KEY = credentials('openai-api-key')
    }
    
    stages {
        stage('Setup') {
            steps {
                sh 'pip install helixcommit'
            }
        }
        
        stage('Generate Release Notes') {
            when {
                tag pattern: "v\\d+\\.\\d+\\.\\d+", comparator: "REGEXP"
            }
            steps {
                script {
                    def previousTag = sh(
                        script: 'git describe --tags --abbrev=0 HEAD^',
                        returnStdout: true
                    ).trim()
                    
                    sh """
                        helixcommit generate \
                            --since-tag ${previousTag} \
                            --until-tag ${env.TAG_NAME} \
                            --format markdown \
                            --out RELEASE_NOTES.md
                    """
                }
            }
        }
        
        stage('Publish') {
            steps {
                archiveArtifacts artifacts: 'RELEASE_NOTES.md'
            }
        }
    }
}
```

### Scripted pipeline

```groovy Jenkinsfile theme={}
node {
    checkout scm
    
    stage('Install') {
        sh 'pip install helixcommit'
    }
    
    stage('Generate Notes') {
        withCredentials([string(credentialsId: 'github-token', variable: 'GITHUB_TOKEN')]) {
            sh '''
                helixcommit generate \
                    --unreleased \
                    --format markdown \
                    --out RELEASE_NOTES.md
            '''
        }
    }
    
    stage('Archive') {
        archiveArtifacts 'RELEASE_NOTES.md'
    }
}
```

## CircleCI

```yaml .circleci/config.yml theme={}
version: 2.1

jobs:
  generate-release-notes:
    docker:
      - image: python:3.11
    steps:
      - checkout
      - run:
          name: Install HelixCommit
          command: pip install helixcommit
      - run:
          name: Generate release notes
          command: |
            helixcommit generate \
              --unreleased \
              --format markdown \
              --out RELEASE_NOTES.md
      - store_artifacts:
          path: RELEASE_NOTES.md

workflows:
  release:
    jobs:
      - generate-release-notes:
          filters:
            tags:
              only: /^v.*/
            branches:
              ignore: /.*/
```

## Travis CI

```yaml .travis.yml theme={}
language: python
python:
  - "3.11"

install:
  - pip install helixcommit

script:
  - |
    if [ -n "$TRAVIS_TAG" ]; then
      helixcommit generate \
        --since-tag $(git describe --tags --abbrev=0 HEAD^) \
        --until-tag $TRAVIS_TAG \
        --format markdown \
        --out RELEASE_NOTES.md
    fi

deploy:
  provider: releases
  api_key: $GITHUB_TOKEN
  file: RELEASE_NOTES.md
  skip_cleanup: true
  on:
    tags: true
```

## Bitbucket Pipelines

```yaml bitbucket-pipelines.yml theme={}
pipelines:
  tags:
    v*:
      - step:
          name: Generate Release Notes
          image: python:3.11
          script:
            - pip install helixcommit
            - export PREVIOUS_TAG=$(git describe --tags --abbrev=0 HEAD^)
            - |
              helixcommit generate \
                --since-tag $PREVIOUS_TAG \
                --until-tag $BITBUCKET_TAG \
                --format markdown \
                --out RELEASE_NOTES.md
          artifacts:
            - RELEASE_NOTES.md
```

## Best practices

<AccordionGroup>
  <Accordion title="Use caching for AI summaries">
    Cache AI-generated summaries to reduce costs:

    ```yaml theme={}
    - name: Cache summaries
      uses: actions/cache@v3
      with:
        path: .helixcommit-cache
        key: summaries-${{ github.sha }}
        restore-keys: summaries-
    ```
  </Accordion>

  <Accordion title="Set up fail-safe for empty commits">
    Handle cases with no changes:

    ```bash theme={}
    helixcommit generate \
      --unreleased \
      --fail-on-empty || echo "No changes to release"
    ```
  </Accordion>

  <Accordion title="Generate multiple formats">
    Create notes in multiple formats for different uses:

    ```yaml theme={}
    - name: Generate all formats
      run: |
        helixcommit generate --unreleased --format markdown --out notes.md
        helixcommit generate --unreleased --format html --out notes.html
        helixcommit generate --unreleased --format text --out notes.txt
    ```
  </Accordion>

  <Accordion title="Use environment-specific configuration">
    ```yaml theme={}
    - name: Generate release notes
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        HELIXCOMMIT_GH_CACHE: 1
        HELIXCOMMIT_GH_MAX_RETRIES: 5
      run: |
        helixcommit generate --unreleased --out RELEASE_NOTES.md
    ```
  </Accordion>

  <Accordion title="Validate before publishing">
    ```bash theme={}
    # Generate notes
    helixcommit generate --unreleased --out RELEASE_NOTES.md

    # Validate content exists
    if [ ! -s RELEASE_NOTES.md ]; then
      echo "Error: Release notes are empty"
      exit 1
    fi

    # Check for required sections
    if ! grep -q "## Release" RELEASE_NOTES.md; then
      echo "Error: Invalid release notes format"
      exit 1
    fi
    ```
  </Accordion>
</AccordionGroup>

## Secrets management

### GitHub Actions

Add secrets at: Repository Settings → Secrets and variables → Actions

```yaml theme={}
env:
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}  # Provided automatically
  OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}  # Add manually
  OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}  # Add manually
```

### GitLab CI

Add variables at: Project Settings → CI/CD → Variables

```yaml theme={}
variables:
  GITHUB_TOKEN: $GITHUB_TOKEN
  OPENAI_API_KEY: $OPENAI_API_KEY
```

### Jenkins

Use Jenkins credentials:

```groovy theme={}
withCredentials([
  string(credentialsId: 'github-token', variable: 'GITHUB_TOKEN'),
  string(credentialsId: 'openai-key', variable: 'OPENAI_API_KEY')
]) {
  // Your script here
}
```

## Troubleshooting

<AccordionGroup>
  <Accordion title="Git history not available">
    Ensure you fetch full history:

    ```yaml theme={}
    - uses: actions/checkout@v4
      with:
        fetch-depth: 0  # Important: fetch all history and tags
    ```
  </Accordion>

  <Accordion title="Python not found">
    Install Python in your CI environment:

    ```yaml theme={}
    - name: Set up Python
      uses: actions/setup-python@v5
      with:
        python-version: '3.11'
    ```
  </Accordion>

  <Accordion title="Permission denied in GitHub Actions">
    Add required permissions:

    ```yaml theme={}
    jobs:
      release:
        permissions:
          contents: write  # Required to update releases
    ```
  </Accordion>

  <Accordion title="API rate limits">
    Enable caching and use authentication:

    ```yaml theme={}
    env:
      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      HELIXCOMMIT_GH_CACHE: 1
    ```
  </Accordion>
</AccordionGroup>

## Complete example

Here's a production-ready workflow with all best practices:

```yaml .github/workflows/release.yml theme={}
name: Generate and Publish Release Notes

on:
  push:
    tags:
      - 'v*'

jobs:
  release:
    runs-on: ubuntu-latest
    permissions:
      contents: write
      
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
      
      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.11'
          cache: 'pip'
      
      - name: Cache HelixCommit data
        uses: actions/cache@v3
        with:
          path: .helixcommit-cache
          key: helixcommit-${{ github.sha }}
          restore-keys: gitrelease-
      
      - name: Install GitReleaseGen
        run: pip install gitreleasegen
      
      - name: Get previous tag
        id: previoustag
        run: |
          PREVIOUS=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
          echo "tag=${PREVIOUS}" >> $GITHUB_OUTPUT
      
      - name: Generate release notes
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
          GITRELEASEGEN_GH_CACHE: 1
        run: |
          if [ -n "${{ steps.previoustag.outputs.tag }}" ]; then
            SINCE_FLAG="--since-tag ${{ steps.previoustag.outputs.tag }}"
          else
            SINCE_FLAG=""
          fi
          
          if [ -n "$OPENAI_API_KEY" ]; then
            gitreleasegen generate \
              $SINCE_FLAG \
              --until-tag ${{ github.ref_name }} \
              --use-llm \
              --openai-model gpt-4o-mini \
              --format markdown \
              --out RELEASE_NOTES.md
          else
            gitreleasegen generate \
              $SINCE_FLAG \
              --until-tag ${{ github.ref_name }} \
              --format markdown \
              --out RELEASE_NOTES.md
          fi
      
      - name: Validate release notes
        run: |
          if [ ! -s RELEASE_NOTES.md ]; then
            echo "Error: Release notes are empty"
            exit 1
          fi
      
      - name: Create GitHub Release
        uses: softprops/action-gh-release@v1
        with:
          tag_name: ${{ github.ref_name }}
          name: Release ${{ github.ref_name }}
          body_path: RELEASE_NOTES.md
          draft: false
          prerelease: false
      
      - name: Upload release notes
        uses: actions/upload-artifact@v4
        with:
          name: release-notes-${{ github.ref_name }}
          path: RELEASE_NOTES.md
```

## Next steps

<CardGroup cols={2}>
  <Card title="Examples" icon="code" href="/examples" color="#0A6ACB">
    See more CI/CD integration examples
  </Card>

  <Card title="Configuration" icon="gear" href="/configuration" color="#F6A02D">
    Advanced configuration options
  </Card>

  <Card title="GitHub integration" icon="github" href="/github-integration" color="#0A6ACB">
    Set up GitHub API authentication
  </Card>

  <Card title="AI features" icon="sparkles" href="/ai-features" color="#F26419">
    Add AI-powered summaries
  </Card>
</CardGroup>
