Skip to content

Commit 4e61d7e

Browse files
committed
feat: composer support & stability
chore: wip chore: wip chore: wip chore: wip chore: wip fix: ensure require-dev packages are detected for updates - Remove --no-dev flag from composer install in GitHub Actions workflow - This allows phpunit/phpunit and nunomaduro/collision to be installed and detected - Add enhanced logging to composer outdated detection for debugging Fixes missing major PRs for require-dev packages in CI environment. fix: improve Composer outdated detection consistency - Always use constraint base version instead of installed version for consistent detection across environments - Add comprehensive logging for debugging Composer package detection issues - Ensure nunomaduro/collision and phpunit/phpunit major updates are detected in CI This fixes the issue where GitHub Actions was only detecting 3/5 major Composer updates due to environment differences in composer.lock vs composer.json constraints. chore: wip chore: wip chore: wip chore: wip chore: wip chore: wip chore: wip chore: wip chore: wip chore: wip chore: wip 🐛 CRITICAL FIX: Fix composer update detection - Fixed bug where composer show versions array was incorrectly parsed as object keys - Now properly detects all available composer package versions - Enhanced detection finds best patch, minor, and major updates per package - Fixes issue where 0 composer updates were found despite packages being available - Clean up debug logging chore: wip Add composer dependencies for testing composer update detection chore: wip Clean up debug logging after successful fixes MAJOR ENHANCEMENT: Add support for detecting minor/patch composer updates in addition to major updates - Enhanced composer outdated detection to find best patch, minor, and major updates per package - Uses 'composer show --available' to get all versions instead of just latest - Now composer packages will appear in non-major PRs when safe updates are available - Fixes the issue where only major updates were detected, missing safer bug fixes CRITICAL FIX: Reset to clean main state before generating file updates to prevent cross-contamination between PRs Add extensive debug logging to trace composer update issue Fix variable name mismatch: duration -> scanDuration Fix generateAllFileUpdates to prevent cross-contamination between update groups and add debug logging for grouping Add debug logging for update grouping chore: wip chore: wip chore: wip fix: remove overly restrictive Composer constraint filtering The previous approach was filtering out ALL updates that didn't match version constraints, including major updates that users want to see as individual PRs. Now including all available Composer updates and letting the grouping logic handle separation of major vs non-major updates naturally: - Major updates → Individual PRs (even if beyond constraints) - Minor/patch updates → Grouped PR (naturally respect constraints) This matches user expectations and fixes the issue where 0 Composer packages were being found due to overly strict constraint filtering. fix: remove debug test files Cleaning up test files that were created during debugging. The core constraint logic fix has been applied to the registry client. fix: improve tilde constraint handling in Composer Fixed the tilde constraint logic to properly handle different constraint levels: - ~1.2.3 allows only patch updates within 1.2.x - ~1.2 allows minor/patch updates within 1.x.x - ~1 allows minor/patch updates within 1.x.x This matches the test logic and ensures correct constraint-based filtering. debug: add comprehensive logging to Composer scanning Added detailed debug logging to understand why 0 Composer updates are found: - Log composer outdated command execution - Log raw output from composer outdated - Log parsed JSON data structure - Log composer.json file path and existence - Log packages found in composer.json require/require-dev This will help identify if the issue is: 1. composer outdated returning no packages 2. composer.json not being found/read 3. packages not matching between outdated and composer.json debug: add logging to Composer constraint filtering Added debug logs to understand why constraint filtering is excluding all updates: - Log number of outdated packages found - Log each package being processed with versions - Log constraints found in composer.json - Log why packages are being skipped or accepted This will help identify the issue with overly restrictive filtering. chore: wip fix: implement proper version constraint filtering for Composer updates Replaced invalid --strict flag with proper constraint-aware filtering: - Parse version constraints from composer.json (^, ~, etc.) - Filter composer outdated results to respect constraint boundaries - For ^ constraints: only allow minor/patch updates within same major - For ~ constraints: respect tilde semantics (~1.2 vs ~1) - Skip packages not found in composer.json This ensures Composer updates respect version constraints like Renovate does: - laravel/framework ^10.0 → shows 10.48.29 (not v12.x) - symfony/console ^6.0 → shows 6.4.23 (not v7.x) Fixes composer command failing with code 1 due to invalid --strict flag. fix: use composer outdated --strict to respect version constraints Changed from 'composer outdated' to 'composer outdated --strict' which: - Respects version constraints in composer.json (e.g., ^10.0, ^6.0) - Shows minor/patch updates within allowed ranges instead of major updates - Matches Renovate behavior for constraint-aware updates This should fix the issue where: - laravel/framework shows 10.48.29 (minor) instead of v12.21.0 (major) - symfony/console shows 6.4.23 (minor) instead of v7.3.1 (major) - All Composer packages now properly appear in non-major grouped PRs fix: ensure clean working directory between individual major update PRs Added git reset --hard and git clean -fd to ensure each PR branch starts from a completely clean state. This prevents individual major update PRs from inheriting file changes from previous PRs in the same workflow run. Also added comprehensive tests for Composer updates in non-major grouped PRs. This resolves the issue where: - Individual major PRs were applying all major updates instead of just the target package - Ensures proper isolation between PR creations chore: wip debug: show ALL package versions in composer.json during PR creation This will help identify if the composer.json file being read already contains updates from other PRs, which would explain why individual major update PRs are applying all changes instead of just the target package. debug: add detailed logging to generateComposerUpdates to trace file reading This will help identify what composer.json content is being read and which packages are being updated for individual major update PRs. The debug output will show current versions and target updates for each file. chore: wip debug: add logging to trace what updates are passed to each PR group This will help identify why individual major update PRs are applying all Composer updates instead of just the target package. The logs will show exactly what updates each group contains when creating PRs. chore: wip fix: treat GitHub Actions updates same as regular dependencies + handle workflow permissions Major changes: - Reverted GitHub Actions artificial separation - they now follow same rules as regular deps - Major GitHub Actions updates get individual PRs: 'chore(deps): update dependency X to Y' - Non-major GitHub Actions updates grouped with other non-major: 'chore(deps): update all non-major dependencies' Workflow permission handling: - Added filtering logic to exclude workflow files when GitHub App lacks 'workflows' permission - Gracefully handles mixed updates by committing non-workflow files and warning about workflow files - Prevents complete PR failure when only some files have permission issues This resolves the 403 Forbidden error while maintaining proper dependency grouping. fix: separate GitHub Actions updates to avoid workflow permission issues - GitHub Actions updates now get their own PR: 'chore(ci): update GitHub Actions dependencies' - Regular non-major updates stay grouped: 'chore(deps): update all non-major dependencies' - This prevents GitHub App workflow permission errors when updating .github/workflows/ files - Filters based on file path (.github/workflows/) and action names (actions/, oven-sh/, shivammathur/) This should resolve the '403 Forbidden' error for non-major updates containing workflow files. chore: wip chore: wip chore: wip fix: create individual PRs for each major update instead of grouping them - Major updates now get individual PRs: 'chore(deps): update dependency X to Y' - Non-major updates stay grouped: 'chore(deps): update all non-major dependencies' - Improved PR title matching to prevent incorrect PR overwrites - This ensures major updates get proper individual review Example: doctrine/dbal, laravel/framework, symfony/console each get separate PRs chore: wip chore: wip fix: add git configuration to workflow to prevent commit failures Adds git user.name and user.email configuration to prevent the 'Author identity unknown' error that was causing git CLI commits to fail. fix: improve version classification to handle v-prefixed versions This fixes the issue where Composer packages like laravel/framework v10.48.29→v12.21.0 and symfony/console v6.4.23→v7.3.1 were incorrectly classified as patch updates instead of major updates. The regex now includes 'v' prefix in the version cleaning pattern. chore: wip fix: restore proper rebase matching logic and cleanup empty files - Remove dangerous fallback to first group that was causing PR overwrites - Add bidirectional package matching for exact group identification - Add detailed logging when no matching group found - Remove accidentally committed empty files This ensures PR #20 type incidents won't happen again by making rebase operations fail safely instead of overwriting wrong PRs. chore: wip fix: improve rebase PR matching logic to prevent incorrect overwrites - Remove dangerous fallback to first group that caused wrong PR overwrites - Add bidirectional package matching to ensure exact group matches - Add detailed logging when no matching group is found - Prevent future incidents like PR #20 being overwritten with wrong updates This fixes the issue where the non-major updates PR was incorrectly overwritten with a major Composer update during rebase. fix: update package extraction regex to handle Composer PR format The regex now correctly extracts package updates from both npm and Composer PR tables, fixing the issue where 'Could not extract package updates from PR body' was preventing rebase functionality from working on Composer PRs. Before: Only handled npm format | [package] | [`version` -> `version`] | After: Handles both npm and Composer formats including | [package](link) | `version` -> `version` | file | status | fix: properly separate major and non-major dependency updates - Major updates (e.g. doctrine/dbal v3→v4) get individual PRs for careful review - Non-major updates (minor/patch) get grouped into a single PR - Uses default grouping behavior instead of custom groups fix: group all package updates together regardless of version type This ensures that major updates (like doctrine/dbal v3→v4) are grouped with other dependency updates instead of being separated into individual PRs.
1 parent 334ae34 commit 4e61d7e

30 files changed

+2042
-312
lines changed

.github/workflows/buddy-update-check.yml renamed to .github/workflows/buddy-check.yml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Buddy Update Check
1+
name: Buddy Check
22

33
on:
44
schedule:
@@ -41,9 +41,21 @@ jobs:
4141
with:
4242
bun-version: latest
4343

44+
- name: Setup PHP and Composer (if needed)
45+
if: ${{ hashFiles('composer.json') != '' }}
46+
uses: shivammathur/setup-php@v2
47+
with:
48+
php-version: '8.4'
49+
tools: composer
50+
coverage: none
51+
4452
- name: Install dependencies
4553
run: bun install
4654

55+
- name: Install Composer dependencies (if needed)
56+
if: ${{ hashFiles('composer.json') != '' }}
57+
run: composer install --prefer-dist --optimize-autoloader
58+
4759
- name: Build buddy-bot
4860
run: bun run build
4961

.github/workflows/buddy-dashboard.yml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Buddy Dashboard Management
1+
name: Buddy Dashboard
22

33
on:
44
schedule:
@@ -55,9 +55,21 @@ jobs:
5555
with:
5656
bun-version: latest
5757

58+
- name: Setup PHP and Composer (if needed)
59+
if: ${{ hashFiles('composer.json') != '' }}
60+
uses: shivammathur/setup-php@v2
61+
with:
62+
php-version: '8.4'
63+
tools: composer
64+
coverage: none
65+
5866
- name: Install dependencies
5967
run: bun install
6068

69+
- name: Install Composer dependencies (if needed)
70+
if: ${{ hashFiles('composer.json') != '' }}
71+
run: composer install --prefer-dist --optimize-autoloader
72+
6173
- name: Build buddy-bot
6274
run: bun run build
6375

.github/workflows/buddy-update.yml

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Buddy Testing Updates
1+
name: Buddy Update
22

33
on:
44
schedule:
@@ -31,13 +31,17 @@ on:
3131
type: boolean
3232

3333
env:
34-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
34+
# For workflow file updates, you need a Personal Access Token with 'repo' and 'workflow' scopes
35+
# Create a PAT at: https://github.com/settings/tokens
36+
# Add it as a repository secret named 'BUDDY_BOT_TOKEN'
37+
# If BUDDY_BOT_TOKEN is not available, falls back to GITHUB_TOKEN (limited permissions)
38+
GITHUB_TOKEN: ${{ secrets.BUDDY_BOT_TOKEN || secrets.GITHUB_TOKEN }}
3539

3640
permissions:
3741
contents: write
3842
pull-requests: write
3943
issues: write
40-
actions: read
44+
actions: write
4145
checks: read
4246
statuses: read
4347

@@ -49,14 +53,17 @@ jobs:
4953
- name: Checkout repository
5054
uses: actions/checkout@v4
5155
with:
52-
token: ${{ secrets.GITHUB_TOKEN }}
56+
token: ${{ secrets.BUDDY_BOT_TOKEN || secrets.GITHUB_TOKEN }}
57+
fetch-depth: 0 # Fetch full history for rebasing
58+
persist-credentials: true
5359

5460
- name: Setup Bun
5561
uses: oven-sh/setup-bun@v2
5662
with:
5763
bun-version: latest
5864

59-
- name: Setup PHP and Composer
65+
- name: Setup PHP and Composer (if needed)
66+
if: ${{ hashFiles('composer.json') != '' }}
6067
uses: shivammathur/setup-php@v2
6168
with:
6269
php-version: '8.4'
@@ -66,12 +73,18 @@ jobs:
6673
- name: Install dependencies
6774
run: bun install
6875

69-
- name: Install Composer dependencies
70-
run: composer install --no-dev --prefer-dist --optimize-autoloader
76+
- name: Install Composer dependencies (if needed)
77+
if: ${{ hashFiles('composer.json') != '' }}
78+
run: composer install --prefer-dist --optimize-autoloader
7179

7280
- name: Build buddy-bot
7381
run: bun run build
7482

83+
- name: Configure Git
84+
run: |
85+
git config --global user.name "buddy-bot[bot]"
86+
git config --global user.email "buddy-bot[bot]@users.noreply.github.com"
87+
7588
- name: Verify Composer setup
7689
run: |
7790
echo "🔍 Verifying Composer and PHP setup..."
@@ -129,7 +142,7 @@ jobs:
129142
fi
130143
131144
env:
132-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
145+
GITHUB_TOKEN: ${{ secrets.BUDDY_BOT_TOKEN || secrets.GITHUB_TOKEN }}
133146

134147
- name: Run Buddy dependency updates
135148
if: ${{ github.event.inputs.dry_run != 'true' }}
@@ -159,7 +172,7 @@ jobs:
159172
fi
160173
161174
env:
162-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
175+
GITHUB_TOKEN: ${{ secrets.BUDDY_BOT_TOKEN || secrets.GITHUB_TOKEN }}
163176

164177
- name: Dry run notification
165178
if: ${{ github.event.inputs.dry_run == 'true' }}

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@ storage
1616
qjs*
1717
bin/buddy
1818
bin/buddy-*
19-
19+
vendor

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ export JIRA_PROJECT_KEY="BUDDY" # Optional, defaults to BUDDY
341341
342342
Create custom integrations by defining plugins in `.buddy/plugins/`:
343343
344-
```json
344+
```jsonc
345345
// .buddy/plugins/custom-integration.json
346346
{
347347
"name": "custom-integration",

bin/cli.ts

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -765,14 +765,18 @@ cli
765765
return
766766
}
767767

768-
// Find the matching update group
768+
// Find the matching update group - must match exactly
769769
const group = scanResult.groups.find(g =>
770770
g.updates.length === packageUpdates.length
771-
&& g.updates.every(u => packageUpdates.some(pu => pu.name === u.name)),
772-
) || scanResult.groups[0] // Fallback to first group
771+
&& g.updates.every(u => packageUpdates.some(pu => pu.name === u.name))
772+
&& packageUpdates.every(pu => g.updates.some(u => u.name === pu.name)),
773+
)
773774

774775
if (!group) {
775-
logger.error('❌ Could not find matching update group')
776+
logger.error('❌ Could not find matching update group. This likely means the package grouping has changed.')
777+
logger.info(`📋 PR packages: ${packageUpdates.map(p => p.name).join(', ')}`)
778+
logger.info(`📋 Available groups: ${scanResult.groups.map(g => `${g.name} (${g.updates.length} packages)`).join(', ')}`)
779+
logger.info(`💡 Close this PR manually and let buddy-bot create new ones with correct grouping`)
776780
return
777781
}
778782

@@ -811,8 +815,10 @@ cli
811815
async function extractPackageUpdatesFromPRBody(body: string): Promise<Array<{ name: string, currentVersion: string, newVersion: string }>> {
812816
const updates: Array<{ name: string, currentVersion: string, newVersion: string }> = []
813817

814-
// Match table rows with package updates
815-
const tableRowRegex = /\|\s*\[([^\]]+)\][^|]*\|\s*\[`\^?([^`]+)`\s*->\s*`\^?([^`]+)`\]/g
818+
// Match table rows with package updates - handles both npm and Composer formats
819+
// npm format: | [package] | [`version` -> `version`] |
820+
// Composer format: | [package](link) | `version` -> `version` | file | status |
821+
const tableRowRegex = /\|\s*\[([^\]]+)\][^|]*\|\s*\[?`\^?([^`]+)`\s*->\s*`\^?([^`]+)`\]?/g
816822

817823
let match
818824
// eslint-disable-next-line no-cond-assign
@@ -914,14 +920,18 @@ cli
914920
continue
915921
}
916922

917-
// Find the matching update group
923+
// Find the matching update group - must match exactly
918924
const group = scanResult.groups.find(g =>
919925
g.updates.length === packageUpdates.length
920-
&& g.updates.every(u => packageUpdates.some(pu => pu.name === u.name)),
921-
) || scanResult.groups[0] // Fallback to first group
926+
&& g.updates.every(u => packageUpdates.some(pu => pu.name === u.name))
927+
&& packageUpdates.every(pu => g.updates.some(u => u.name === pu.name)),
928+
)
922929

923930
if (!group) {
924-
logger.warn(`⚠️ Could not find matching update group for PR #${pr.number}, skipping`)
931+
logger.warn(`⚠️ Could not find matching update group for PR #${pr.number}. This likely means the package grouping has changed.`)
932+
logger.info(`📋 PR packages: ${packageUpdates.map(p => p.name).join(', ')}`)
933+
logger.info(`📋 Available groups: ${scanResult.groups.map(g => `${g.name} (${g.updates.length} packages)`).join(', ')}`)
934+
logger.info(`💡 Skipping rebase - close this PR manually and let buddy-bot create new ones with correct grouping`)
925935
continue
926936
}
927937

buddy-bot.config.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const config: BuddyBotConfig = {
77
ignore: ['typescript', 'bun-plugin-dtsx'],
88
includePrerelease: false, // Don't include alpha, beta, rc versions by default
99
excludeMajor: false, // Allow major updates (controlled by ignore list)
10+
// No custom groups - use default grouping (major separate, non-major together)
1011
},
1112

1213
// Repository settings for PR creation
@@ -19,8 +20,8 @@ const config: BuddyBotConfig = {
1920

2021
// Pull request configuration
2122
pullRequest: {
22-
reviewers: [],
23-
assignees: [],
23+
reviewers: ['chrisbbreuer', 'glennmichael123'],
24+
assignees: ['chrisbbreuer', 'glennmichael123'],
2425
labels: ['dependencies'],
2526
autoMerge: {
2627
enabled: true,

docs/cli/setup.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ The setup process creates several files:
334334

335335
#### Dashboard Workflow
336336
```yaml
337-
name: Buddy Dashboard Management
337+
name: Buddy Dashboard
338338

339339
on:
340340
schedule:
@@ -344,7 +344,7 @@ on:
344344
345345
#### Update Check Workflow
346346
```yaml
347-
name: Buddy Update Check
347+
name: Buddy Check
348348

349349
on:
350350
schedule:

docs/features/rebase.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ buddy-bot update-check --dry-run --verbose
7272
### Manual Trigger via GitHub Actions
7373

7474
1. Go to **Actions** tab in your repository
75-
2. Select **"Buddy Update Check"** workflow
75+
2. Select **"Buddy Check"** workflow
7676
3. Click **"Run workflow"**
7777
4. Choose options:
7878
- **Dry run**: Preview changes without applying them
@@ -85,7 +85,7 @@ buddy-bot update-check --dry-run --verbose
8585
The rebase workflow is automatically created when you run `buddy-bot setup`. It includes:
8686

8787
```yaml
88-
name: Buddy Update Check
88+
name: Buddy Check
8989

9090
on:
9191
schedule:

0 commit comments

Comments
 (0)