🔄 Weekly Dependency Update #11
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: 🔄 Weekly Dependency Update | |
| on: | |
| schedule: | |
| # Run weekly on Monday at 9 AM UTC | |
| - cron: '0 9 * * 1' | |
| workflow_dispatch: | |
| inputs: | |
| dry-run: | |
| description: 'Check for updates without creating PR' | |
| required: false | |
| type: boolean | |
| default: false | |
| permissions: | |
| contents: read | |
| jobs: | |
| check-updates: | |
| name: Check for dependency updates | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| outputs: | |
| has-updates: ${{ steps.check.outputs.has-updates }} | |
| steps: | |
| - uses: SocketDev/socket-registry/.github/actions/setup-and-install@6147a08ccc20fcb1f690dcc4650ec745776b3345 # main | |
| - name: Check for npm updates | |
| id: check | |
| shell: bash | |
| run: | | |
| echo "Checking for npm package updates..." | |
| HAS_UPDATES=false | |
| NPM_UPDATES=$(pnpm outdated 2>/dev/null || true) | |
| if [ -n "$NPM_UPDATES" ] && ! echo "$NPM_UPDATES" | grep -q "No outdated"; then | |
| echo "npm packages have updates available" | |
| HAS_UPDATES=true | |
| fi | |
| echo "has-updates=$HAS_UPDATES" >> $GITHUB_OUTPUT | |
| apply-updates: | |
| name: Apply updates with Claude Code | |
| needs: check-updates | |
| if: needs.check-updates.outputs.has-updates == 'true' && inputs.dry-run != true | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| steps: | |
| - uses: SocketDev/socket-registry/.github/actions/setup-and-install@6147a08ccc20fcb1f690dcc4650ec745776b3345 # main | |
| - name: Create update branch | |
| id: branch | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| BRANCH_NAME="weekly-update-$(date +%Y%m%d)" | |
| git remote set-url origin "https://x-access-token:${GH_TOKEN}@github.com/${{ github.repository }}.git" | |
| git checkout -b "$BRANCH_NAME" | |
| echo "branch=$BRANCH_NAME" >> $GITHUB_OUTPUT | |
| - uses: SocketDev/socket-registry/.github/actions/setup-git-signing@6147a08ccc20fcb1f690dcc4650ec745776b3345 # main | |
| with: | |
| gpg-private-key: ${{ secrets.BOT_GPG_PRIVATE_KEY }} | |
| - name: Update dependencies (haiku) | |
| id: update | |
| timeout-minutes: 10 | |
| env: | |
| ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} | |
| GITHUB_ACTIONS: 'true' | |
| run: | | |
| if [ -z "$ANTHROPIC_API_KEY" ]; then | |
| echo "ANTHROPIC_API_KEY not set - skipping automated update" | |
| echo "success=false" >> $GITHUB_OUTPUT | |
| exit 0 | |
| fi | |
| set +e | |
| claude --print \ | |
| --allowedTools "Bash(pnpm:*)" "Bash(git add:*)" "Bash(git commit:*)" "Bash(git status:*)" "Bash(git diff:*)" "Bash(git log:*)" "Bash(git rev-parse:*)" "Read" "Write" "Edit" "Glob" "Grep" \ | |
| --model haiku \ | |
| --max-turns 15 \ | |
| "$(cat <<'PROMPT' | |
| /updating | |
| <context> | |
| You are an automated CI agent in a weekly dependency update workflow. | |
| Git is configured with GPG signing. A branch has been created for you. | |
| The pnpm binary is on PATH (wrapped through Socket firewall). | |
| </context> | |
| <instructions> | |
| Update all dependencies to their latest versions. | |
| Create one atomic commit per dependency update with a conventional commit message. | |
| Leave all changes local — the workflow handles pushing and PR creation. | |
| Skip running builds, tests, and type checks — CI runs those separately. | |
| </instructions> | |
| <success_criteria> | |
| Each updated dependency has its own commit. | |
| The lockfile is consistent with package.json changes. | |
| No uncommitted changes remain in the working tree. | |
| </success_criteria> | |
| PROMPT | |
| )" \ | |
| 2>&1 | tee claude-update.log | |
| CLAUDE_EXIT=${PIPESTATUS[0]} | |
| set -e | |
| if [ "$CLAUDE_EXIT" -eq 0 ]; then | |
| echo "success=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "success=false" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Run tests | |
| id: tests | |
| if: steps.update.outputs.success == 'true' | |
| run: | | |
| set +e | |
| pnpm build 2>&1 | tee build-output.log | |
| BUILD_EXIT=${PIPESTATUS[0]} | |
| pnpm test 2>&1 | tee test-output.log | |
| TEST_EXIT=${PIPESTATUS[0]} | |
| set -e | |
| if [ "$BUILD_EXIT" -eq 0 ] && [ "$TEST_EXIT" -eq 0 ]; then | |
| echo "success=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "success=false" >> $GITHUB_OUTPUT | |
| { | |
| echo "BUILD_LOG<<GHEOF" | |
| tail -50 build-output.log | |
| echo "GHEOF" | |
| } >> $GITHUB_OUTPUT | |
| { | |
| echo "TEST_LOG<<GHEOF" | |
| tail -50 test-output.log | |
| echo "GHEOF" | |
| } >> $GITHUB_OUTPUT | |
| fi | |
| - name: Fix test failures (sonnet) | |
| id: claude | |
| if: steps.update.outputs.success == 'true' && steps.tests.outputs.success == 'false' | |
| timeout-minutes: 15 | |
| env: | |
| ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} | |
| GITHUB_ACTIONS: 'true' | |
| BUILD_LOG: ${{ steps.tests.outputs.BUILD_LOG }} | |
| TEST_LOG: ${{ steps.tests.outputs.TEST_LOG }} | |
| run: | | |
| set +e | |
| claude --print \ | |
| --allowedTools "Bash(pnpm:*)" "Bash(git add:*)" "Bash(git commit:*)" "Bash(git status:*)" "Bash(git diff:*)" "Bash(git log:*)" "Bash(git rev-parse:*)" "Read" "Write" "Edit" "Glob" "Grep" \ | |
| --model sonnet \ | |
| --max-turns 25 \ | |
| "$(cat <<PROMPT | |
| Dependency updates were applied but tests are failing. Fix the failures. | |
| Git is configured with GPG signing. | |
| The pnpm binary is on PATH (wrapped through Socket firewall). | |
| <build_output> | |
| $BUILD_LOG | |
| </build_output> | |
| <test_output> | |
| $TEST_LOG | |
| </test_output> | |
| <instructions> | |
| 1. Analyze the build and test failures above. | |
| 2. Fix the source code so tests pass (pnpm build && pnpm test). | |
| 3. Commit each fix with a conventional commit message. | |
| 4. Leave all changes local — the workflow handles pushing. | |
| </instructions> | |
| PROMPT | |
| )" \ | |
| 2>&1 | tee claude-fix.log | |
| CLAUDE_EXIT=${PIPESTATUS[0]} | |
| set -e | |
| if [ "$CLAUDE_EXIT" -eq 0 ]; then | |
| echo "success=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "success=false" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Set final status | |
| id: final | |
| if: always() | |
| env: | |
| UPDATE_SUCCESS: ${{ steps.update.outputs.success }} | |
| TESTS_SUCCESS: ${{ steps.tests.outputs.success }} | |
| FIX_SUCCESS: ${{ steps.claude.outputs.success }} | |
| run: | | |
| if [ "$UPDATE_SUCCESS" != "true" ]; then | |
| echo "success=false" >> $GITHUB_OUTPUT | |
| elif [ "$TESTS_SUCCESS" = "true" ]; then | |
| echo "success=true" >> $GITHUB_OUTPUT | |
| elif [ "$FIX_SUCCESS" = "true" ]; then | |
| echo "success=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "success=false" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Validate changes | |
| id: validate | |
| if: steps.final.outputs.success == 'true' | |
| run: | | |
| UNEXPECTED="" | |
| for file in $(git diff --name-only origin/main..HEAD); do | |
| case "$file" in | |
| package.json|*/package.json|pnpm-lock.yaml|*/pnpm-lock.yaml|.npmrc|pnpm-workspace.yaml) ;; | |
| *) UNEXPECTED="$UNEXPECTED $file" ;; | |
| esac | |
| done | |
| if [ -n "$UNEXPECTED" ]; then | |
| echo "::warning::Non-dependency files modified:$UNEXPECTED" | |
| fi | |
| echo "valid=true" >> $GITHUB_OUTPUT | |
| - name: Check for changes | |
| id: changes | |
| run: | | |
| if [ -n "$(git status --porcelain)" ] || [ "$(git rev-list --count HEAD ^origin/main)" -gt 0 ]; then | |
| echo "has-changes=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "has-changes=false" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Push branch | |
| if: steps.final.outputs.success == 'true' && steps.validate.outputs.valid == 'true' && steps.changes.outputs.has-changes == 'true' | |
| env: | |
| BRANCH_NAME: ${{ steps.branch.outputs.branch }} | |
| run: git push origin "$BRANCH_NAME" | |
| - name: Create Pull Request | |
| if: steps.final.outputs.success == 'true' && steps.validate.outputs.valid == 'true' && steps.changes.outputs.has-changes == 'true' | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| BRANCH_NAME: ${{ steps.branch.outputs.branch }} | |
| run: | | |
| COMMITS=$(git log --oneline origin/main..HEAD) | |
| COMMIT_COUNT=$(git rev-list --count origin/main..HEAD) | |
| PR_BODY="## Weekly Dependency Update"$'\n\n' | |
| PR_BODY+="Automated weekly update of npm packages."$'\n\n' | |
| PR_BODY+="---"$'\n\n' | |
| PR_BODY+="### Commits (${COMMIT_COUNT})"$'\n\n' | |
| PR_BODY+="<details>"$'\n' | |
| PR_BODY+="<summary>View commit history</summary>"$'\n\n' | |
| PR_BODY+="\`\`\`"$'\n' | |
| PR_BODY+="${COMMITS}"$'\n' | |
| PR_BODY+="\`\`\`"$'\n\n' | |
| PR_BODY+="</details>"$'\n\n' | |
| PR_BODY+="---"$'\n\n' | |
| PR_BODY+="<sub>Generated by [weekly-update.yml](.github/workflows/weekly-update.yml)</sub>" | |
| gh pr create \ | |
| --title "chore(deps): weekly dependency update ($(date +%Y-%m-%d))" \ | |
| --body "$PR_BODY" \ | |
| --draft \ | |
| --head "$BRANCH_NAME" \ | |
| --base main | |
| - name: Add job summary | |
| if: steps.final.outputs.success == 'true' && steps.validate.outputs.valid == 'true' && steps.changes.outputs.has-changes == 'true' | |
| env: | |
| BRANCH_NAME: ${{ steps.branch.outputs.branch }} | |
| run: | | |
| COMMIT_COUNT=$(git rev-list --count origin/main..HEAD) | |
| echo "## Weekly Update Complete" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Branch:** \`${BRANCH_NAME}\`" >> $GITHUB_STEP_SUMMARY | |
| echo "**Commits:** ${COMMIT_COUNT}" >> $GITHUB_STEP_SUMMARY | |
| - name: Upload Claude output | |
| if: always() | |
| uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 | |
| with: | |
| name: claude-output-${{ github.run_id }} | |
| path: | | |
| claude-update.log | |
| claude-fix.log | |
| build-output.log | |
| test-output.log | |
| retention-days: 7 | |
| - uses: SocketDev/socket-registry/.github/actions/cleanup-git-signing@6147a08ccc20fcb1f690dcc4650ec745776b3345 # main | |
| if: always() | |
| notify: | |
| name: Notify results | |
| needs: [check-updates, apply-updates] | |
| if: always() | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| steps: | |
| - name: Report status | |
| env: | |
| HAS_UPDATES: ${{ needs.check-updates.outputs.has-updates }} | |
| DRY_RUN: ${{ inputs.dry-run }} | |
| run: | | |
| if [ "$HAS_UPDATES" = "true" ]; then | |
| if [ "$DRY_RUN" = "true" ]; then | |
| echo "Updates available (dry-run mode - no PR created)" | |
| else | |
| echo "Weekly update workflow completed" | |
| echo "Check the PRs tab for the automated update PR" | |
| fi | |
| else | |
| echo "All dependencies are up to date - no action needed!" | |
| fi |