chore: sync workflow templates - #5191
Conversation
Automated sync from stranske/Workflows Template hash: 76ebdcce08bb Changes synced from sync-manifest.yml
There was a problem hiding this comment.
Pull request overview
Syncs workflow template scripts from stranske/Workflows into the consumer repo to keep weekly metrics aggregation and PR-metadata automation behavior consistent.
Changes:
- Improves weekly metrics artifact selection by adding “priority producer” workflow scanning and configurable limits.
- Adds explicit “no automation” source-context detection and uses it to skip keepalive dispatch and PR-body automation.
- Hardens metrics/coverage reporting contracts (typing improvements; safer filesystem probing).
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
scripts/aggregate_agent_metrics.py |
Adds stronger typing for counters and tightens the artifact selection JSON contract handling. |
.github/scripts/weekly_metrics_artifacts.js |
Adds priority-workflow artifact collection, deduping, and new config knobs for bounded scanning. |
.github/scripts/source_context.js |
Adds noAutomation detection across markers/labels/templates and threads it through source context resolution. |
.github/scripts/coverage_monitor_summary.js |
Wraps statSync in a try/catch to avoid crashing on transient filesystem issues. |
.github/scripts/agents_pr_meta_update_body.js |
Skips PR-body automation when noAutomation is set; improves workflow-source repair comment handling and issue-sync heuristics. |
.github/scripts/agents_pr_meta_keepalive.js |
Prevents keepalive dispatch when the PR opts out of automation via source context. |
| parseDateMs(run.updated_at ?? run.updatedAt) | ||
| ); | ||
| if (runTimestamp > 0 && runTimestamp < config.cutoff_ms) { | ||
| continue; |
There was a problem hiding this comment.
In the workflow-runs scan, once runTimestamp is older than config.cutoff_ms, remaining runs will typically also be older (GitHub returns runs in descending created/updated order). Using break instead of continue here would avoid unnecessary API calls and reduce rate-limit pressure.
| continue; | |
| break; |
| const comments = await github.paginate(github.rest.issues.listComments, { | ||
| owner, | ||
| repo, | ||
| issue_number: pr.number, | ||
| }); | ||
| await resolveSourceContextRepairComment({ | ||
| github, | ||
| owner, | ||
| repo, | ||
| prNumber: pr.number, | ||
| comments, | ||
| sourceContext, | ||
| core, | ||
| }); |
There was a problem hiding this comment.
In the issue-backed path, PR comments are fetched via github.paginate(...listComments...) here to resolve the workflow-source repair comment, and then fetched again later via fetchIssueComments(...). To reduce duplicate API calls (and rate-limit risk), consider reusing a single fetched issueComments array for both resolveSourceContextRepairComment and the later connector/authorization logic.
| let artifactResponse; | ||
| try { | ||
| artifactResponse = await withRetry((client) => | ||
| client.rest.actions.listWorkflowRunArtifacts({ | ||
| owner, | ||
| repo, | ||
| run_id: run.id, | ||
| per_page: config.per_page, | ||
| }) | ||
| ); | ||
| } catch (error) { | ||
| if (isNotFoundError(error)) continue; | ||
| throw error; | ||
| } | ||
| const matchingArtifacts = (artifactResponse?.data?.artifacts || []).filter((artifact) => | ||
| families.includes(artifactFamily(artifact.name)) | ||
| ); | ||
| sourceArtifacts.push(...matchingArtifacts); | ||
| artifacts.push(...matchingArtifacts); |
There was a problem hiding this comment.
listWorkflowRunArtifacts is only fetched for a single page (via per_page), so if a workflow run has more artifacts than config.per_page the selection may miss matching metrics artifacts that fall on later pages. Consider paginating actions.listWorkflowRunArtifacts (looping page until fewer than per_page results) so priority families are reliably discovered.
| let artifactResponse; | |
| try { | |
| artifactResponse = await withRetry((client) => | |
| client.rest.actions.listWorkflowRunArtifacts({ | |
| owner, | |
| repo, | |
| run_id: run.id, | |
| per_page: config.per_page, | |
| }) | |
| ); | |
| } catch (error) { | |
| if (isNotFoundError(error)) continue; | |
| throw error; | |
| } | |
| const matchingArtifacts = (artifactResponse?.data?.artifacts || []).filter((artifact) => | |
| families.includes(artifactFamily(artifact.name)) | |
| ); | |
| sourceArtifacts.push(...matchingArtifacts); | |
| artifacts.push(...matchingArtifacts); | |
| let page = 1; | |
| while (true) { | |
| let artifactResponse; | |
| try { | |
| artifactResponse = await withRetry((client) => | |
| client.rest.actions.listWorkflowRunArtifacts({ | |
| owner, | |
| repo, | |
| run_id: run.id, | |
| per_page: config.per_page, | |
| page, | |
| }) | |
| ); | |
| } catch (error) { | |
| if (isNotFoundError(error)) continue; | |
| throw error; | |
| } | |
| const pageArtifacts = artifactResponse?.data?.artifacts || []; | |
| const matchingArtifacts = pageArtifacts.filter((artifact) => | |
| families.includes(artifactFamily(artifact.name)) | |
| ); | |
| sourceArtifacts.push(...matchingArtifacts); | |
| artifacts.push(...matchingArtifacts); | |
| if (familiesSatisfied(sourceArtifacts, families, config)) { | |
| break; | |
| } | |
| if (pageArtifacts.length < config.per_page) { | |
| break; | |
| } | |
| page += 1; | |
| } |
Sync Summary
Files Updated
Files Skipped
Review Checklist
Source: stranske/Workflows
Source SHA:
070765783f4b6e6598f86787bcb556d788335077Template hash:
76ebdcce08bbSync branch:
sync/workflows-76ebdcce08bbConsumer repo:
stranske/Trend_Model_ProjectManifest:
.github/sync-manifest.yml