whogitit 1.0.0

Track AI-generated code at line-level granularity
Documentation
# CI/CD Integration

Integrate whogitit with your CI/CD pipeline to automatically add AI attribution summaries to pull requests.

## GitHub Action

### Basic Setup

Create `.github/workflows/ai-attribution.yml`:

```yaml
name: AI Attribution Summary

on:
  pull_request:
    types: [opened, synchronize, reopened]

permissions:
  contents: read
  pull-requests: write

jobs:
  analyze:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
          ref: ${{ github.event.pull_request.head.sha }}

      - name: Fetch git notes
        run: |
          git fetch origin refs/notes/whogitit:refs/notes/whogitit || true
        continue-on-error: true

      - name: Setup Rust
        uses: dtolnay/rust-toolchain@stable

      - name: Cache cargo
        uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/bin/
            ~/.cargo/registry/index/
            ~/.cargo/registry/cache/
            ~/.cargo/git/db/
            target/
          key: ${{ runner.os }}-cargo-whogitit-${{ hashFiles('**/Cargo.lock') }}
          restore-keys: |
            ${{ runner.os }}-cargo-whogitit-

      - name: Install whogitit
        run: |
          if ! command -v whogitit &> /dev/null; then
            cargo install --git https://github.com/dotsetlabs/whogitit
          fi

      - name: Generate summary
        id: summary
        run: |
          BASE_SHA="${{ github.event.pull_request.base.sha }}"

          # Generate markdown summary
          SUMMARY=$(whogitit summary --base "$BASE_SHA" --format markdown 2>/dev/null || echo "")

          if [ -n "$SUMMARY" ]; then
            # Save to file for the comment step
            echo "$SUMMARY" > attribution-summary.md
            echo "has_attribution=true" >> $GITHUB_OUTPUT
          else
            echo "has_attribution=false" >> $GITHUB_OUTPUT
          fi

      - name: Comment on PR
        if: steps.summary.outputs.has_attribution == 'true'
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            const summary = fs.readFileSync('attribution-summary.md', 'utf8');

            // Find existing comment
            const { data: comments } = await github.rest.issues.listComments({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
            });

            const botComment = comments.find(c =>
              c.user.type === 'Bot' &&
              c.body.includes('AI Attribution Summary')
            );

            const body = `${summary}\n\n---\n*Generated by [whogitit](https://github.com/dotsetlabs/whogitit)*`;

            if (botComment) {
              await github.rest.issues.updateComment({
                owner: context.repo.owner,
                repo: context.repo.repo,
                comment_id: botComment.id,
                body: body
              });
            } else {
              await github.rest.issues.createComment({
                owner: context.repo.owner,
                repo: context.repo.repo,
                issue_number: context.issue.number,
                body: body
              });
            }
```

### Example PR Comment

The action posts a comment like:

---

## 🤖 AI Attribution Summary

This PR adds **+200** lines with AI attribution across **3** files.

### Additions Breakdown

| Metric | Lines | % of Additions |
|--------|------:|--------------:|
| 🟢 AI-generated | +145 | 72.5% |
| 🟡 AI-modified by human | +12 | 6.0% |
| 🔵 Human-written | +43 | 21.5% |
| **Total additions** | **+200** | **100%** |

**AI involvement: 78.5%** of additions are AI-generated

### Files Changed

| File | +Added | AI | Human | AI % | Status |
|------|-------:|---:|------:|-----:|--------|
| `src/auth.rs` | +80 | 72 | 8 | 90% | New |
| `src/main.rs` | +45 | 32 | 13 | 71% | Modified |
| `src/jwt.rs` | +75 | 53 | 22 | 71% | New |

### Commits with AI Attribution

| Commit | Message | AI | Modified | Human | Files |
|--------|---------|---:|--------:|------:|------:|
| `abc1234` | Add user authentication | 72 | 3 | 5 | 2 |
| `def5678` | Implement JWT tokens | 85 | 9 | 26 | 2 |

### Prompts Used (2)

<details>
<summary>Add user authentication with bcrypt password hashing...</summary>

```text
Add user authentication with bcrypt password hashing. Create a User struct
with email and password_hash fields. Implement register and login functions
that return Result types.
```
</details>

---

## Caching Strategy

The workflow caches:
- Cargo registry and indices
- Compiled binaries
- whogitit itself

This significantly speeds up subsequent runs.

## Handling Missing Notes

Git notes may not exist if:
- The contributor didn't push notes
- Notes haven't been fetched yet
- The commits have no AI attribution

The workflow handles this gracefully:

```yaml
- name: Fetch git notes
  run: git fetch origin refs/notes/whogitit:refs/notes/whogitit || true
  continue-on-error: true
```

## Branch Protection

Consider adding AI attribution requirements:

```yaml
# In a separate check job
- name: Check AI disclosure
  run: |
    AI_PERCENT=$(whogitit summary --base main --format json | jq '.ai_percentage')
    if (( $(echo "$AI_PERCENT > 80" | bc -l) )); then
      echo "::warning::This PR has >80% AI-generated code. Ensure thorough review."
    fi
```

## GitLab CI

For GitLab, create `.gitlab-ci.yml`:

```yaml
ai-attribution:
  stage: review
  image: rust:latest
  only:
    - merge_requests
  before_script:
    - cargo install --git https://github.com/dotsetlabs/whogitit
    - git fetch origin refs/notes/whogitit:refs/notes/whogitit || true
  script:
    - |
      SUMMARY=$(whogitit summary --base $CI_MERGE_REQUEST_TARGET_BRANCH_NAME --format markdown)
      if [ -n "$SUMMARY" ]; then
        echo "$SUMMARY" > attribution.md
        # Post to MR via GitLab API
      fi
  artifacts:
    paths:
      - attribution.md
```

## Jenkins

For Jenkins pipelines:

```groovy
pipeline {
    agent any
    stages {
        stage('AI Attribution') {
            when {
                changeRequest()
            }
            steps {
                sh '''
                    git fetch origin refs/notes/whogitit:refs/notes/whogitit || true
                    whogitit summary --base origin/main --format markdown > attribution.md
                '''
                script {
                    def summary = readFile('attribution.md')
                    if (summary.trim()) {
                        // Post comment via GitHub/GitLab API
                    }
                }
            }
        }
    }
}
```

## Custom Integrations

### Slack Notification

```bash
#!/bin/bash
SUMMARY=$(whogitit summary --base main --format json)
AI_PERCENT=$(echo "$SUMMARY" | jq '.ai_percentage')

if (( $(echo "$AI_PERCENT > 50" | bc -l) )); then
  curl -X POST "$SLACK_WEBHOOK" \
    -H 'Content-type: application/json' \
    -d "{\"text\": \"PR #$PR_NUMBER has ${AI_PERCENT}% AI-generated code\"}"
fi
```

### Export for Analytics

```bash
# In CI, export attribution data for each release
whogitit export \
  --since "$LAST_RELEASE_DATE" \
  --format json \
  -o "attribution-$VERSION.json"

# Upload to S3 or analytics platform
aws s3 cp "attribution-$VERSION.json" "s3://metrics/ai-attribution/"
```

## See Also

- [summary]../guide/commands/summary.md - Summary command reference
- [export]../guide/commands/export.md - Export command reference
- [Team Collaboration]./team-collaboration.md - Team policies