elizaos_plugin_github/actions/
create_issue.rs1#![allow(missing_docs)]
2
3use async_trait::async_trait;
4use serde_json::json;
5
6use super::{ActionContext, ActionResult, GitHubAction};
7use crate::error::Result;
8use crate::types::CreateIssueParams;
9use crate::GitHubService;
10
11pub struct CreateIssueAction;
12
13#[async_trait]
14impl GitHubAction for CreateIssueAction {
15 fn name(&self) -> &str {
16 "CREATE_GITHUB_ISSUE"
17 }
18
19 fn description(&self) -> &str {
20 "Creates a new issue in a GitHub repository. Use this to report bugs, request features, or track tasks."
21 }
22
23 fn similes(&self) -> Vec<&str> {
24 vec![
25 "OPEN_ISSUE",
26 "NEW_ISSUE",
27 "FILE_ISSUE",
28 "REPORT_BUG",
29 "CREATE_BUG_REPORT",
30 "SUBMIT_ISSUE",
31 ]
32 }
33
34 async fn validate(&self, context: &ActionContext) -> Result<bool> {
35 let text = context
36 .message
37 .get("content")
38 .and_then(|c| c.get("text"))
39 .and_then(|t| t.as_str())
40 .unwrap_or("")
41 .to_lowercase();
42
43 Ok(text.contains("issue")
44 || text.contains("bug")
45 || text.contains("report")
46 || text.contains("ticket"))
47 }
48
49 async fn handler(
50 &self,
51 context: &ActionContext,
52 service: &GitHubService,
53 ) -> Result<ActionResult> {
54 let text = context
55 .message
56 .get("content")
57 .and_then(|c| c.get("text"))
58 .and_then(|t| t.as_str())
59 .unwrap_or("");
60
61 let title = context
62 .state
63 .get("title")
64 .and_then(|t| t.as_str())
65 .map(|s| s.to_string())
66 .unwrap_or_else(|| text.chars().take(100).collect());
67
68 let params = CreateIssueParams {
69 owner: context.owner.clone(),
70 repo: context.repo.clone(),
71 title,
72 body: Some(text.to_string()),
73 assignees: Vec::new(),
74 labels: Vec::new(),
75 milestone: None,
76 };
77
78 let issue = service.create_issue(params).await?;
79
80 Ok(ActionResult::success(
81 format!("Created issue #{}: {}", issue.number, issue.title),
82 json!({
83 "issue_number": issue.number,
84 "html_url": issue.html_url,
85 }),
86 ))
87 }
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93 use serde_json::json;
94
95 #[tokio::test]
96 async fn test_validate_with_issue_keyword() {
97 let action = CreateIssueAction;
98 let context = ActionContext {
99 message: json!({
100 "content": { "text": "Create an issue for this bug" }
101 }),
102 owner: "test".to_string(),
103 repo: "test".to_string(),
104 state: json!({}),
105 };
106
107 assert!(action.validate(&context).await.unwrap());
108 }
109
110 #[tokio::test]
111 async fn test_validate_without_keywords() {
112 let action = CreateIssueAction;
113 let context = ActionContext {
114 message: json!({
115 "content": { "text": "Hello world" }
116 }),
117 owner: "test".to_string(),
118 repo: "test".to_string(),
119 state: json!({}),
120 };
121
122 assert!(!action.validate(&context).await.unwrap());
123 }
124}