Skip to main content

aster/github/
workflow.rs

1//! GitHub Actions 工作流管理
2//!
3//! 提供工作流模板和设置功能
4
5use std::path::Path;
6use tokio::process::Command;
7
8/// GitHub Actions 工作流模板
9pub const CLAUDE_CODE_WORKFLOW: &str = r#"name: Claude Code Review
10
11on:
12  pull_request:
13    types: [opened, synchronize, reopened]
14  issue_comment:
15    types: [created]
16
17permissions:
18  contents: read
19  pull-requests: write
20  issues: write
21
22jobs:
23  claude-review:
24    runs-on: ubuntu-latest
25    if: |
26      github.event_name == 'pull_request' ||
27      (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude'))
28
29    steps:
30      - name: Checkout code
31        uses: actions/checkout@v4
32        with:
33          fetch-depth: 0
34
35      - name: Run Claude Code Review
36        env:
37          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
38          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
39        run: |
40          echo "Claude Code Review placeholder"
41"#;
42
43/// GitHub CLI 状态
44#[derive(Debug, Clone)]
45pub struct GitHubCLIStatus {
46    /// 是否已安装
47    pub installed: bool,
48    /// 是否已认证
49    pub authenticated: bool,
50}
51
52/// 检查 GitHub CLI 是否可用
53pub async fn check_github_cli() -> GitHubCLIStatus {
54    let output = Command::new("gh").args(["auth", "status"]).output().await;
55
56    match output {
57        Ok(output) => {
58            let stdout = String::from_utf8_lossy(&output.stdout);
59            let stderr = String::from_utf8_lossy(&output.stderr);
60            let combined = format!("{}{}", stdout, stderr);
61
62            if output.status.success() || combined.contains("Logged in") {
63                GitHubCLIStatus {
64                    installed: true,
65                    authenticated: true,
66                }
67            } else if combined.contains("gh auth login") {
68                GitHubCLIStatus {
69                    installed: true,
70                    authenticated: false,
71                }
72            } else {
73                GitHubCLIStatus {
74                    installed: false,
75                    authenticated: false,
76                }
77            }
78        }
79        Err(_) => GitHubCLIStatus {
80            installed: false,
81            authenticated: false,
82        },
83    }
84}
85
86/// 设置 GitHub Actions 工作流结果
87#[derive(Debug, Clone)]
88pub struct SetupWorkflowResult {
89    /// 是否成功
90    pub success: bool,
91    /// 消息
92    pub message: String,
93    /// 工作流文件路径
94    pub workflow_path: Option<String>,
95}
96
97/// 设置 GitHub Actions 工作流
98pub async fn setup_github_workflow(project_dir: &Path) -> SetupWorkflowResult {
99    let workflows_dir = project_dir.join(".github").join("workflows");
100    let workflow_path = workflows_dir.join("claude-code.yml");
101
102    // 检查是否是 git 仓库
103    let git_dir = project_dir.join(".git");
104    if !git_dir.exists() {
105        return SetupWorkflowResult {
106            success: false,
107            message: "不是 git 仓库,请先运行 git init".to_string(),
108            workflow_path: None,
109        };
110    }
111
112    // 创建目录
113    if !workflows_dir.exists() {
114        if let Err(e) = tokio::fs::create_dir_all(&workflows_dir).await {
115            return SetupWorkflowResult {
116                success: false,
117                message: format!("创建目录失败: {}", e),
118                workflow_path: None,
119            };
120        }
121    }
122
123    // 检查是否已存在
124    if workflow_path.exists() {
125        return SetupWorkflowResult {
126            success: false,
127            message: "GitHub 工作流已存在".to_string(),
128            workflow_path: Some(workflow_path.to_string_lossy().to_string()),
129        };
130    }
131
132    // 写入工作流文件
133    if let Err(e) = tokio::fs::write(&workflow_path, CLAUDE_CODE_WORKFLOW).await {
134        return SetupWorkflowResult {
135            success: false,
136            message: format!("写入工作流文件失败: {}", e),
137            workflow_path: None,
138        };
139    }
140
141    SetupWorkflowResult {
142        success: true,
143        message: "GitHub Actions 工作流创建成功!".to_string(),
144        workflow_path: Some(workflow_path.to_string_lossy().to_string()),
145    }
146}