Rust Azure DevOps集成库azure_devops_rust_api的使用,实现高效API调用与自动化任务管理

Azure DevOps Rust API

概述

azure_devops_rust_api 实现了 Rust 对 Azure DevOps REST API(版本 7.1)的接口。

该 crate 是从 Azure DevOps OpenAPI 规范自动生成的。

该 crate 包含 38 个模块

使用

使用概述

该 crate 有许多功能/模块,但通用方法对所有模块都类似:

  • 获取认证凭据
    • 查看示例了解如何使用 azure_identity crate 实现此操作
  • 为您想要使用的功能/模块创建客户端
    • 通常您需要为您想要使用的顶级模块创建一个客户端(例如 git_client),然后为子模块创建一个(例如 repositories_client)。
  • 使用客户端进行操作请求
    • 每个操作有零个或多个必需参数和零个或多个可选参数。 必需参数作为操作请求方法的参数传递。可选 参数可以通过调用操作请求方法返回的“构建器”对象上的方法来提供。构建器对象通过调用 await 来最终确定,这将构建器转换为 Future(通过 IntoFuture 特性)并等待响应。

代码示例

示例用法(来自 examples/git_repo_list.rs):

    // 从 PAT ("ADO_TOKEN") 或通过 az cli 获取认证凭据
    let credential = utils::get_credential()
// 通过环境变量获取 ADO 配置
let organization = env::var("ADO_ORGANIZATION")
    .expect("Must define ADO_ORGANIZATION");
let project = env::var("ADO_PROJECT")
    .expect("Must define ADO_PROJECT");

// 创建 git 客户端
let git_client = git::ClientBuilder::new(credential).build();

// 获取指定组织/项目中的所有仓库
let repos = git_client
    .repositories_client()
    .list(organization, project)
    .await?
    .value;

// 输出仓库名称
for repo in repos.iter() {
    println!("{}", repo.name);
}
println!("{} repos found", repos.len());

API 中的各个模块通过 Rust features 启用。

查看 Cargo.toml 的 features 部分以获取完整的功能列表。

示例应用程序 Cargo.toml 依赖规范,显示如何指定所需功能:

[dependencies]
...
azure_devops_rust_api = { version = "0.29.0", features = ["git", "pipelines"] }

示例

查看示例目录。

定义环境变量:

export ADO_ORGANIZATION=<organization-name>
export ADO_PROJECT=<project-name>

要运行示例,您需要通过以下方式提供认证凭据:

  • az CLI,您只需在运行示例之前通过运行 az login 进行认证。
  • 个人访问令牌 (PAT),通过环境变量 ADO_TOKEN 提供

    注意:个人访问令牌包含您在 Azure DevOps 中的安全凭据。 PAT 标识您、您可访问的组织以及访问范围。 因此,它们与密码一样关键,您应该以相同的方式对待它们。 创建 PAT 时,仅授予其所需的最小范围,并将过期时间设置得较短。

通过 cargo run --example 运行示例。您需要启用示例所需的 功能。如果您未指定必要的功能,您会收到有用的错误 消息。

示例:

cargo run --example git_repo_get --features="git" <repo-name>

问题报告

如果您发现任何问题,请通过 Github 提出。

完整示例代码

以下是一个完整的示例,演示如何使用 azure_devops_rust_api 库列出 Azure DevOps 项目中的所有 Git 仓库:

use azure_devops_rust_api::git;
use azure_identity::token_credentials::{AzureCliCredential, TokenCredential};
use std::env;
use std::error::Error;

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    // 获取认证凭据 - 使用 Azure CLI 凭据
    let credential = AzureCliCredential {};

    // 从环境变量获取组织名称和项目名称
    let organization = env::var("ADO_ORGANIZATION")
        .expect("Must define ADO_ORGANIZATION environment variable");
    let project = env::var("ADO_PROJECT")
        .expect("Must define ADO_PROJECT environment variable");

    // 创建 Git 客户端
    let git_client = git::ClientBuilder::new(credential).build();

    // 获取指定组织/项目中的所有仓库
    let repos = git_client
        .repositories_client()
        .list(&organization, &project)
        .await?
        .value;

    // 输出每个仓库的详细信息
    println!("Found {} repositories in project '{}':", repos.len(), project);
    for repo in repos.iter() {
        println!("----------------------------------------");
        println!("Name: {}", repo.name.as_deref().unwrap_or("Unknown"));
        println!("ID: {}", repo.id.as_deref().unwrap_or("Unknown"));
        println!("URL: {}", repo.url.as_deref().unwrap_or("Unknown"));
        println!("Default branch: {}", repo.default_branch.as_deref().unwrap_or("Unknown"));
        println!("Size: {} bytes", repo.size.unwrap_or(0));
    }

    Ok(())
}

要运行此示例,您需要:

  1. 在 Cargo.toml 中添加依赖:
[dependencies]
azure_devops_rust_api = { version = "0.29.0", features = ["git"] }
azure_identity = "0.1.0"
tokio = { version = "1.0", features = ["full"] }
  1. 设置环境变量:
export ADO_ORGANIZATION=your-organization-name
export ADO_PROJECT=your-project-name
  1. 确保已通过 Azure CLI 登录:
az login
  1. 运行程序:
cargo run

此示例展示了如何使用 azure_devops_rust_api 库进行基本的 Azure DevOps API 调用,实现高效的自动化任务管理。


1 回复

Rust Azure DevOps集成库azure_devops_rust_api使用指南

概述

azure_devops_rust_api是一个用于与Azure DevOps服务进行交互的Rust库。它提供了类型安全的API调用接口,支持高效地管理和自动化Azure DevOps中的各项任务,包括项目管理、版本控制、流水线管理和工作项跟踪等功能。

安装方法

在Cargo.toml中添加依赖:

[dependencies]
azure_devops_rust_api = "0.1"
tokio = { version = "1.0", features = ["full"] }

基本使用方法

1. 创建客户端实例

use azure_devops_rust_api::Client;
use std::env;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let personal_access_token = env::var("AZURE_DEVOPS_PAT")?;
    let organization = "your-organization-name";
    
    let client = Client::new(organization, personal_access_token);
    
    Ok(())
}

2. 获取项目列表

use azure_devops_rust_api::projects;

async fn list_projects(client: &Client) -> Result<(), Box<dyn std::error::Error>> {
    let projects_client = client.projects_client();
    let projects = projects_client.list().await?;
    
    for project in projects.value {
        println!("Project: {} - {}", project.name, project.description.unwrap_or_default());
    }
    
    Ok(())
}

3. 创建工作项

use azure_devops_rust_api::wit;
use serde_json::json;

async fn create_work_item(client: &Client, project: &str) -> Result<(), Box<dyn std::error::Error>> {
    let wit_client = client.wit_client();
    
    let work_item = json!([
        {
            "op": "add",
            "path": "/fields/System.Title",
            "value": "New bug report"
        },
        {
            "op": "add",
            "path": "/fields/System.Description",
            "value": "Detailed description of the issue"
        }
    ]);
    
    let result = wit_client
        .create(project, "Bug", work_item)
        .await?;
    
    println!("Created work item: {}", result.id);
    Ok(())
}

4. 触发构建流水线

use azure_devops_rust_api::build;

async fn trigger_build(client: &Client, project: &str, pipeline_id: i32) -> Result<(), Box<dyn std::error::Error>> {
    let build_client = client.build_client();
    
    let build_parameters = json!({
        "definition": {
            "id": pipeline_id
        },
        "parameters": {
            "configuration": "release",
            "platform": "x64"
        }
    });
    
    let build = build_client
        .queue_build(project, build_parameters)
        .await?;
    
    println!("Build queued: {}", build.id);
    Ok(())
}

高级功能示例

批量处理工作项

async fn batch_update_work_items(client: &Client, project: &str, item_ids: Vec<i32>) -> Result<(), Box<dyn std::error::Error>> {
    let wit_client = client.wit_client();
    
    let operations: Vec<serde_json::Value> = item_ids.iter().map(|&id| {
        json!({
            "op": "add",
            "path": format!("/{}/fields/System.State", id),
            "value": "Done"
        })
    }).collect();
    
    wit_client
        .update_work_items_batch(project, operations)
        .await?;
    
    println!("Updated {} work items", item_ids.len());
    Ok(())
}

监控构建状态

use std::time::{Duration, Instant};
use tokio::time::sleep;

async fn monitor_build(client: &Client, project: &str, build_id: i32) -> Result<(), Box<dyn std::error::Error>> {
    let build_client = client.build_client();
    let start_time = Instant::now();
    
    while start_time.elapsed() < Duration::from_secs(300) { // 5分钟超时
        let build = build_client.get_build(project, build_id).await?;
        
        match build.status.as_str() {
            "completed" => {
                println!("Build completed with result: {}", build.result.unwrap_or_default());
                break;
            }
            "inProgress" => {
                println!("Build in progress...");
                sleep(Duration::from_secs(10)).await;
            }
            _ => {
                println!("Build status: {}", build.status);
                sleep(Duration::from_secs(10)).await;
            }
        }
    }
    
    Ok(())
}

错误处理最佳实践

use azure_devops_rust_api::Error;

async fn safe_api_call(client: &Client) -> Result<(), Box<dyn std::error::Error>> {
    match client.projects_client().list().await {
        Ok(response) => {
            // 处理成功响应
            Ok(())
        }
        Err(Error::ApiError { status, body }) => {
            eprintln!("API error: Status {}, Body: {}", status, body);
            Err(Box::new(std::io::Error::new(
                std::io::ErrorKind::Other,
                "API call failed"
            )))
        }
        Err(e) => {
            eprintln!("Other error: {}", e);
            Err(Box::new(e))
        }
    }
}

环境变量配置

建议使用环境变量管理认证信息:

export AZURE_DEVOPS_PAT=your_personal_access_token
export AZURE_DEVOPS_ORG=your_organization_name

完整示例demo

use azure_devops_rust_api::Client;
use azure_devops_rust_api::{projects, wit, build};
use serde_json::json;
use std::env;
use std::time::{Duration, Instant};
use tokio::time::sleep;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 从环境变量获取认证信息
    let personal_access_token = env::var("AZURE_DEVOPS_PAT")?;
    let organization = env::var("AZURE_DEVOPS_ORG").unwrap_or_else(|_| "your-organization-name".to_string());
    
    // 创建客户端实例
    let client = Client::new(&organization, personal_access_token);
    
    // 示例1: 获取项目列表
    println!("=== 获取项目列表 ===");
    list_projects(&client).await?;
    
    // 示例2: 创建工作项
    println!("\n=== 创建工作项 ===");
    let project_name = "your-project-name"; // 替换为实际项目名称
    create_work_item(&client, project_name).await?;
    
    // 示例3: 触发构建流水线
    println!("\n=== 触发构建流水线 ===");
    let pipeline_id = 1; // 替换为实际流水线ID
    trigger_build(&client, project_name, pipeline_id).await?;
    
    // 示例4: 批量更新工作项状态
    println!("\n=== 批量更新工作项 ===");
    let item_ids = vec![1001, 1002, 1003]; // 替换为实际工作项ID
    batch_update_work_items(&client, project_name, item_ids).await?;
    
    Ok(())
}

// 获取项目列表函数
async fn list_projects(client: &Client) -> Result<(), Box<dyn std::error::Error>> {
    let projects_client = client.projects_client();
    let projects = projects_client.list().await?;
    
    println!("找到 {} 个项目:", projects.count);
    for project in projects.value {
        println!("项目: {} - {}", 
                project.name, 
                project.description.unwrap_or_default());
    }
    
    Ok(())
}

// 创建工作项函数
async fn create_work_item(client: &Client, project: &str) -> Result<(), Box<dyn std::error::Error>> {
    let wit_client = client.wit_client();
    
    // 创建工作项的JSON操作数组
    let work_item = json!([
        {
            "op": "add",
            "path": "/fields/System.Title",
            "value": "新的Bug报告"
        },
        {
            "op": "add",
            "path": "/fields/System.Description",
            "value": "问题的详细描述"
        },
        {
            "op": "add",
            "path": "/fields/System.AssignedTo",
            "value": "user@example.com"
        }
    ]);
    
    let result = wit_client
        .create(project, "Bug", work_item)
        .await?;
    
    println!("创建工作项成功: ID {}", result.id);
    Ok(())
}

// 触发构建流水线函数
async fn trigger_build(client: &Client, project: &str, pipeline_id: i32) -> Result<(), Box<dyn std::error::Error>> {
    let build_client = client.build_client();
    
    // 构建参数配置
    let build_parameters = json!({
        "definition": {
            "id": pipeline_id
        },
        "parameters": {
            "configuration": "release",
            "platform": "x64",
            "buildReason": "Manual"
        },
        "sourceBranch": "refs/heads/main"
    });
    
    let build = build_client
        .queue_build(project, build_parameters)
        .await?;
    
    println!("构建已加入队列: ID {}", build.id);
    
    // 监控构建状态
    monitor_build(client, project, build.id).await?;
    
    Ok(())
}

// 批量更新工作项函数
async fn batch_update_work_items(client: &Client, project: &str, item_ids: Vec<i32>) -> Result<(), Box<dyn std::error::Error>> {
    let wit_client = client.wit_client();
    
    // 为每个工作项创建更新操作
    let operations: Vec<serde_json::Value> = item_ids.iter().map(|&id| {
        json!({
            "op": "add",
            "path": format!("/{}/fields/System.State", id),
            "value": "Done"
        })
    }).collect();
    
    if !operations.is_empty() {
        wit_client
            .update_work_items_batch(project, operations)
            .await?;
        
        println!("成功更新 {} 个工作项状态为 'Done'", item_ids.len());
    }
    
    Ok(())
}

// 监控构建状态函数
async fn monitor_build(client: &Client, project: &str, build_id: i32) -> Result<(), Box<dyn std::error::Error>> {
    let build_client = client.build_client();
    let start_time = Instant::now();
    let timeout = Duration::from_secs(300); // 5分钟超时
    
    println!("开始监控构建 {} 的状态...", build_id);
    
    while start_time.elapsed() < timeout {
        let build = build_client.get_build(project, build_id).await?;
        
        match build.status.as_str() {
            "completed" => {
                let result = build.result.unwrap_or_default();
                println!("构建完成: 结果 - {}", result);
                return Ok(());
            }
            "inProgress" => {
                println!("构建进行中...");
                sleep(Duration::from_secs(15)).await;
            }
            "notStarted" => {
                println!("构建尚未开始...");
                sleep(Duration::from_secs(10)).await;
            }
            "cancelling" => {
                println!("构建正在取消...");
                sleep(Duration::from_secs(5)).await;
            }
            _ => {
                println!("构建状态: {}", build.status);
                sleep(Duration::from_secs(10)).await;
            }
        }
    }
    
    println!("构建监控超时");
    Ok(())
}

// 错误处理示例函数
async fn safe_api_call(client: &Client) -> Result<(), Box<dyn std::error::Error>> {
    use azure_devops_rust_api::Error;
    
    match client.projects_client().list().await {
        Ok(response) => {
            println!("成功获取 {} 个项目", response.count);
            Ok(())
        }
        Err(Error::ApiError { status, body }) => {
            eprintln!("API调用错误: 状态码 {}, 响应体: {}", status, body);
            Err(Box::new(std::io::Error::new(
                std::io::ErrorKind::Other,
                "API调用失败"
            )))
        }
        Err(Error::ReqwestError(e)) => {
            eprintln!("网络请求错误: {}", e);
            Err(Box::new(e))
        }
        Err(Error::SerdeError(e)) => {
            eprintln!("JSON解析错误: {}", e);
            Err(Box::new(e))
        }
        Err(e) => {
            eprintln!("其他错误: {}", e);
            Err(Box::new(e))
        }
    }
}

这个库提供了完整的Azure DevOps API覆盖,支持异步操作和类型安全的数据处理,是构建自动化工具和集成解决方案的理想选择。

回到顶部