Skip to content

Dependency Updates

Dependency Updates #2

name: Dependency Updates
on:
schedule:
# Check for dependency updates weekly on Tuesday at 3 AM UTC (different from security scan)
- cron: '0 3 * * 2'
workflow_dispatch: # Allow manual trigger
inputs:
update_type:
description: 'Type of dependency update'
required: false
default: 'all'
type: choice
options:
- all
- patch
- minor
- major
- security
include_indirect:
description: 'Include indirect dependencies'
required: false
type: boolean
default: true
create_pr:
description: 'Create pull request for updates'
required: false
type: boolean
default: true
env:
GO_VERSION: '1.24'
jobs:
check-dependencies:
name: Check for Dependency Updates
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
outputs:
updates_available: ${{ steps.check-updates.outputs.updates_available }}
security_updates: ${{ steps.check-security.outputs.security_updates }}
outdated_count: ${{ steps.check-updates.outputs.outdated_count }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- name: Cache go modules
uses: actions/cache@v4
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-go-deps-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-deps-
- name: Download dependencies
run: go mod download
- name: Install dependency update tools
run: |
# Install go-mod-upgrade with proper error handling
if ! go install github.com/chainguard-dev/go-mod-upgrade@latest 2>/dev/null; then
echo "Failed to install chainguard-dev/go-mod-upgrade, trying alternative..."
# Try the oligot version as fallback (already installed below)
go install github.com/oligot/go-mod-upgrade@latest
fi
go install github.com/oligot/go-mod-upgrade@latest
go install golang.org/x/vuln/cmd/govulncheck@latest
- name: Check for outdated dependencies
id: check-updates
run: |
echo "Checking for outdated dependencies..."
# Get list of outdated modules
go list -u -m -json all | jq -r '. | select(.Update != null) | "\(.Path) \(.Version) \(.Update.Version)"' > outdated.txt
echo "Found outdated dependencies:"
cat outdated.txt
COUNT=$(wc -l < outdated.txt)
echo "outdated_count=$COUNT" >> $GITHUB_OUTPUT
if [ "$COUNT" -gt 0 ]; then
echo "updates_available=true" >> $GITHUB_OUTPUT
else
echo "updates_available=false" >> $GITHUB_OUTPUT
fi
# Create detailed dependency report
cat > dependency-report.txt << 'EOF'
# Dependency Update Report
Generated on: $(date)
Repository: ${{ github.repository }}
Commit: ${{ github.sha }}
EOF
echo -e "\n## Outdated Dependencies\n" >> dependency-report.txt
echo "| Module | Current | Latest | Type |" >> dependency-report.txt
echo "|--------|---------|--------|------|" >> dependency-report.txt
while read -r module current latest; do
# Determine update type
update_type="patch"
if [[ "$current" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && [[ "$latest" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
current_major=$(echo "$current" | cut -d. -f1)
current_minor=$(echo "$current" | cut -d. -f2)
latest_major=$(echo "$latest" | cut -d. -f1)
latest_minor=$(echo "$latest" | cut -d. -f2)
if [ "$current_major" != "$latest_major" ]; then
update_type="major"
elif [ "$current_minor" != "$latest_minor" ]; then
update_type="minor"
fi
fi
echo "| $module | $current | $latest | $update_type |" >> dependency-report.txt
done < outdated.txt
- name: Check for security vulnerabilities
id: check-security
run: |
echo "Checking for security vulnerabilities..."
# Run vulnerability scanner
govulncheck -json ./... > vuln-report.json 2>/dev/null || echo "No vulnerabilities found or vulncheck failed"
# Extract security vulnerabilities
if [ -f "vuln-report.json" ] && [ -s "vuln-report.json" ]; then
VULNS=$(jq -r '.ID // empty' vuln-report.json | wc -l)
echo "Found $VULNS potential security vulnerabilities"
if [ "$VULNS" -gt 0 ]; then
echo "security_updates=true" >> $GITHUB_OUTPUT
else
echo "security_updates=false" >> $GITHUB_OUTPUT
fi
echo -e "\n## Security Vulnerabilities\n" >> dependency-report.txt
jq -r '"| \(.ID) | \(.details.Pkg // .pkg) | \(.details.CurrentVersion // "unknown") | \(.details.FixedVersion // "unknown") |"' vuln-report.json >> dependency-report.txt || echo "No vulnerabilities details available"
else
echo "No security vulnerabilities found"
echo "security_updates=false" >> $GITHUB_OUTPUT
echo -e "\n## Security Vulnerabilities\nNo security vulnerabilities found." >> dependency-report.txt
fi
- name: Upload dependency report
uses: actions/upload-artifact@v4
with:
name: dependency-report-${{ github.run_number }}
path: |
dependency-report.txt
outdated.txt
vuln-report.json
retention-days: 30
update-dependencies:
name: Update Dependencies
runs-on: ubuntu-latest
needs: check-dependencies
if: needs.check-dependencies.outputs.updates_available == 'true'
permissions:
contents: write
pull-requests: write
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- name: Cache go modules
uses: actions/cache@v4
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-go-deps-${{ hashFiles('**/go.sum') }}
- name: Download dependencies
run: go mod download
- name: Configure Git
run: |
git config --local user.email "[email protected]"
git config --local user.name "GitHub Actions"
- name: Create update branch
run: |
BRANCH_NAME="deps/$(date +'%Y-%m-%d')-update-${{ github.run_number }}"
echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV
git checkout -b "$BRANCH_NAME"
- name: Apply dependency updates
id: updates
run: |
echo "Applying dependency updates..."
# Update based on input type
case "${{ github.event.inputs.update_type || 'all' }}" in
"patch")
go get -u=patch ./...
;;
"minor")
go get -u=patch ./...
go get -u=minor ./...
;;
"major")
go get -u ./...
;;
"security")
# Focus on security updates only
go install github.com/oligot/go-mod-upgrade@latest
go-mod-upgrade -v
;;
*)
go get -u ./...
;;
esac
# Include indirect dependencies if requested
if [ "${{ github.event.inputs.include_indirect || 'true' }}" = "true" ]; then
go get -u=patch ./...
fi
# Tidy up
go mod tidy
# Check if anything changed
if git diff --quiet go.mod go.sum; then
echo "No dependency changes after update"
echo "changes=false" >> $GITHUB_OUTPUT
else
echo "Dependencies updated"
echo "changes=true" >> $GITHUB_OUTPUT
fi
- name: Run tests after update
if: steps.updates.outputs.changes == 'true'
run: |
echo "Running tests with updated dependencies..."
# Quick test to ensure updates don't break anything
go test -v ./... || {
echo "Tests failed after dependency update"
echo::warning::Dependency updates broke tests, creating PR anyway for manual review"
}
- name: Commit and push changes
if: steps.updates.outputs.changes == 'true' && (github.event.inputs.create_pr != 'false')
run: |
git add go.mod go.sum
# Create commit based on what was updated
if [ "${{ needs.check-dependencies.outputs.security_updates }}" = "true" ]; then
COMMIT_MSG="chore: update dependencies (including security fixes)"
else
COMMIT_MSG="chore: update Go dependencies ($(date +'%Y-%m-%d'))"
fi
git commit -m "$COMMIT_MSG
This PR updates Go modules to their latest versions.
**Updated Dependencies:**
$(cat outdated.txt | awk '{printf "- %s: %s → %s\n", $1, $2, $3}')
**Security Updates:**
$(if [ -f "vuln-report.json" ] && [ -s "vuln-report.json" ]; then jq -r '.ID' vuln-report.json | sed 's/^/- /'; else echo "None"; fi)
⚠️ **Manual Review Required**: Please review the changes and ensure all tests pass before merging.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: GitHub Actions <[email protected]>"
git push origin "$BRANCH_NAME"
- name: Create pull request
if: steps.updates.outputs.changes == 'true' && (github.event.inputs.create_pr != 'false')
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
PR_TITLE="chore: update Go dependencies ($(date +'%Y-%m-%d'))"
PR_BODY="## 📦 Dependency Update
This PR updates Go modules to their latest versions.
**Summary:**
- 📋 Outdated dependencies found: ${{ needs.check-dependencies.outputs.outdated_count }}
- 🔒 Security updates available: ${{ needs.check-dependencies.outputs.security_updates }}
- 📅 Generated: $(date +'%Y-%m-%d %H:%M:%S UTC')
**Updated Modules:**
\`\`\`
$(cat outdated.txt | awk '{printf "%-40s %s → %s\n", $1, $2, $3}')
\`\`\`
**Security Vulnerabilities:**
$(if [ -f "vuln-report.json" ] && [ -s "vuln-report.json" ]; then echo "Found security vulnerabilities requiring attention:"; cat vuln-report.json | jq -r '"- \(.ID): \(.details.summary // "")"'; else echo "No security vulnerabilities found."; fi)
**Next Steps:**
1. 🧪 Review the test results
2. 🔍 Check for breaking changes in the dependency updates
3. ✅ Ensure all tests pass
4. 🚀 Merge if everything looks good
**Automated Checks:**
- [x] Dependency compatibility check
- [x] Basic test suite execution
- [x] Security vulnerability scan
---
🤖 Generated with [Claude Code](https://claude.com/claude-code)
"
gh pr create \
--title "$PR_TITLE" \
--body "$PR_BODY" \
--head "$BRANCH_NAME" \
--base main \
--label "dependencies" \
--label "automated" || {
echo "PR creation failed or already exists"
gh pr list --head "$BRANCH_NAME" || echo "No PR found for this branch"
}
compatibility-tests:
name: Compatibility Testing
runs-on: ubuntu-latest
needs: check-dependencies
if: needs.check-dependencies.outputs.updates_available == 'true'
strategy:
matrix:
go_version: ['1.21', '1.22', '1.23']
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Go ${{ matrix.go_version }}
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go_version }}
cache: true
- name: Cache go modules
uses: actions/cache@v4
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-go-${{ matrix.go_version }}-${{ hashFiles('**/go.sum') }}
- name: Update to latest dependencies
run: |
go get -u ./...
go mod tidy
- name: Run compatibility tests
run: |
go test -v ./... || {
echo "Compatibility tests failed for Go ${{ matrix.go_version }}"
exit 1
}
- name: Build with updated dependencies
run: |
go build -o cortex-compat-${{ matrix.go_version }} ./cmd/router
license-compliance:
name: License Compliance Check
runs-on: ubuntu-latest
needs: check-dependencies
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- name: Install go-licenses
run: go install github.com/google/go-licenses@latest
- name: Update to latest dependencies
run: |
go get -u ./...
go mod tidy
- name: Check licenses for updated dependencies
run: |
echo "Checking licenses for updated dependencies..."
# Check licenses
go-licenses check ./... || {
echo "::warning::License check failed - review new dependencies"
}
# Generate license report
go-licenses csv ./... > updated-licenses.csv
# Check for problematic licenses
if grep -i "gpl\|agpl\|lgpl" updated-licenses.csv; then
echo "::warning::Found GPL/AGPL/LGPL licensed dependencies"
echo "Review licensing compliance for new dependencies"
else
echo "✅ All dependencies have compatible licenses"
fi
- name: Upload license report
uses: actions/upload-artifact@v4
with:
name: updated-licenses-${{ github.run_number }}
path: updated-licenses.csv
retention-days: 30
notify-dependencies:
name: Dependency Update Notifications
runs-on: ubuntu-latest
needs: [check-dependencies, update-dependencies, compatibility-tests]
if: always()
steps:
- name: Notify on successful updates
if: needs.update-dependencies.result == 'success'
run: |
echo "✅ Dependency update process completed successfully!"
echo "📊 Outdated dependencies found: ${{ needs.check-dependencies.outputs.outdated_count }}"
echo "🔒 Security updates needed: ${{ needs.check-dependencies.outputs.security_updates }}"
- name: Notify when no updates needed
if: needs.check-dependencies.outputs.updates_available == 'false'
run: |
echo "✅ All dependencies are up to date!"
echo "No action needed at this time."
- name: Notify on failures
if: needs.update-dependencies.result == 'failure' || needs.compatibility-tests.result == 'failure'
run: |
echo "⚠️ Dependency update process encountered issues"
if [ "${{ needs.update-dependencies.result }}" = "failure" ]; then
echo "- Dependency update failed"
fi
if [ "${{ needs.compatibility-tests.result }}" = "failure" ]; then
echo "- Compatibility tests failed"
fi
echo "Please review the run logs and manually address any issues."
- name: Create summary comment for dashboard
if: github.event_name == 'schedule'
run: |
cat << EOF
## 📊 Dependency Update Summary - $(date +'%Y-%m-%d')
- 📋 **Outdated Dependencies**: ${{ needs.check-dependencies.outputs.outdated_count }}
- 🔒 **Security Updates**: ${{ needs.check-dependencies.outputs.security_updates }}
- ✅ **Update Status**: ${{ needs.update-dependencies.result || 'completed' }}
- 🧪 **Compatibility**: ${{ needs.compatibility-tests.result || 'passed' }}
**Repository**: ${{ github.repository }}
**Commit**: ${{ github.sha }}
EOF