diff --git a/.github/workflows/check-for-actions-updates.yaml b/.github/workflows/check-for-actions-updates.yaml new file mode 100644 index 00000000..4292d9fe --- /dev/null +++ b/.github/workflows/check-for-actions-updates.yaml @@ -0,0 +1,204 @@ +name: Check for outdated GitHub Actions +on: + schedule: + - cron: '37 20 * * 3' + workflow_dispatch: + +jobs: + check-actions: + name: Check for GHA updates + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + + - name: Install actions-up + run: npm install -g actions-up + + - name: Run actions-up check + id: actions-check + run: | + echo "## GitHub Actions Update Check" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + # Initialize variables + HAS_UPDATES=false + UPDATE_COUNT=0 + + # Run actions-up and capture output + echo "Running actions-up to check for updates..." + actions-up --dry-run > actions-up-raw.txt 2>&1 || true + + # Parse the output to detect updates + if grep -q "→" actions-up-raw.txt; then + HAS_UPDATES=true + # Count the number of updates (lines with arrows) + UPDATE_COUNT=$(grep -c "→" actions-up-raw.txt || echo "0") + fi + + # Create formatted output + if [ "$HAS_UPDATES" = true ]; then + echo "Found $UPDATE_COUNT GitHub Actions with available updates" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "
" >> $GITHUB_STEP_SUMMARY + echo "Click to see details" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY + cat actions-up-raw.txt >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY + echo "
" >> $GITHUB_STEP_SUMMARY + + # Create detailed markdown report with better formatting + { + echo "## GitHub Actions Update Report" + echo "" + + echo "### Summary" + echo "- **Updates available:** $UPDATE_COUNT" + echo "" + + # See the raw output above for details. + echo "### How to Update" + echo "" + echo "You have several options to update these actions:" + echo "" + echo "#### Option 1: Automatic Update (Recommended)" + echo '```bash' + echo "# Run this command locally in your repository" + echo "npx actions-up" + echo '```' + echo "" + echo "#### Option 2: Manual Update" + echo "1. Review each update in the table above" + echo "2. For breaking changes, click the Release Notes link to review changes" + echo "3. Edit the workflow files and update the version numbers" + echo "4. Test the changes in your CI/CD pipeline" + echo "" + echo "---" + echo "" + echo "
" + echo "Raw actions-up output" + echo "" + echo '```' + cat actions-up-raw.txt + echo '```' + echo "
" + } > actions-up-report.md + + echo "has-updates=true" >> $GITHUB_OUTPUT + echo "update-count=$UPDATE_COUNT" >> $GITHUB_OUTPUT + else + echo "All GitHub Actions are up to date!" >> $GITHUB_STEP_SUMMARY + + { + echo "## GitHub Actions Update Report" + echo "" + echo "### All GitHub Actions in this repository are up to date!" + echo "" + echo "No action required. Your workflow files are using the latest versions of all GitHub Actions." + } > actions-up-report.md + + echo "has-updates=false" >> $GITHUB_OUTPUT + echo "update-count=0" >> $GITHUB_OUTPUT + fi + + - name: Comment PR with updates + if: github.event_name == 'pull_request' + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + const report = fs.readFileSync('actions-up-report.md', 'utf8'); + const hasUpdates = '${{ steps.actions-check.outputs.has-updates }}' === 'true'; + const updateCount = '${{ steps.actions-check.outputs.update-count }}'; + + // Check if we already commented + const comments = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number + }); + + const botComment = comments.data.find(comment => + comment.user.type === 'Bot' && + comment.body.includes('GitHub Actions Update Report') + ); + + const commentBody = `${report} + + --- + *Generated by [actions-up](https://github.com/azat-io/actions-up) | Last check: ${new Date().toISOString()}*`; + + // Only comment if there are updates or if we previously commented + if (hasUpdates || botComment) { + if (botComment) { + // Update existing comment + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: botComment.id, + body: commentBody + }); + console.log('Updated existing comment'); + } else { + // Create new comment only if there are updates + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: commentBody + }); + console.log('Created new comment'); + } + } else { + console.log('No updates found and no previous comment exists - skipping comment'); + } + + // Add or update PR labels based on status + const labels = await github.rest.issues.listLabelsOnIssue({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number + }); + + const hasOutdatedLabel = labels.data.some(label => label.name === 'outdated-actions'); + + if (hasUpdates && !hasOutdatedLabel) { + // Add label if updates are found + try { + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + labels: ['outdated-actions'] + }); + console.log('Added outdated-actions label'); + } catch (error) { + console.log('Could not add label (might not exist in repo):', error.message); + } + } else if (!hasUpdates && hasOutdatedLabel) { + // Remove label if no updates + try { + await github.rest.issues.removeLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + name: 'outdated-actions' + }); + console.log('Removed outdated-actions label'); + } catch (error) { + console.log('Could not remove label:', error.message); + } + } + + - name: Fail if outdated actions found + if: steps.actions-check.outputs.has-updates == 'true' + run: | + echo "::error:: Found ${{ steps.actions-check.outputs.update-count }} outdated GitHub Actions. Please update them before merging." + echo "" + echo "You can update them by running: npx actions-up" + echo "Or manually update the versions in your workflow files." + exit 1