How To: Migrate Existing Repository to Linting

This guide walks you through adopting documentation linting in an existing repository with legacy content.

Overview

Existing documentation repositories often have:

  • Mixed filename conventions (spaces, uppercase, underscores)
  • Inconsistent directory structures
  • Broken or stale links
  • Orphaned assets

This guide provides a step-by-step process to clean up existing content and adopt linting practices.

Migration Strategy

Phase 1: Assessment (Day 1)

Run initial scan to understand current state.

Step 1: Run Discovery Scan

1
2
cd your-repository
docbuilder lint --format=json > lint-assessment.json

This generates a complete report of all issues without blocking.

Step 2: Analyze Results

1
2
3
4
5
6
7
8
# View human-readable summary
docbuilder lint

# Count issues by type
jq '.issues | group_by(.rule) | map({rule: .[0].rule, count: length})' lint-assessment.json

# Find most problematic directories
jq -r '.issues[].file' lint-assessment.json | xargs -n1 dirname | sort | uniq -c | sort -rn

Expected output:

Results:
  147 files scanned
  89 errors (blocks build)
  23 warnings (should fix)
  
Most common issues:
  • 45 files with spaces in filename
  • 32 files with uppercase letters
  • 12 files with invalid double extensions

Step 3: Categorize Work

Create fix plan based on severity:

Priority Issue Type Count Effort
P0 Spaces in filenames 45 Auto-fix
P0 Uppercase letters 32 Auto-fix
P0 Special characters 7 Auto-fix
P1 Double extensions 12 Manual review
P2 Missing section indexes 8 Manual creation
P3 Orphaned assets 15 Manual cleanup

Phase 2: Automated Cleanup (Day 1-2)

Use auto-fix to handle the majority of issues.

Step 1: Preview Auto-Fix

1
2
3
4
5
# Dry-run to see what would change
docbuilder lint --fix --dry-run > fix-preview.txt

# Review the preview
less fix-preview.txt

Example preview:

DRY RUN: No changes will be applied

FILE RENAMES:
  docs/API Guide.md → docs/api-guide.md
  docs/User Manual.md → docs/user-manual.md
  docs/Getting Started.md → docs/getting-started.md
  images/Screenshot 2024.png → images/screenshot-2024.png

CONTENT UPDATES:
  docs/index.md
    Line 15: [API Guide](./API Guide.md)
         →   [API Guide](/docbuilder/how-to/api-guide)
    Line 23: ![Screenshot](/docbuilder/how-to/images/screenshot 2024.png)
         →   ![Screenshot](/docbuilder/how-to/images/screenshot-2024.png)
  
  docs/tutorials/quickstart.md
    Line 8: See [Getting Started](../Getting Started.md)
        →  See [Getting Started](/docbuilder/getting-started)

Summary:
  45 files would be renamed
  87 links would be updated across 23 files

Step 2: Apply Auto-Fix

1
2
3
4
# Interactive mode (recommended first time)
docbuilder lint --fix

# Confirm when prompted

Expected output:

Found 45 files with naming issues:

Files to rename: 45
Links to update: 87 links in 23 files

This will:
  ✓ Rename 45 files using git mv (preserves history)
  ✓ Update 87 internal links
  ✓ Create backup: .docbuilder-backup-20251229-143052/

Proceed with fixes? [y/N]: y

Fixing issues...
✓ Renamed 45 files
✓ Updated 87 links in 23 files
✓ All changes applied successfully

Run 'git status' to review changes.

Step 3: Review Changes

1
2
3
4
5
6
7
8
9
# Check Git status
git status

# Review specific changes
git diff docs/index.md
git diff --name-status

# Verify no broken links
find docs/ -name "*.md" -exec grep -l "API Guide.md" {} \;  # Should be empty

Step 4: Test Build

1
2
3
4
5
6
# Verify Hugo build works
cd your-repository
docbuilder build -c config.yaml -o /tmp/test-build

# Or if using Hugo directly
cd docs && hugo server

Visit http://localhost:1313 and verify:

  • ✅ All pages render correctly
  • ✅ Navigation works
  • ✅ Links work
  • ✅ Images display

Step 5: Commit Automated Fixes

1
2
3
4
5
6
7
8
git add -A
git commit -m "docs: normalize filenames for linting compliance

- Rename files to lowercase with hyphens (45 files)
- Update internal links to renamed files (87 links)
- Preserve Git history with git mv

Generated by: docbuilder lint --fix"

Phase 3: Manual Cleanup (Day 2-3)

Handle issues that require manual intervention.

Issue: Invalid Double Extensions

Example: api-guide.md.backup, notes.markdown.old

Resolution:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# Find all double extension files
find docs/ -name "*.md.*" -o -name "*.markdown.*"

# Review and remove backup files
rm docs/api-guide.md.backup
rm docs/notes.markdown.old

# Add to .gitignore
echo "*.backup" >> .gitignore
echo "*.old" >> .gitignore
echo "*.tmp" >> .gitignore

git add -A
git commit -m "docs: remove backup files and update .gitignore"

Issue: Reserved Filenames

Example: docs/tags.md, docs/categories.md

Resolution:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# Rename with prefix
git mv docs/tags.md docs/content-tags.md
git mv docs/categories.md docs/content-categories.md

# Update any links
grep -r "tags.md" docs/ --include="*.md"
# Manually update found references

git add -A
git commit -m "docs: rename reserved filenames to avoid Hugo conflicts"

Issue: Missing Section Indexes

Example: docs/api/ directory has no _index.md

Resolution:

Create docs/api/_index.md:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
---
title: "API Documentation"
weight: 2
description: "Complete API reference and guides"
---

# API Documentation

This section contains comprehensive API documentation including:

- Authentication and authorization
- REST API endpoints
- GraphQL schema
- SDKs and client libraries
1
2
git add docs/api/_index.md
git commit -m "docs: add missing section index for API documentation"

Example: Links to moved or deleted files

Resolution:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# Find all broken links (requires build or manual check)
docbuilder lint  # Will report broken links

# For each broken link, either:
# 1. Fix the target path
# 2. Remove the link
# 3. Create the missing target file

# Example fix
vim docs/index.md
# Change: [Old Guide](/docbuilder/how-to/removed-doc)
# To:     [New Guide](/docbuilder/how-to/current-doc)

git add docs/index.md
git commit -m "docs: fix broken link to renamed documentation"

Issue: Orphaned Assets

Example: Images not referenced by any documentation

Resolution:

1
2
3
4
5
6
7
8
# Find orphaned images (requires custom script or manual review)
# For each orphaned file, either:
# 1. Reference it in documentation
# 2. Remove if truly unused

# Example removal
git rm docs/images/old-screenshot.png
git commit -m "docs: remove orphaned screenshot"

Phase 4: Git Hooks Setup (Day 3)

Prevent future issues by installing pre-commit hooks.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Install lefthook
brew install lefthook  # macOS
# or
go install github.com/evilmartians/lefthook@latest

# Create lefthook.yml
cat > lefthook.yml << 'EOF'
pre-commit:
  parallel: true
  commands:
    lint-docs:
      glob: "*.{md,markdown,png,jpg,jpeg,gif,svg}"
      run: docbuilder lint {staged_files} --quiet
      stage_fixed: true
EOF

# Install hooks
lefthook install

# Test
echo "test" >> docs/Test File.md  # Invalid filename
git add docs/Test\ File.md
git commit -m "test"  # Should fail

Option B: Traditional Hook

1
2
3
4
5
6
7
# Install pre-commit hook
docbuilder lint install-hook

# Test
echo "test" >> docs/Invalid\ Name.md
git add docs/Invalid\ Name.md
git commit -m "test"  # Should fail

Commit hook configuration:

1
2
git add lefthook.yml  # or .git/hooks/pre-commit
git commit -m "chore: add documentation linting pre-commit hook"

Phase 5: Team Rollout (Week 1-2)

Communicate changes and help team adopt.

Step 1: Announce Migration

Email template:

Subject: Documentation Linting Now Active

Hi team,

We've cleaned up our documentation and enabled automatic linting 
to maintain quality going forward.

What changed:
• All docs now use lowercase, hyphen-separated filenames
• Git hooks validate documentation before commit
• CI/CD pipeline checks will catch any issues

What you need to do:
1. Pull latest changes: git pull
2. Install hooks: lefthook install (or docbuilder lint install-hook)
3. Test: lefthook run pre-commit --verbose

Resources:
• Setup guide: docs/how-to/setup-linting.md
• Rule reference: docs/reference/lint-rules.md
• Questions: #docs-tooling Slack channel

Thanks!

Step 2: Setup Guide for Team

Create docs/CONTRIBUTING.md (if not exists):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Contributing to Documentation

## Setup (One-Time)

1. Install lefthook:
   - macOS: `brew install lefthook`
   - Linux: `go install github.com/evilmartians/lefthook@latest`

2. Install hooks:
   ```bash
   lefthook install
  1. Verify:
    1
    
    lefthook run pre-commit --verbose

Writing Documentation

Filename Rules

Do: Use lowercase with hyphens

api-guide.md
getting-started.md
user-manual.md

Don’t: Use spaces, uppercase, or special characters

API Guide.md          # Uppercase
getting_started.md    # Underscore
user manual.md        # Spaces

Auto-Fix

If linting fails on commit:

1
2
3
4
docbuilder lint --fix --dry-run  # Preview
docbuilder lint --fix            # Apply
git add -A
git commit -m "your message"

Bypassing Hooks

Only in emergencies:

1
git commit --no-verify -m "emergency fix"
```bash
git add docs/CONTRIBUTING.md
git commit -m "docs: add documentation contribution guidelines"

Step 3: Monitor Adoption

First week: Track metrics

1
2
3
4
5
6
# Count commits that passed linting
git log --since="1 week ago" --grep="docs:" --oneline | wc -l

# Check for --no-verify usage
git log --since="1 week ago" --all --source --full-history \
  --grep="no-verify" | wc -l

Adjust if needed:

  • Too many complaints: Review if rules too strict
  • People bypassing: Improve auto-fix or documentation
  • Confusion: Hold Q&A session

Phase 6: CI/CD Integration (Week 2)

Add automated validation to CI/CD pipeline.

GitHub Actions

Create .github/workflows/lint-docs.yml:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
name: Lint Documentation
on:
  pull_request:
    paths:
      - 'docs/**'
      - '**.md'

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Setup Go
        uses: actions/setup-go@v5
        with:
          go-version: '1.21'
      
      - name: Install DocBuilder
        run: go install github.com/your-org/docbuilder/cmd/docbuilder@latest
      
      - name: Lint Documentation
        run: |
          docbuilder lint --format=json > lint-report.json
          docbuilder lint  # Human-readable output
      
      - name: Upload Report
        if: always()
        uses: actions/upload-artifact@v3
        with:
          name: lint-report
          path: lint-report.json
1
2
git add .github/workflows/lint-docs.yml
git commit -m "ci: add documentation linting workflow"

GitLab CI

Add to .gitlab-ci.yml:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
lint-docs:
  stage: test
  image: golang:1.21
  script:
    - go install github.com/your-org/docbuilder/cmd/docbuilder@latest
    - docbuilder lint --format=json | tee lint-report.json
    - docbuilder lint  # Human-readable
  artifacts:
    when: always
    paths:
      - lint-report.json
    reports:
      junit: lint-report.json
  only:
    changes:
      - docs/**
      - '**/*.md'
1
2
git add .gitlab-ci.yml
git commit -m "ci: add documentation linting to CI pipeline"

Common Migration Scenarios

Scenario 1: Large Repository (1000+ Docs)

Challenge: Too many files to review manually

Solution: Incremental approach

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# Fix one directory at a time
docbuilder lint --fix docs/api/
git add docs/api/
git commit -m "docs(api): normalize filenames"

docbuilder lint --fix docs/guides/
git add docs/guides/
git commit -m "docs(guides): normalize filenames"

# Continue for each top-level directory

Scenario 2: Active Development

Challenge: Many concurrent PRs

Solution: Coordinate freeze window

1
2
3
4
5
1. Announce: "Docs cleanup Friday 2-4pm, merge PRs before then"
2. Friday 2pm: Merge all pending docs PRs
3. Friday 2-4pm: Run migration, commit changes
4. Friday 4pm: Team pulls latest, installs hooks
5. Monday: CI enforcement active

Scenario 3: Multi-Repo Organization

Challenge: Dozens of repositories

Solution: Batch automation

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#!/bin/bash
# migrate-all-repos.sh

REPOS=(
  "project-docs"
  "api-docs"
  "platform-docs"
)

for repo in "${REPOS[@]}"; do
  echo "Migrating $repo..."
  cd "$repo"
  
  # Run migration
  docbuilder lint --fix --yes
  
  # Commit if changes
  if [[ -n $(git status -s) ]]; then
    git add -A
    git commit -m "docs: normalize filenames for linting compliance"
    git push
  fi
  
  cd ..
done

Scenario 4: External Contributors

Challenge: Contributors don’t have DocBuilder installed

Solution: CI-only mode

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# .github/workflows/lint-docs.yml
- name: Auto-fix on PR
  if: github.event_name == 'pull_request'
  run: |
    docbuilder lint --fix --yes
    
    # Commit fixes if needed
    if [[ -n $(git status -s) ]]; then
      git config user.name "docbuilder-bot"
      git config user.email "bot@example.com"
      git add -A
      git commit -m "docs: auto-fix linting issues"
      git push
    fi

Rollback Plan

If migration causes issues:

Quick Rollback

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Revert the migration commit
git revert <migration-commit-sha>
git push

# Uninstall hooks
rm .git/hooks/pre-commit
# or
lefthook uninstall

# Notify team
echo "Linting temporarily disabled, investigating issues"

Gradual Rollback

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# Change hooks to non-blocking
# In lefthook.yml:
pre-commit:
  commands:
    lint-docs:
      run: docbuilder lint {staged_files} --quiet || true  # Don't block

# In .github/workflows/lint-docs.yml:
- name: Lint Documentation
  continue-on-error: true  # Don't fail CI

Success Metrics

Track these metrics over 30 days:

Metric Target Actual
Commits passing linting >90% ___
CI failures from docs <5% ___
–no-verify usage <10% ___
Time to fix issues <5 min avg ___
Team satisfaction >4/5 ___

Survey questions (after 2 weeks):

  1. How easy was linting setup? (1-5)
  2. Do error messages help you fix issues? (1-5)
  3. Has linting improved docs quality? (Yes/No)
  4. Suggestions for improvement? (Open)

Troubleshooting Migration

Issue: Too Many Errors to Fix

Solution: Use gradual enforcement

1
2
3
4
5
6
7
# Week 1: Warnings only
# In CI config, add: || true

# Week 2: Block new files only
# Custom script to check only changed files

# Week 3: Full enforcement

Issue: Team Resistance

Solution: Show value

  • Demonstrate auto-fix saving time
  • Show before/after build reliability
  • Highlight caught issues (broken links, etc.)

Issue: Performance Issues

Solution: Optimize linting scope

1
2
3
4
5
6
7
8
9
# Only lint changed files in CI
- name: Get changed files
  run: |
    git diff --name-only origin/main...HEAD > changed_files.txt
    grep -E '\.(md|markdown)$' changed_files.txt || true

- name: Lint changed files only
  run: |
    cat changed_files.txt | xargs docbuilder lint

Next Steps

After successful migration:

  1. ✅ All error-level issues resolved
  2. ✅ Team has hooks installed
  3. ✅ CI/CD enforcing linting
  4. 📖 Review Lint Rules Reference
  5. 📖 Consider CI/CD Integration enhancements
  6. 📊 Track metrics and iterate

Additional Resources


Migration Duration: 1-2 weeks for most repositories
Effort: ~1 day hands-on, rest is coordination
ROI: Improved docs quality, fewer build failures, better developer experience

permalink[how-to-migrate-existing-repository-to-linting](https://docs.home.luguber.info/_uid/f589369a-b003-410b-87ff-86e976e787ce/)