feat: add actions-updater agentic workflow#18693
feat: add actions-updater agentic workflow#18693salmanmkc wants to merge 1 commit intogithub:mainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a new agentic workflow to detect outdated GitHub Action versions referenced in .md workflow sources and (when updates are found) open tracking issues for upgrades.
Changes:
- Introduces
.github/workflows/actions-updater.mdwith a deterministiccheck_outdatedjob that parsesuses:references and checks latest tags/releases viagh api. - Adds an agent prompt section intended to create one issue per outdated action (optionally across a repository or organization) with update instructions and grouping rules.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| If all actions are up to date, create a single informational issue noting that all actions are current. | ||
|
|
There was a problem hiding this comment.
The agent instructions say to "create a single informational issue" when everything is up to date, but the workflow is gated by if: needs.check_outdated.outputs.has_outdated == 'true', so the agent will never run in the all-up-to-date case. Either remove this instruction, or change the gating/logic so a no-op run can still optionally create that informational issue.
| workflow_dispatch: | ||
| inputs: | ||
| repository: | ||
| description: "Repository to scan (format: owner/repo). Defaults to current repo." | ||
| required: false | ||
| type: string | ||
| organization: | ||
| description: "Scan all repos in an organization (overrides repository input)" | ||
| required: false | ||
| type: string | ||
| dry-run: | ||
| description: "Only report outdated actions, don't create issues" | ||
| required: false | ||
| type: boolean | ||
| default: false |
There was a problem hiding this comment.
check_outdated ignores the repository and organization workflow_dispatch inputs (it always checks out and scans only the current repo). With the workflow-level if: needs.check_outdated.outputs.has_outdated == 'true', running the workflow for another repo/org can incorrectly skip the agent even when targets are outdated. Either incorporate the selected target(s) into the deterministic precheck, or change the gating so the agent runs when repository/organization are provided (and the agent does the scanning).
| # Extract unique action@version pairs from .md workflow files | ||
| grep -rhn 'uses:' .github/workflows/*.md 2>/dev/null \ | ||
| | sed -n 's/.*uses:[[:space:]]*\([^@#"'"'"'[:space:]]*\)@\([^#"'"'"'[:space:]]*\).*/\1@\2/p' \ | ||
| | sort -u > /tmp/current-actions.txt |
There was a problem hiding this comment.
The extractor only scans .github/workflows/*.md (non-recursive), so it misses action references in nested source files like .github/workflows/shared/**/*.md that can be imported into workflows. Consider scanning recursively (e.g., grep -r --include='*.md' .github/workflows) so the check covers all .md workflow sources.
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| run: | | ||
| # Extract unique action@version pairs from .md workflow files | ||
| grep -rhn 'uses:' .github/workflows/*.md 2>/dev/null \ |
There was a problem hiding this comment.
This grep scans the entire .md file contents, including the markdown prompt section after the frontmatter delimiter. In this file that includes example lines like uses: {action}@{old_version}, which will be picked up as a fake action and trigger unnecessary API calls/"SKIP" noise. Consider limiting parsing to the YAML frontmatter section only (up to the second ---), or otherwise excluding fenced code blocks / the prompt body from the uses: extraction.
| grep -rhn 'uses:' .github/workflows/*.md 2>/dev/null \ | |
| # Only consider the YAML frontmatter (before the second ---) to avoid prompt/example noise | |
| find .github/workflows -name '*.md' -type f -print0 2>/dev/null \ | |
| | while IFS= read -r -d '' file; do | |
| awk 'BEGIN{d=0} /^---[[:space:]]*$/{d++; if (d>=2) exit} {print}' "$file" | |
| done \ |
| if [ "$OUTDATED" -gt 0 ]; then | ||
| echo "has_outdated=true" >> "$GITHUB_OUTPUT" | ||
| # Truncate to fit output limits | ||
| echo "outdated_list=$(printf '%b' "$OUTDATED_LIST" | head -50)" >> "$GITHUB_OUTPUT" | ||
| else | ||
| echo "has_outdated=false" >> "$GITHUB_OUTPUT" | ||
| fi | ||
| echo "outdated_count=${OUTDATED}" >> "$GITHUB_OUTPUT" |
There was a problem hiding this comment.
outdated_list is written to $GITHUB_OUTPUT using name=value, but the value is multi-line (OUTDATED_LIST accumulates \n). Multi-line outputs must use the <<EOF delimiter form; otherwise this can break output parsing and fail the step. Update this to use the documented multi-line output syntax when emitting outdated_list.
| resolved=$(gh api "repos/${action}/git/matching-refs/tags" --jq '.[].ref' 2>/dev/null | while read ref; do | ||
| tag_sha=$(gh api "repos/${action}/git/ref/${ref#refs/}" --jq '.object.sha' 2>/dev/null) | ||
| if [ "$tag_sha" = "$current" ]; then | ||
| echo "${ref#refs/tags/}" | ||
| break | ||
| fi | ||
| done | head -1) |
There was a problem hiding this comment.
The SHA→tag resolution compares the input SHA to git/ref's .object.sha, which is the tag object's SHA for annotated tags (not the commit SHA). This will fail to resolve many real tags. To make this reliable, dereference annotated tags by checking .object.type and, when it's tag, follow up with git/tags/{sha} to compare the underlying commit SHA (or use an endpoint that returns the peeled commit).
|
|
||
| - **Repository input**: `${{ github.event.inputs.repository || github.repository }}` | ||
| - **Organization input**: `${{ github.event.inputs.organization }}` | ||
| - **Dry run**: `${{ github.event.inputs.dry-run }}` |
There was a problem hiding this comment.
The workflow_dispatch input name dry-run is referenced as ${{ github.event.inputs.dry-run }}. In GitHub Actions expressions, keys with hyphens generally require bracket notation (e.g., github.event.inputs['dry-run']) or using an input name without - (like dry_run). As written, this expression is likely to fail to evaluate and may break the run/compile.
| - **Dry run**: `${{ github.event.inputs.dry-run }}` | |
| - **Dry run**: `${{ github.event.inputs['dry-run'] }}` |
Adds an agentic workflow that scans .md workflow source files for outdated GitHub Actions and creates issues (like Dependabot). - Deterministic pre-filter: checks versions via gh api before invoking agent - Agent only runs when outdated actions are detected (saves tokens) - Creates one issue per outdated action with update instructions - Supports workflow_dispatch with repo/org inputs for org-wide scanning - Issues can be assigned to CCA for automatic PR creation
5f58f77 to
61f2f58
Compare
|
I think |
Summary
Adds an agentic workflow (actions-updater.md) that scans .md workflow source files for outdated GitHub Actions and creates issues, similar to how Dependabot creates alerts for outdated dependencies.
How it works
Deterministic pre-filter (no agent tokens burned)
A check_outdated job runs first as regular GitHub Actions:
The agent only runs if outdated actions are detected - zero token spend when everything is current.
Agent (only runs when needed)
Smart version detection
Inputs (workflow_dispatch)
Schedule
Runs weekly on Monday at 6am UTC.