Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion .github/workflows/cgo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1750,9 +1750,34 @@ jobs:
}
}

// Fetch all jobs for this run to get direct job links
const jobsResponse = await github.rest.actions.listJobsForWorkflowRun({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: context.runId,
per_page: 100,
});

// Build a map from job name to job URL for failed jobs
const jobUrlMap = {};
for (const job of jobsResponse.data.jobs) {
if (failedJobs.includes(job.name)) {
jobUrlMap[job.name] = job.html_url;
}
Comment on lines +1754 to +1766
Copy link

Copilot AI Apr 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The workflow currently assumes listJobsForWorkflowRun will always succeed. If that REST call fails (permissions, transient GitHub API failure, pagination edge cases), the script will throw and no failure issue gets created. Wrap the job-list fetch/build in a try/catch and fall back to rendering plain job names (or the run URL) when job URLs can't be resolved.

Suggested change
const jobsResponse = await github.rest.actions.listJobsForWorkflowRun({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: context.runId,
per_page: 100,
});
// Build a map from job name to job URL for failed jobs
const jobUrlMap = {};
for (const job of jobsResponse.data.jobs) {
if (failedJobs.includes(job.name)) {
jobUrlMap[job.name] = job.html_url;
}
const jobUrlMap = {};
try {
const jobsResponse = await github.rest.actions.listJobsForWorkflowRun({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: context.runId,
per_page: 100,
});
// Build a map from job name to job URL for failed jobs
for (const job of jobsResponse.data.jobs) {
if (failedJobs.includes(job.name)) {
jobUrlMap[job.name] = job.html_url;
}
}
} catch (e) {
core.warning(`Unable to resolve direct job links for workflow run ${context.runId}; falling back to plain job names. ${e.message}`);

Copilot uses AI. Check for mistakes.
}
Comment on lines +1753 to +1767
Copy link

Copilot AI Apr 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

github.rest.actions.listJobsForWorkflowRun requires the actions: read permission, but this job sets permissions to only issues: write. As written, this API call will fail (403) and the notify step will error. Add actions: read to the notify-failure job permissions (and keep issues: write).

Suggested change
// Fetch all jobs for this run to get direct job links
const jobsResponse = await github.rest.actions.listJobsForWorkflowRun({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: context.runId,
per_page: 100,
});
// Build a map from job name to job URL for failed jobs
const jobUrlMap = {};
for (const job of jobsResponse.data.jobs) {
if (failedJobs.includes(job.name)) {
jobUrlMap[job.name] = job.html_url;
}
}
// The notify job may not have `actions: read`, so avoid the Actions API here.
// Failed jobs will be listed by name, and the workflow run link below remains available.
const jobUrlMap = {};

Copilot uses AI. Check for mistakes.

const runUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
const expiresAt = new Date(Date.now() + 4 * 60 * 60 * 1000).toISOString();

// Format expiration line using the gh-aw-expires XML comment format
const expiresDate = new Date(expiresAt);
const humanReadableDate = expiresDate.toLocaleString('en-US', {
dateStyle: 'medium',
timeStyle: 'short',
timeZone: 'UTC',
});
const expirationLine = `- [x] expires <!-- gh-aw-expires: ${expiresAt} --> on ${humanReadableDate} UTC`;

const body = [
`## CGO Workflow Failure`,
``,
Expand All @@ -1766,9 +1791,13 @@ jobs:
``,
`## Failed Jobs`,
``,
...failedJobs.map(name => `- \`${name}\``),
// Map job names to direct links; fall back to plain text if a job ID wasn't found
...failedJobs.map(name => jobUrlMap[name]
? `- [\`${name}\`](${jobUrlMap[name]})`
: `- \`${name}\``),
``,
`> This issue expires at ${expiresAt}. Please investigate the failed jobs above and close once resolved.`,
`> ${expirationLine}`,
].join('\n');

const issue = await github.rest.issues.create({
Expand Down
1 change: 1 addition & 0 deletions docs/src/content/docs/agent-factory-status.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ These are experimental agentic workflows used by the GitHub Next team to learn,
| [Delight](https://github.com/github/gh-aw/blob/main/.github/workflows/delight.md) | copilot | [![Delight](https://github.com/github/gh-aw/actions/workflows/delight.lock.yml/badge.svg)](https://github.com/github/gh-aw/actions/workflows/delight.lock.yml) | - | - |
| [Dependabot Burner](https://github.com/github/gh-aw/blob/main/.github/workflows/dependabot-burner.md) | copilot | [![Dependabot Burner](https://github.com/github/gh-aw/actions/workflows/dependabot-burner.lock.yml/badge.svg)](https://github.com/github/gh-aw/actions/workflows/dependabot-burner.lock.yml) | - | - |
| [Dependabot Dependency Checker](https://github.com/github/gh-aw/blob/main/.github/workflows/dependabot-go-checker.md) | copilot | [![Dependabot Dependency Checker](https://github.com/github/gh-aw/actions/workflows/dependabot-go-checker.lock.yml/badge.svg)](https://github.com/github/gh-aw/actions/workflows/dependabot-go-checker.lock.yml) | `20 9 * * 1,3,5` | - |
| [Deployment Incident Monitor](https://github.com/github/gh-aw/blob/main/.github/workflows/deployment-incident-monitor.md) | copilot | [![Deployment Incident Monitor](https://github.com/github/gh-aw/actions/workflows/deployment-incident-monitor.lock.yml/badge.svg)](https://github.com/github/gh-aw/actions/workflows/deployment-incident-monitor.lock.yml) | - | - |
| [Design Decision Gate 🏗️](https://github.com/github/gh-aw/blob/main/.github/workflows/design-decision-gate.md) | claude | [![Design Decision Gate 🏗️](https://github.com/github/gh-aw/actions/workflows/design-decision-gate.lock.yml/badge.svg)](https://github.com/github/gh-aw/actions/workflows/design-decision-gate.lock.yml) | - | - |
| [Dev](https://github.com/github/gh-aw/blob/main/.github/workflows/dev.md) | copilot | [![Dev](https://github.com/github/gh-aw/actions/workflows/dev.lock.yml/badge.svg)](https://github.com/github/gh-aw/actions/workflows/dev.lock.yml) | `daily around 9:00` | - |
| [Dev Hawk](https://github.com/github/gh-aw/blob/main/.github/workflows/dev-hawk.md) | copilot | [![Dev Hawk](https://github.com/github/gh-aw/actions/workflows/dev-hawk.lock.yml/badge.svg)](https://github.com/github/gh-aw/actions/workflows/dev-hawk.lock.yml) | - | - |
Expand Down
18 changes: 14 additions & 4 deletions docs/src/content/docs/reference/frontmatter-full.md
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,17 @@ on:

# Option 2: object
deployment_status:
{}
# Filter to specific deployment states (compiled into if condition). Use a string
# for one state or an array for multiple states.
# (optional)
# This field supports multiple formats (oneOf):

# Option 1: string
state: "error"

# Option 2: array
state: []
# Array items: string
Comment on lines 484 to +495
Copy link

Copilot AI Apr 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The deployment_status YAML example is not valid YAML because it repeats the state key twice in the same mapping. Also, the array example uses an empty array (state: []), but the schema requires at least one item (minItems: 1). Adjust the example/generator to show the two oneOf options without duplicate keys (e.g., separate example blocks or commented alternatives) and use a non-empty array example.

See below for a potential fix:

  # Option 2: object with string state
  deployment_status:
    # Filter to specific deployment states (compiled into if condition). Use a string
    # for one state or an array for multiple states.
    # (optional)
    state: "error"

  # Option 3: object with array state
  deployment_status:
    # Filter to specific deployment states (compiled into if condition). Use a string
    # for one state or an array for multiple states.
    # (optional)
    state:
      # Array items: string
      - "error"
      - "failure"

Copilot uses AI. Check for mistakes.
Comment on lines 482 to +495
Copy link

Copilot AI Apr 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description focuses on lint-go/CGO workflow changes, but this PR also changes generated documentation content in frontmatter-full.md and the workflow status page. Please either update the PR description to mention the docs updates (and why they’re needed) or split them into a separate PR to keep the change intent clear.

Copilot uses AI. Check for mistakes.

# Fork event trigger that runs when someone forks the repository
# (optional)
Expand Down Expand Up @@ -3595,7 +3605,7 @@ safe-outputs:
github-token-for-extra-empty-commit: "example-value"

# Controls protected-file protection. String form: blocked (default), allowed, or
# fallback-to-issue. Object form: { policy, exclude } to customize the
# fallback-to-issue. Object form: { policy, exclude } to customise the
Copy link

Copilot AI Apr 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change introduces UK spelling (“customise”) in the generated reference, but the rest of the docs predominantly use US spelling (“customize”). For consistency across the documentation set, consider updating the source schema text so the generated output uses “customize”.

This issue also appears on line 4790 of the same file.

Suggested change
# fallback-to-issue. Object form: { policy, exclude } to customise the
# fallback-to-issue. Object form: { policy, exclude } to customize the

Copilot uses AI. Check for mistakes.
# protected-file set.
# (optional)
# This field supports multiple formats (oneOf):
Expand Down Expand Up @@ -4777,7 +4787,7 @@ safe-outputs:
# Array of strings

# Controls protected-file protection. String form: blocked (default), allowed, or
# fallback-to-issue. Object form: { policy, exclude } to customize the
# fallback-to-issue. Object form: { policy, exclude } to customise the
# protected-file set.
# (optional)
# This field supports multiple formats (oneOf):
Expand Down Expand Up @@ -5298,7 +5308,7 @@ safe-outputs:
# Default values injected when the model omits a field
# (optional)
defaults:
# Behavior when no files match: 'error' (default) or 'ignore'
# Behaviour when no files match: 'error' (default) or 'ignore'
Copy link

Copilot AI Apr 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line uses UK spelling (“Behaviour”) while the same document (and most other docs) use “Behavior”. For consistency, update the source schema/generator text to use a single spelling variant across the docs.

Suggested change
# Behaviour when no files match: 'error' (default) or 'ignore'
# Behavior when no files match: 'error' (default) or 'ignore'

Copilot uses AI. Check for mistakes.
# (optional)
if-no-files: "error"

Expand Down
5 changes: 3 additions & 2 deletions pkg/gitutil/spec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

// TestSpec_PublicAPI_IsRateLimitError validates the documented behavior of
Expand Down Expand Up @@ -274,7 +275,7 @@ func TestSpec_PublicAPI_IsValidFullSHA(t *testing.T) {
func TestSpec_PublicAPI_FindGitRoot(t *testing.T) {
t.Run("returns non-empty absolute path when in git repository", func(t *testing.T) {
root, err := FindGitRoot()
assert.NoError(t, err, "FindGitRoot should not error when inside a git repository")
require.NoError(t, err, "FindGitRoot should not error when inside a git repository")
assert.NotEmpty(t, root, "FindGitRoot should return a non-empty path")
assert.True(t, filepath.IsAbs(root),
"FindGitRoot should return an absolute path, got %q", root)
Expand All @@ -295,7 +296,7 @@ func TestSpec_PublicAPI_ReadFileFromHEADWithRoot(t *testing.T) {

t.Run("reads known file from HEAD without error", func(t *testing.T) {
content, err := ReadFileFromHEADWithRoot(filepath.Join(root, "go.mod"), root)
assert.NoError(t, err, "ReadFileFromHEADWithRoot should read go.mod without error")
require.NoError(t, err, "ReadFileFromHEADWithRoot should read go.mod without error")
assert.NotEmpty(t, content, "content of go.mod should not be empty")
})

Expand Down
Loading