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 with: node-version: '20' - name: Install actions-up run: npm install -g actions-up - name: Run actions-up check id: actions-check run: | echo "GitHub Actions Update Check..." # 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" echo "actions-up output:" cat actions-up-raw.txt else echo "All GitHub Actions are up to date." 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