Skip to content
This repository was archived by the owner on Aug 10, 2026. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Set lockfile to use union merge strategy to reduce conflicts
# This tells Git to keep changes from both branches when there's a conflict
pnpm-lock.yaml merge=union

# Treat pnpm-lock.yaml as generated file for diff purposes
pnpm-lock.yaml linguist-generated=true
192 changes: 192 additions & 0 deletions .github/workflows/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
# pnpm-lock.yaml Conflict Prevention

This directory contains automated workflows to prevent and resolve `pnpm-lock.yaml` merge conflicts.

## Problem

When multiple developers work on different branches and modify dependencies, merging branches often results in conflicts in `pnpm-lock.yaml`. This file is auto-generated and difficult to resolve manually, leading to:

- Wasted time resolving conflicts
- Potential dependency inconsistencies
- Failed CI/CD pipelines
- Developer frustration

## Solution

We've implemented a multi-layered approach to prevent and automatically resolve lockfile conflicts:

### Layer 1: Version Consistency

**What:** Enforce consistent pnpm version across all environments.

**How:**
- Added `engines` field in `package.json` requiring pnpm 9.x
- All GitHub Actions workflows use pnpm version 9
- Lockfile format version is 9.0

**Why:** Different pnpm versions can generate different lockfile formats, causing unnecessary conflicts.

### Layer 2: Automated Resolution

**What:** GitHub Action that automatically detects and resolves lockfile conflicts on PRs.

**File:** `lockfile-autoresolve.yml`

**How it works:**
1. Triggers when a PR is opened/updated with changes to lockfiles or package.json
2. Detects merge conflicts in `pnpm-lock.yaml`
3. Removes the conflicted lockfile
4. Runs `pnpm install` to regenerate a clean lockfile
5. Commits and pushes the resolved lockfile back to the PR branch
6. Comments on the PR to notify the author

**Security:** Only runs on PRs from the same repository (not forks) to prevent unauthorized code execution.

### Layer 3: Pre-merge Validation

**What:** GitHub Action that validates lockfile integrity before merging.

**File:** `lockfile-validate.yml`

**How it works:**
1. Triggers on PRs targeting the main branch
2. Validates lockfile is in sync with package.json files
3. Checks for merge conflict markers
4. Verifies lockfile format version
5. Fails the CI if any issues are detected

**Why:** Ensures only valid, conflict-free lockfiles are merged to main.

### Layer 4: Git Merge Strategy

**What:** Git configuration to reduce lockfile conflicts.

**File:** `.gitattributes`

**How it works:**
- Sets `merge=union` strategy for `pnpm-lock.yaml`
- Git attempts to keep changes from both branches automatically
- Marks the file as linguist-generated for better diff display

**Why:** Provides a fallback mechanism for automatic conflict resolution at the Git level.

## For Developers

### If You Get a Lockfile Conflict

**Option 1: Let automation handle it (Recommended)**
1. Push your changes
2. Create/update your PR
3. Wait for the bot to auto-resolve and commit
4. Review the bot's commit
5. Pull the changes to your local branch

**Option 2: Resolve manually**
```bash
# Delete the conflicted lockfile
rm pnpm-lock.yaml

# Reinstall dependencies
pnpm install

# Commit the resolved lockfile
git add pnpm-lock.yaml
git commit -m "chore: resolve pnpm-lock.yaml conflicts"
git push
```

### Prevention Tips

1. **Always use pnpm 9.x**
```bash
# Check your version
pnpm --version

# Install correct version if needed
npm install -g pnpm@9
```

2. **Keep your branch up-to-date**
```bash
# Before installing new dependencies
git checkout main
git pull
git checkout your-branch
git merge main
pnpm install
```

3. **Coordinate dependency changes**
- Communicate with team when adding/updating major dependencies
- Merge dependency PRs quickly to reduce conflict window

## For Maintainers

### Monitoring

Check the Actions tab for:
- Failed lockfile validation runs
- Auto-resolve activity
- Pattern of frequent conflicts (may indicate coordination issues)

### Troubleshooting

**If auto-resolve keeps failing:**
1. Check if there are conflicting dependency versions in package.json files
2. Manually review the dependency changes in the PR
3. Ask the PR author to rebase on latest main

**If validation keeps failing:**
1. Check if developers are using different pnpm versions
2. Verify CI cache isn't stale
3. Review recent dependency changes for circular dependencies

### Customization

To adjust the automation:

- **Change pnpm version:** Update `package.json` engines and all workflow files
- **Modify auto-resolve behavior:** Edit `.github/workflows/lockfile-autoresolve.yml`
- **Adjust validation rules:** Edit `.github/workflows/lockfile-validate.yml`
- **Change merge strategy:** Edit `.gitattributes`

## Technical Details

### Workflow Triggers

**lockfile-autoresolve.yml:**
- `pull_request` events (opened, synchronize, reopened)
- Only when `pnpm-lock.yaml` or any `package.json` changes
- Only on same-repository PRs (security)

**lockfile-validate.yml:**
- `pull_request` events targeting main branch
- Only when `pnpm-lock.yaml` or any `package.json` changes

### Permissions

Both workflows require:
- `contents: write` - To commit resolved lockfile
- `pull-requests: write` - To comment on PRs

### Cost Considerations

These workflows add minimal CI cost:
- Auto-resolve: ~30-60 seconds per trigger
- Validate: ~20-30 seconds per trigger
- Only trigger on dependency-related changes
- Skip on subsequent commits if lockfile is clean

## Related Resources

- [pnpm Documentation](https://pnpm.io)
- [GitHub Actions Documentation](https://docs.github.com/actions)
- [Git Attributes Documentation](https://git-scm.com/docs/gitattributes)

## Questions?

If you have questions or issues with the lockfile automation:
1. Check the workflow run logs in GitHub Actions
2. Review this documentation
3. Open an issue with the `automation` label
4. Ask in the team chat
2 changes: 1 addition & 1 deletion .github/workflows/deploy-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ jobs:
cache: 'pnpm'

- name: Install Dependencies
run: pnpm install
run: pnpm install --frozen-lockfile

- name: Build Docs
run: pnpm run docs:build
Expand Down
97 changes: 97 additions & 0 deletions .github/workflows/lockfile-autoresolve.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
name: Auto-resolve pnpm-lock.yaml Conflicts

on:
pull_request:
types: [opened, synchronize, reopened]
paths:
- 'pnpm-lock.yaml'
- 'package.json'
- '**/package.json'

permissions:
contents: write
pull-requests: write

jobs:
resolve-lockfile:
runs-on: ubuntu-latest
# Only run on PRs from the same repository (not forks) to avoid security issues
if: github.event.pull_request.head.repo.full_name == github.repository

steps:
- name: Checkout PR branch
uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}
token: ${{ secrets.GITHUB_TOKEN }}
fetch-depth: 0

- name: Configure Git
run: |
git config --global user.name 'github-actions[bot]'
git config --global user.email '41898282+github-actions[bot]@users.noreply.github.com'

- name: Install pnpm
uses: pnpm/action-setup@v3
with:
version: 9

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20.x
cache: 'pnpm'

- name: Check for merge conflicts in lockfile
id: check-conflict
run: |
if git show :pnpm-lock.yaml 2>&1 | grep -q "<<<<<<< HEAD"; then
echo "conflict=true" >> $GITHUB_OUTPUT
echo "::notice::Detected merge conflict in pnpm-lock.yaml"
else
echo "conflict=false" >> $GITHUB_OUTPUT
echo "::notice::No merge conflict detected in pnpm-lock.yaml"
fi
continue-on-error: true

- name: Resolve lockfile by reinstalling dependencies
if: steps.check-conflict.outputs.conflict == 'true' || github.event_name == 'pull_request'
run: |
# Remove lockfile to force a fresh resolution
rm -f pnpm-lock.yaml

# Reinstall to generate a new lockfile
pnpm install --no-frozen-lockfile

echo "::notice::Successfully regenerated pnpm-lock.yaml"

- name: Check if lockfile changed
id: check-changes
run: |
if git diff --quiet pnpm-lock.yaml; then
echo "changed=false" >> $GITHUB_OUTPUT
echo "::notice::No changes to lockfile"
else
echo "changed=true" >> $GITHUB_OUTPUT
echo "::notice::Lockfile has been updated"
fi

- name: Commit resolved lockfile
if: steps.check-changes.outputs.changed == 'true'
run: |
git add pnpm-lock.yaml
git commit -m "chore: auto-resolve pnpm-lock.yaml conflicts [skip ci]"
git push origin ${{ github.head_ref }}
echo "::notice::Committed and pushed resolved lockfile"

- name: Comment on PR
if: steps.check-changes.outputs.changed == 'true'
uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: '🤖 **Lockfile Auto-resolved**\n\nThe `pnpm-lock.yaml` has been automatically regenerated to resolve conflicts. Please review the changes and ensure your dependencies are correct.'
})
63 changes: 63 additions & 0 deletions .github/workflows/lockfile-validate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
name: Validate Lockfile

on:
pull_request:
branches:
- main
paths:
- 'pnpm-lock.yaml'
- 'package.json'
- '**/package.json'

jobs:
validate:
name: Validate pnpm-lock.yaml
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Install pnpm
uses: pnpm/action-setup@v3
with:
version: 9

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20.x
cache: 'pnpm'

- name: Validate lockfile is up-to-date
run: |
# This will fail if lockfile is out of sync with package.json files
pnpm install --frozen-lockfile
echo "✅ Lockfile is up-to-date and consistent"

- name: Check for merge conflict markers
run: |
if grep -rn "<<<<<<< HEAD" pnpm-lock.yaml; then
echo "❌ Merge conflict markers found in pnpm-lock.yaml"
echo "::error::Please resolve merge conflicts in pnpm-lock.yaml"
exit 1
fi
echo "✅ No merge conflict markers found"

- name: Verify lockfile integrity
run: |
# Verify the lockfile format is valid
if [ ! -f "pnpm-lock.yaml" ]; then
echo "❌ pnpm-lock.yaml not found"
exit 1
fi

# Check lockfile version
LOCKFILE_VERSION=$(head -1 pnpm-lock.yaml | grep -oP "lockfileVersion: '\K[0-9.]+")
echo "Lockfile version: $LOCKFILE_VERSION"

if [ "$LOCKFILE_VERSION" != "9.0" ]; then
echo "⚠️ Warning: Lockfile version is $LOCKFILE_VERSION, expected 9.0"
fi

echo "✅ Lockfile integrity verified"
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
cache: 'pnpm'

- name: Install Dependencies
run: pnpm install
run: pnpm install --frozen-lockfile

- name: Create Release Pull Request or Publish to npm
id: changesets
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
cache: 'pnpm'

- name: Install Dependencies
run: pnpm install
run: pnpm install --frozen-lockfile

- name: Build
run: pnpm run build
Expand Down
1 change: 1 addition & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
enable-pre-post-scripts=true
auto-install-peers=true
engine-strict=true
Loading