追梦人物❤️包子 博主
一直走在追梦的路上。

Rust 项目从创建到发布

2025-03-16131 阅读0 评论

最近开始学习 Rust 编程,一直想找一个合适的项目练手,正好碰到一个需求,在 GitHub 也没有找到现成的工具,于是想着自己开发一个,并且将其开源到 GitHub,同时发布到 crates.io 上。

发布一个开源项目并不是简单地把代码传到 GitHub 就完事,它涵盖了从创建、开发、测试、文档、发布到版本迭代等多个环节,每一个环节都有相应工具帮助开发者高效地完成工作。这篇文章将分享一个 Rust 项目从创建到发布的整套流程及所用工具。

项目背景

我用 Supervisor 管理服务进程,期望进程崩溃时能收到飞书通知。Supervisor 的 Event Listener 机制可在进程状态改变时执行指定程序,例如发送飞书通知给监控人员。但我在 GitHub 上没找到现成工具,于是想着正好借此机会练习一下 Rust 开发。

在本文中,我将以该需求催生的 crashfeishu 项目为例,分享 Rust 项目从创建、开发、单元测试,到持续集成、发布及版本迭代的全流程,以及各环节中实用的工具,希望对 Rust 萌新开发者有所帮助。

注:这篇文章重点是 Rust 项目开发流程,无需了解示例项目的具体实现细节。

项目创建

我特别喜欢 Rust 的一点是项目全生命周期基本都能借助 Cargo 全家桶管理。

首先给项目取一个合适的名字,例如我的项目名为 crashfeishu,然后运行 cargo new 命令就可以创建项目:

cargo new crashfeishu --bin

由于 crashfeishu 是一个命令行工具,所以加了 --bin 参数,这样 Rust 将编译打包二进制可执行程序。如果项目是供其他 Rust 项目使用的基础库就无需加此参数。

功能开发

接下来便进入功能开发阶段,开发时应尽可能遵循 Rust 开发规范。Rust 工具链自带一系列与代码规范相关的实用工具,IDE 或者编辑器插件都已集成这些工具,无需复杂配置即可直接使用。我使用的是 Cursor,一个基于 VS Code 的 AI 编辑器,安装 rust-analyzer 插件后它就能自动格式化代码、实现代码补全以及 Lint 检查等功能。

开发过程中,还可以借助 AI 优化代码,让其更具 Rust 风格。以 crashfeishu 项目为例,有个辅助函数需要把 key1:value1 key2:value2 这种格式的字符串解析成 HashMap<String, String> 类型。由于我对 Rust API 不够熟悉,起初采用循环实现,Cursor 帮我将代码重构为基于 iterator 的实现方式:

type TokenSet = HashMap<String, String>;

fn parse_token_set(line: &str) -> TokenSet {
    line.trim()
        .split(' ')
        .filter(|s| !s.is_empty())
        .map(|pair| {
            let (k, v) = pair.split_once(':').unwrap();
            (k.to_string(), v.to_string())
        })
        .collect()
}

单元测试

在开发进程中,为保障代码质量,对于关键逻辑部分,应尽可能编写单元测试。Cargo 内置一套完整的测试框架,当完成测试代码的编写后,只需在命令行中执行cargo test指令,即可快速运行所有编写好的测试用例。

强烈推荐借助 AI 来生成单元测试代码。crashfeishu 项目中的单元测试代码几乎都是 AI 生成。个人体验下来,AI 生成的单元测试代码准确性非常高,基本无需进行大幅修改即可直接使用,大大节省编写测试代码的时间和精力。

集成测试

如果开发的是供其他 Rust 项目使用的基础库,在确保单元测试完善后基本可以准备编译发布了。但如果是命令行工具或服务,还需要测试其在真实环境中的运行情况。

crashfeishu 是一个命令行工具,功能比较简单,因此这部分测试我是手动完成的。我在 WSL 中搭建了 Supervisor 环境,部署一个 10 秒后自动崩溃的程序,并配置好开发的 Event Listener。10 秒后,成功收到进程崩溃的飞书通知,表明功能符合预期。接下来便可准备编译打包与发布。

编译打包

Cargo 集成了一整套完备的编译打包工具,借助它可以轻松完成项目的编译打包工作。如果要构建发布版本,只需在命令行中执行 cargo build --release 命令,Cargo 便会按照既定流程,将项目代码编译并打包成可交付使用的形式。

在实际项目中,依据具体需求,可能需要选择合适的目标编译平台,并同步安装该平台所需的必要依赖。例如 crashfeishu 的初期目标是在 Linux 环境下运行,为了兼容性和跨平台性,我选用 musl 工具链来进行静态编译,编译环境是 WSL Ubuntu 22.04,我需要运行如下命令完成编译打包:

sudo apt install musl-tools

rustup target add x86_64-unknown-linux-musl
cargo build --release --target x86_64-unknown-linux-musl

首先,通过 sudo apt install musl-tools 命令,在系统中安装 musl 工具链相关的必要软件包。接着使用 rustup target add x86_64-unknown-linux-musl 命令,添加针对 x86_64 目标平台的支持,使得 Rust 编译器能够针对该特定平台进行代码生成。最后执行 cargo build --release --target x86_64-unknown-linux-musl 命令,Cargo 便会以发布模式,针对指定的目标平台对项目进行编译打包,生成在 Linux 环境下具有良好兼容性和跨平台特性的可执行文件。

文档编写

开源项目,文档至关重要。Cargo 全家桶内置文档生成工具,运行 cargo doc 命令后,cargo 会根据代码中的文档注释自动生成 HTML 文档。

crashfeishu 是一个命令行工具,主要关注命令行文档。我使用的 clap 是 Rust 命令行参数解析最受欢迎的库,我只需要按规范写好 Rust 文档注释后,就会自动生成一套完善的命令行帮助文档。

比如像这样的参数文档注释:

#[derive(Parser, Debug)]
#[command(author = "jukanntenn <jukanntenn@outlook.com>", version)]
/// This event listener will push Feishu message when processes that are children of
/// supervisord transition unexpectedly to the EXITED state.
pub struct Args {
    /// Specify a supervisor process_name.
    ///
    /// Push Feishu notification when this process transitions to the EXITED state unexpectedly.
    /// If this process is part of a group, it can be specified using the 'group_name:process_name' syntax.
    /// This option can be specified multiple times, allowing for specification of multiple processes.
    /// If not specified, all processes will be monitored.
    #[arg(short, long)]
    pub program: Vec<String>,

    /// Specify a Feishu webhook URL to push notifications to.
    #[arg(short, long)]
    pub webhook: Option<String>,
}

就能生成如下命令行文档:

> crashfeishu --help
This event listener will push Feishu message when processes that are children of supervisord transition unexpectedly to the EXITED state

Usage: crashfeishu [OPTIONS]

Options:
  -p, --program <PROGRAM>
          Specify a supervisor process_name.

          Push Feishu notification when this process transitions to the EXITED state unexpectedly. If this process is part of a group, it can be specified using the 'group_name:process_name' syntax. This option can be specified multiple times, allowing for specification of multiple processes. If not specified, all processes will be monitored.

  -w, --webhook <WEBHOOK>
          Specify a Feishu webhook URL to push notifications to

发布 GitHub

完成上述工作后,开源项目通常会在 GitHub 发布版本。GitHub 发版流程如下:

  1. 使用 Git 提交代码,打版本标签并推送到 GitHub。
  2. 创建 GitHub Release 草稿并审核。
  3. 正式发布 GitHub Release。

手动操作整个流程非常繁琐,可以借助 GitHub Actions 实现自动化。不过,GitHub Actions 只有在代码推送到 GitHub 仓库时才会触发工作流任务,初次创建的工作流配置文件很可能存在错误,如果每次都推送到 GitHub 调试,会留下大量测试提交。

我使用 act 在本地环境模拟测试 GitHub Actions 工作流。act 是一个在 Docker 容器内运行 GitHub Actions 工作流的工具,它模拟 GitHub 的环境,让你在本地就能测试工作流,避免频繁推送代码到 GitHub 进行调试。

安装 act 后,可在本地运行以下命令测试工作流任务能否正确执行:

act push --eventpath <(echo '{"ref":"refs/tags/v0.1.0","repository":{"name":"crashfeishu","owner":{"login":"jukanntenn"}},"commits":[],"head_commit":{}}') --secret GITHUB_TOKEN=your_github_token

确认无误后,再正式提交到 GitHub 仓库。此后发布新版本,只需打版本标签并推送到 GitHub,GitHub Actions 就会自动完成编译打包、发布 GitHub Release 等操作。

发布 crates.io

还是 Cargo,它提供将项目编译打包后的成果发布至 crates.io 的功能。首次发布步骤如下:

  1. 使用 GitHub 账户登录 crates.io
  2. 获取 token
  3. 编辑 Cargo.toml,补充完善项目相关信息
  4. 执行如下命令将项目发布至 crates.io
cargo login your_token
cargo publish

发布结束后,最好回到 crates.io 网站进行确认,查看项目是否已成功发布。

实际使用验证

至此,一个完整的开源 Rust 项目便成功发布上线了。项目发布后,为确保其可用性与文档的准确性,强烈建议依照项目文档中【安装和使用】章节的指引,再次进行实际测试。通过这一环节,一方面能验证从安装步骤开始,整个流程是否顺畅无误;另一方面也能确认在实际使用过程中,用户能否依据文档说明,正确调用项目功能,实现预期效果,从而为使用者提供可靠的项目体验。

版本迭代

以上基础工作完成后,版本迭代将变得非常轻松,每当有新的版本需要发布,我们只需要:

  1. 开发和测试,更新文档
  2. 提交代码,打版本标签,push GitHub 仓库,GitHub Actions 将帮我们自动发布新的 Release
  3. 执行 cargo publish 发布 crates.io

总结

本文以 crashfeishu 项目为例,详细阐述了一个 Rust 项目从无到有,再到发布及后续迭代的全过程。从基于实际需求决定开发项目,到借助 Cargo 创建项目,在开发过程中遵循规范并使用工具如 Cursor 编辑器及 AI 辅助优化代码、编写单元测试;接着进行集成测试以确保项目在真实场景可用,再通过 Cargo 完成编译打包,并分别发布到 GitHub 和 crates.io 平台,最后强调实际使用验证及版本迭代的要点。整个流程展示了 Rust 生态中丰富的工具和便捷的开发、发布机制,希望能为 Rust 开发者,尤其是新手在项目实践方面提供全面且实用的参考,助力更多优秀 Rust 项目诞生。

参考链接

-- EOF --

0 评论
登录后回复