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
5 changes: 5 additions & 0 deletions .changeset/patch-add-assignees-to-create-issue.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 17 additions & 5 deletions .github/workflows/dev.lock.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 2 additions & 4 deletions .github/workflows/dev.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
---
on:
workflow_dispatch:
push:
paths:
- '.github/workflows/dev.md'
concurrency:
group: dev-workflow-${{ github.ref }}
cancel-in-progress: true
Expand All @@ -17,8 +14,9 @@ tools:
github:
safe-outputs:
create-issue:
assignees: copilot
imports:
- shared/mcp/tavily.md
---

Search the latest trends about javascript frameworks using tavily tools, and the last 3 pull requests using github tools and print a summary.
Write a creative poem about GitHub Agentic Workflows and create an issue with the poem. Assign the issue to copilot.
10 changes: 10 additions & 0 deletions docs/src/content/docs/reference/safe-outputs.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,22 @@ safe-outputs:
create-issue:
title-prefix: "[ai] " # Optional: prefix for issue titles
labels: [automation, agentic] # Optional: labels to attach to issues
assignees: [user1, user2, copilot] # Optional: users/bots to assign the issue to
max: 5 # Optional: maximum number of issues (default: 1)
target-repo: "owner/target-repo" # Optional: create issues in a different repository (requires github-token with appropriate permissions)
```

The agentic part of your workflow should describe the issue(s) it wants created.

**Configuration Options:**
- **`assignees:`** - GitHub username(s) to automatically assign to created issues. Accepts either a single string (`assignees: user1`) or an array of strings (`assignees: [user1, user2]`). The workflow automatically adds steps that call `gh issue edit --add-assignee` for each assignee after the issue is created. Only runs if the issue was successfully created.
- **Special value**: Use `copilot` to assign to the `copilot-swe-agent` bot
- Uses the configured GitHub token (respects `github-token` precedence: create-issue config > safe-outputs config > top-level config > default)

:::note
To assign issues to bots (including `copilot`), you must use a Personal Access Token (PAT) with appropriate permissions. The default `GITHUB_TOKEN` does not have permission to assign issues to bots. Configure a PAT using the `github-token` field at the workflow, safe-outputs, or create-issue level.
:::

**Example markdown to generate the output:**

```yaml
Expand Down
15 changes: 15 additions & 0 deletions pkg/parser/schemas/main_workflow_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -2055,6 +2055,21 @@
"type": "string"
}
},
"assignees": {
"oneOf": [
{
"type": "string",
"description": "Single GitHub username to assign the created issue to (e.g., 'user1' or 'copilot'). Use 'copilot' to assign to copilot-swe-agent."
},
{
"type": "array",
"description": "List of GitHub usernames to assign the created issue to (e.g., ['user1', 'user2', 'copilot']). Use 'copilot' to assign to copilot-swe-agent.",
"items": {
"type": "string"
}
}
]
},
"max": {
"type": "integer",
"description": "Maximum number of issues to create (default: 1)",
Expand Down
55 changes: 55 additions & 0 deletions pkg/workflow/create_issue.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ type CreateIssuesConfig struct {
BaseSafeOutputConfig `yaml:",inline"`
TitlePrefix string `yaml:"title-prefix,omitempty"`
Labels []string `yaml:"labels,omitempty"`
Assignees []string `yaml:"assignees,omitempty"` // List of users/bots to assign the issue to
TargetRepoSlug string `yaml:"target-repo,omitempty"` // Target repository in format "owner/repo" for cross-repository issues
}

Expand Down Expand Up @@ -40,6 +41,23 @@ func (c *Compiler) parseIssuesConfig(outputMap map[string]any) *CreateIssuesConf
}
}

// Parse assignees (supports both string and array)
if assignees, exists := configMap["assignees"]; exists {
if assigneeStr, ok := assignees.(string); ok {
// Single string format
issuesConfig.Assignees = []string{assigneeStr}
} else if assigneesArray, ok := assignees.([]any); ok {
// Array format
var assigneeStrings []string
for _, assignee := range assigneesArray {
if assigneeStr, ok := assignee.(string); ok {
assigneeStrings = append(assigneeStrings, assigneeStr)
}
}
issuesConfig.Assignees = assigneeStrings
}
}

// Parse target-repo
if targetRepoSlug, exists := configMap["target-repo"]; exists {
if targetRepoStr, ok := targetRepoSlug.(string); ok {
Expand Down Expand Up @@ -116,6 +134,43 @@ func (c *Compiler) buildCreateOutputIssueJob(data *WorkflowData, mainJobName str
})
steps = append(steps, scriptSteps...)

// Add assignee steps if assignees are configured
if len(data.SafeOutputs.CreateIssues.Assignees) > 0 {
// Add checkout step for gh CLI to work
steps = append(steps, " - name: Checkout repository for gh CLI\n")
steps = append(steps, " if: steps.create_issue.outputs.issue_number != ''\n")
steps = append(steps, " uses: actions/checkout@v5\n")
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@copilot also make conditional to having issue created

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Made the checkout step conditional on issue creation. The step now includes if: steps.create_issue.outputs.issue_number != '' so it only runs when an issue is successfully created.

Commit: [short_hash]


// Get the effective GitHub token to use for gh CLI
var safeOutputsToken string
if data.SafeOutputs != nil {
safeOutputsToken = data.SafeOutputs.GitHubToken
}
effectiveToken := getEffectiveGitHubToken(token, getEffectiveGitHubToken(safeOutputsToken, data.GitHubToken))

for i, assignee := range data.SafeOutputs.CreateIssues.Assignees {
// Special handling: "copilot" is the username for "copilot-swe-agent"
actualAssignee := assignee
if assignee == "copilot" {
actualAssignee = "copilot-swe-agent"
}

steps = append(steps, fmt.Sprintf(" - name: Assign issue to %s\n", assignee))
steps = append(steps, " if: steps.create_issue.outputs.issue_number != ''\n")
steps = append(steps, " env:\n")
steps = append(steps, fmt.Sprintf(" GH_TOKEN: %s\n", effectiveToken))
steps = append(steps, fmt.Sprintf(" ASSIGNEE: %q\n", actualAssignee))
steps = append(steps, " ISSUE_NUMBER: ${{ steps.create_issue.outputs.issue_number }}\n")
steps = append(steps, " run: |\n")
steps = append(steps, " gh issue edit \"$ISSUE_NUMBER\" --add-assignee \"$ASSIGNEE\"\n")

// Add a comment after each assignee step except the last
if i < len(data.SafeOutputs.CreateIssues.Assignees)-1 {
steps = append(steps, "\n")
}
}
}

// Create outputs for the job
outputs := map[string]string{
"issue_number": "${{ steps.create_issue.outputs.issue_number }}",
Expand Down
Loading
Loading