生产环境中会用到的工具及简单配置
上一篇简单说明了 rust 的基本安装 , 这一篇是常用开发工具的简单配置及自动化方案的分享
依赖检查
Cargo Deny 是 Rust 的一个工具,旨在帮助开发者管理和控制项目依赖项,特别是帮助防止引入不安全的、过时的或不符合项目要求的 crate。它通过检查 Cargo.toml 和 Cargo.lock 文件中的依赖关系,并与设定的规则进行对比,从而提高项目的安全性和合规性。
安装
首先,确保你已经安装了 Rust(可以参考专栏中之前的教程)。然后,你可以通过 cargo 来安装 cargo deny:
$ cargo install cargo-deny
此命令会安装 cargo deny 工具,并将其添加到你的 PATH 中。安装完成后,你可以通过以下命令验证安装是否成功:
$ cargo deny --version
配置文件
在成功安装了 deny 之后可以通过 init 初始化配置文件
$ cargo deny init
上面的指令会在项目目录下创建一个 deny.toml 文件 , 里面包含缺省配置 , 通常来讲我们只需要修改 allow 字段的内容就可以了 , 打开deny.toml 文件并找到 allow 字段 , 按需修改其中的内容 , 例如:
[licenses]
allow = [
"MIT",
"Apache-2.0",
"Unicode-DFS-2016",
"MPL-2.0",
"BSD-2-Clause",
"BSD-3-Clause",
"ISC",
"CC0-1.0",
"Unicode-3.0"
]
现在就可以使用 cargo deny 进行检查了
$ cargo deny check
当 allow 中的许可没有没遇到的时候会出现类似下面这样的 wraning
warning[license-not-encountered]: license was not encountered
┌─ /Users/wuzexian/codes/rust_project/rust_demo/deny.toml:95:4
│
95 │ "Unicode-DFS-2016",
│ ━━━━━━━━━━━━━━━━ unmatched license allowance
可以通过 unused-allowed-license 设置未使用的 license 不再 "wran" 而是 "allow"
[licenses]
unused-allowed-license = "allow" # defult wran
allow = [..]
拼写检查
安装
首先,确保你已经安装了 Rust 环境。如果尚未安装 Rust,请访问 Rust 官网 进行安装。
然后,使用以下命令通过 cargo 安装 cargo typos 工具:
$ cargo install typos-cli
安装完成后,您可以通过以下命令验证是否成功安装:
$ typos --version
如果安装成功,命令会输出 cargo-typos 的版本号。
使用
一旦安装完成,你就可以使用 cargo typos 来检查项目中的拼写错误了。在项目根目录下运行以下命令:
$ typos
这会扫描项目中的源代码(包括 .rs 文件),并报告任何拼写错误。输出内容会列出拼写错误的单词和位置,例如:
error: possible typo in documentation: "recieve" should be "receive"
--> src/lib.rs:10:5
|
10 | // This function will recieve the value
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `cargo typos` suggests replacing with "receive"
在此输出中,cargo typos 会列出错误的单词(如 "recieve"),并且还会给出一个建议的更正(如 "receive")。
忽略
有的时候我们代码中会有 "故意错误" 的单词 , 或者不想进行拼写检查的文件 , 可以同意typos.toml进行配置
[default.extend-words]
teh = "teh" # 不纠正 teh
[files]
# 不纠正某些文件
extend-exclude = ["README.md", "LICENSECHANGELOG.md", "notebooks/*"]
NEXTEST
nextest 是 rust 下一代的 "test runner" , 界面干净简介 , 最重要的是比 cargo test 快 3 倍
安装
首先,确保你已经安装了 Rust 环境。如果尚未安装 Rust,请访问 Rust 官网 进行安装。
然后,使用以下命令通过 cargo 安装 nextest
$ cargo install cargo-nextest
在需要测试的时候使用 nextest 代替 test即可
$ cargo nextest run
日志文件生成
git-cliff 可以通过使用传统的提交以及regex驱动的自定义解析器从Git历史记录中生成更新日志文件。用于自动生成 CHANGELOG 文件
安装
首先,确保你已经安装了 Rust 环境。如果尚未安装 Rust,请访问 Rust 官网 进行安装。
然后,使用以下命令通过 cargo 安装 git-cliff
$ cargo install git-cliff
配置
git-ciff 的配置需要在根目录下有 cliff.toml 文件 , rust 项目中可以通过 metadata table在 cargo.toml 中直接配置
[package]
name = "..."
[dependencies]
# ...
# 配置 git-cliff 的 Changelog 生成器
[package.metadata.git-cliff.changelog]
# 定义 Changelog 文件的头部内容
header = """
# 更新日志\n
所有显著的变化将记录在此文件中。请参阅 [常规提交](https://www.conventionalcommits.org/) 规范以了解提交指南。\n
"""
# 定义 Changelog 正文的模板,使用 Tera 模板语言
body = """
---
{% if version %}\
{% if previous.version %}\
## [{{ version | trim_start_matches(pat="v") }}]($REPO/compare/{{ previous.version }}..{{ version }}) - {{ timestamp | date(format="%Y-%m-%d") }}
{% else %}\
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
{% endif %}\
{% else %}\
## [未发布]
{% endif %}\
{% for group, commits in commits | group_by(attribute="group") %}
### {{ group | striptags | trim | upper_first }}
{% for commit in commits
| filter(attribute="scope")
| sort(attribute="scope") %}
- **({{commit.scope}})**{% if commit.breaking %} [**破坏性更改**]{% endif %} \
{{ commit.message|trim }} - ([{{ commit.id | truncate(length=7, end="") }}]($REPO/commit/{{ commit.id }})) - {{ commit.author.name }}
{%- endfor -%}
{% raw %}\n{% endraw %}\
{%- for commit in commits %}
{%- if commit.scope -%}
{% else -%}
- {% if commit.breaking %} [**破坏性更改**]{% endif %}\
{{ commit.message|trim }} - ([{{ commit.id | truncate(length=7, end="") }}]($REPO/commit/{{ commit.id }})) - {{ commit.author.name }}
{% endif -%}
{% endfor -%}
{% endfor %}\n
"""
# 定义 Changelog 文件的尾部内容
footer = """
<!-- 由 git-cliff 生成 -->
"""
# 移除模板字符串首尾的空白字符
trim = true
# 定义 postprocessors,用于替换模板中的变量或模式
postprocessors = [
# 替换 $REPO 为实际的仓库地址
{ pattern = '\$REPO', replace = "" }, # 替换仓库 URL
]
[package.metadata.git-cliff.git]
# 是否解析遵循 conventional commits 规范的提交
conventional_commits = true
# 是否过滤掉非 conventional commits 规范的提交
filter_unconventional = false
# 是否将每个提交的每个正文行作为单独的提交处理
split_commits = false
# 提交消息的预处理正则表达式列表
commit_preprocessors = [
# 替换 Issue 编号为链接形式
# { pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](https://github.com/orhun/git-cliff/issues/${2}))" },
]
# 解析和分组提交的正则表达式列表
commit_parsers = [
# 跳过
{ message = "\\[skip", skip = true },
# 包含任何中文跳过
# { message = "\\p{Han}", skip = true },
# feat 开头放入特性分类
{ message = "^feat", group = "feat" },
# fix 开头放入 bug 修复分类
{ message = "^fix", group = "fix bug" },
# doc 开头放入文档分类
{ message = "^doc", group = "document" },
# perf 开头放入性能分类
{ message = "^perf", group = "perf" },
# refactor 放入重构分类
{ message = "^refactor", group = "refactor" },
# style 开头放入样式分类
{ message = "^style", group = "style" },
# revert 放入还原复原分类
{ message = "^revert", group = "revert" },
# test 放入测试分类
{ message = "^test", group = "tests" },
# 以 chore: 开头,跳过这条提交
{ message = "^chore:", skip = true },
# 包含 security 安全修复
{ body = ".*security", group = "security" },
# 不匹配的其他内容归入 Other
{ message = ".*", group = "others" },
]
# 是否保护破坏性更改不被跳过
protect_breaking_commits = false
# 是否过滤掉不符合 commit parsers 的提交
filter_commits = false
# 匹配 git 标签的正则表达式
tag_pattern = "v[0-9].*"
# 跳过匹配的标签
skip_tags = "v0.1.0-beta.1"
# 忽略匹配的标签
ignore_tags = ""
# 是否按照拓扑排序排序标签
topo_order = false
# 小节内提交的排序方式,"oldest" 或 "newest"
sort_commits = "oldest"
# 限制在 Changelog 中包含的提交数量
# limit_commits = 42
此时使用 git cliff -o CHANGELOG.md 即可自动根据git 的提交历史生成CHANGELOG.md 文件 ,例如进行了两次提交 , 第一次commit 的是"first commit: init" ,第二次是"fix : fix unused warning" , 并打了个0.1.1的 tag , 最终生成如下:
# 更新日志 Change log
所有显著的变化将记录在此文件中。请参阅 [常规提交](https://www.conventionalcommits.org/) 规范以了解提交指南。
All notable changes to this project will be documented in this file. See [conventional commits](https://www.conventionalcommits.org/) for commit guidelines.
---
## [0.1.1] - 2025-01-03
### Fix bug
- fix : fix unused warning - ([9560718](https://github.com/WITstudio86//commit/956071822239ee41896a95199bce8187f99a5995)) - WITstudio
### others
- first commit: init - ([7c97ec1](https://github.com/WITstudio86//commit/7c97ec1228e0ce282a9bbc3c5547070272a67c36)) - WITstudio
<!-- 由 git-cliff 生成 -->
自动化
自动化执行流程,在每次 Git 提交之前执行 cargo fmt、cargo deny、nextest、typos 和 git-cliff,可以使用 Git 钩子来实现。Git 钩子(git hooks)是 Git 提供的一种机制,可以在特定的 Git 操作(如提交、推送、合并等)之前或之后执行自定义脚本。
使用pre-commit
我们可以使用 pre-commit 钩子来在每次提交之前自动执行这些任务。如果它们都通过了,提交才会继续进行。以下是如何配置和实现这一流程:
安装
先通过pip 安装 pre-commit , 这需要电脑中存在 pip 工具 , 需要安装 python
$ pip install pre-commit
和之前其他工具一样 ,安装之后可以通过--version 检查安装是否成功
配置
在 .pre-commit-config.yaml 文件中,配置你要执行的所有工具。
# 如果检测到任何钩子失败,pre-commit 将不会继续执行剩余的钩子。
fail_fast: false
# repos 是一个钩子仓库的列表,每个仓库可以包含多个钩子。
repos:
# 每个仓库通过 URL 指定,并且可以指定特定的版本(rev)。
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.3.0
hooks:
# 这是从上述仓库中定义的钩子列表。
- id: check-byte-order-marker # 检查文件是否包含字节顺序标记(BOM)。
- id: check-case-conflict # 检查文件名在不同操作系统的大小写冲突。
- id: check-merge-conflict # 检查文件中是否有合并冲突。
- id: check-symlinks # 检查文件是否是符号链接。
- id: check-yaml # 检查 YAML 文件的格式。
- id: end-of-file-fixer # 确保文件以单个换行符结束。
- id: mixed-line-ending # 检查文件的行结束符是否一致。
- id: trailing-whitespace # 检查并修复行尾的空格。
# local 部分定义了本地钩子。
- repo: local
hooks:
# 每个钩子有以下属性:
# id: 钩子的唯一标识符。
# name: 钩子的名称。
# description: 钩子的描述。
# entry: 要执行的命令。
# language: 钩子运行的语言环境。
# files: 钩子应该运行的文件模式。
# args: 传递给钩子的参数列表。
# pass_filenames: 如果设置为 false,pre-commit 将不会传递文件名给钩子脚本。
- id: cargo-fmt
name: cargo fmt
description: Format files with rustfmt.
entry: bash -c 'cargo fmt -- --check'
language: rust
files: \.rs$ # 钩子仅对 Rust 源文件生效。
args: [] # 不传递额外的参数。
- .......
- ......
cargo make
pre-commit 本身是按照顺序执行某些特定的指令 , fail_fast 配置在出错的时候是否继续执行 , cargo make 可以实现定义多个子指令 , 并将他们组合,配置依赖 , 轻松的组合成为很多不同的自动化脚本
安装
首先,确保你已经安装了 Rust 环境。如果尚未安装 Rust,请访问 Rust 官网 进行安装。
然后,使用以下命令通过 cargo 安装 cargo make
$ cargo install --force cargo-make
使用
我们需要使用一个Makefile.toml 文件对cargo make 进行配置 , 配置很简单,
[tasks.<name>]配置不同任务的别名command设置要执行的指令args设置传递的参数dependencies用于设置依赖 , 说明当前任务需要依赖于哪个任务的成功install_crate可以帮助下载需要的 crate
下面是一个实例:
[tasks.format]
install_crate="rustfmt"
command = "cargo"
args = ["fmt", "--", "--emit=files"]
[tasks.clean]
command = "cargo"
args = ["clean"]
[tasks.build]
command = "cargo"
args = ["build"]
dependencies = ["clean"]
[tasks.test]
command = "cargo"
args = ["test"]
dependencies = ["clean"]
[tasks.my-flow]# 下面指令执行时的my-flow是在这里定义的别名
dependencies = [
"format",
"build",
"test"
]
在使用的时候只需要执行下面的指令即可:
$ cargo make my-flow
下面是对于本篇所说到的所有工具的自动化执行配置:
[tasks.format]
command = "cargo"
args = ["fmt", "--", "--emit=files"]
[tasks.deny]
install_crate="cargo-deny"
command = "cargo"
args = ["deny" , "check"]
[tasks.typos]
install_crate="typos-cli"
command = "typos"
dependencies = ["deny"]
[tasks.check]
command = "cargo"
args = ["check" , "--all"]
dependencies = ["typos"]
[tasks.clippy]# 一种代码风格检查工具
command = "cargo"
args = ["clippy" , "--all-features" , "--tests" , "--benches" , "--", "-D" , "warnings"]
dependencies = ["check"]
[tasks.test]
install_crate="cargo-nextest"
command = "cargo"
args = ["nextest" , "run"]
dependencies = ["clippy"]
[tasks.add]
command = "git"
args = ["add" , "."]
dependencies = ["test"]
[tasks.commit]
command = "git"
args = ["commit" , "-a"]
dependencies = ["add"]
[tasks.cliff]
install_crate="git-cliff"
command = "git"
args = ["cliff" , "-o" , "CHANGELOG.md"]
dependencies = ["commit"]
[tasks.doit]
dependencies = [
"format",
"deny",
"typos",
"check",
"clippy",
"test",
"commit",
"cliff"
]
Rust 项目 CI/CD 配置
(25/1/8 更新)
CI/CD 是现代软件开发中常用的自动化方法,用于提高开发效率、减少人为错误,并确保软件质量。CI/CD 包括两个主要部分:持续集成(CI)和持续交付/部署(CD)。
GitHub Actions 是 GitHub 提供的一项持续集成和持续部署(CI/CD)服务,它允许开发者直接在 GitHub 仓库内创建和管理自动化工作流。GitHub Actions 使得开发者能够在代码提交、拉取请求、发布版本等事件发生时自动执行一系列任务,例如构建、测试、部署等。
下面是一个简单的GitHub Actions 配置文件,来实现对 Rust 项目的持续集成(CI)和持续交付(CD). 这个配置文件会在 GitHub 上的每次提交、拉取请求以及标签发布时自动运行 Rust 代码的格式检查、静态分析、测试、发布变更日志,并在版本标签发布时发布新的 GitHub Release。
首先,在你的 GitHub 仓库中创建一个工作流文件,这个文件将定义 CI/CD 任务。
- 在仓库根目录下创建
.github/workflows文件夹。 - 在该文件夹中创建一个新的文件,例如
build.yml,并将以下配置粘贴进去。
name: build
on:
push:
branches:
- main # 当代码推送到 main 分支时触发工作流
tags:
- v* # 当发布版本标签(例如 v1.0.0)时触发工作流
pull_request:
branches:
- master # 当拉取请求指向 master 分支时触发工作流
permissions:
contents: write # 允许访问仓库内容
jobs:
build-rust:
strategy:
matrix:
platform: [ubuntu-latest] # 当前只使用 Ubuntu 环境,你也可以添加其他平台
runs-on: ${{ matrix.platform }} # 指定虚拟环境为 Ubuntu
steps:
- uses: actions/checkout@v4 # 检出代码
with:
fetch-depth: 0 # 提取完整的提交历史
submodules: recursive # 提取子模块
- name: Install Rust
run: rustup toolchain install stable --component llvm-tools-preview # 安装 Rust 稳定版本,并添加 llvm-tools-preview 组件
- name: Install cargo-llvm-cov
uses: taiki-e/install-action@cargo-llvm-cov # 安装 cargo-llvm-cov,用于 Rust 代码覆盖率
- name: Install nextest
uses: taiki-e/install-action@nextest # 安装 nextest,用于快速运行 Rust 测试
- uses: Swatinem/rust-cache@v2 # 缓存 Rust 构建依赖
- name: Check code format
run: cargo fmt -- --check # 检查代码格式
- name: Check the package for errors
run: cargo check --all # 检查 Rust 项目的错误
- name: Lint rust sources
run: cargo clippy --all-targets --all-features --tests --benches -- -D warnings # 使用 Clippy 进行代码检查
- name: Execute rust tests
run: cargo nextest run --all-features # 执行所有的 Rust 测试
- name: Generate a changelog
uses: orhun/git-cliff-action@v2 # 生成变更日志
id: git-cliff
if: startsWith(github.ref, 'refs/tags/') # 仅在标签推送时执行
with:
config: cliff.toml # 配置文件
args: -vv --latest --strip header
env:
OUTPUT: CHANGES.md # 输出变更日志到 CHANGES.md 文件
- name: Release
uses: softprops/action-gh-release@v1 # 自动发布 GitHub Release
if: startsWith(github.ref, 'refs/tags/') # 仅在标签推送时执行
with:
body: ${{ steps.git-cliff.outputs.content }} # 使用生成的变更日志作为 Release 的内容
解释
触发条件(on)
-
push:branches: 当代码推送到main分支时触发。tags: 当创建符合v*格式(如v1.0.0)的标签时触发。
-
pull_request:branches: 当创建指向master分支的拉取请求时触发。
权限(permissions)
contents: write: 允许 GitHub Actions 写入仓库的内容,通常用于推送新的发布版本。
作业(jobs)
这个工作流包含一个名为 build-rust 的作业,它将在指定的平台(此例中是 ubuntu-latest)上运行。
步骤(steps)
- Checkout代码:使用
actions/checkout检出代码,并配置提取完整的提交历史和递归获取子模块。 - 安装 Rust 工具链:通过
rustup安装 Rust 的稳定版本。 - 安装工具:安装一些常用的 Rust 工具,如
cargo-llvm-cov和nextest。 - Rust 缓存:使用
Swatinem/rust-cache缓存构建依赖,以提高构建速度。 - 格式检查:使用
cargo fmt检查 Rust 代码的格式是否符合规范。 - 编译检查:使用
cargo check检查 Rust 项目中是否有编译错误。 - 代码质量检查:使用
cargo clippy进行静态代码分析,检查潜在的代码问题。 - 执行测试:使用
cargo nextest运行所有测试。 - 生成变更日志:使用
git-cliff-action生成项目的变更日志,只在标签发布时执行。 - 发布 GitHub Release:在标签发布时,使用
action-gh-release发布 GitHub Release,并将生成的变更日志作为 Release 的内容。
使用
- 推送到
main分支:- 当你将代码推送到
main分支时,CI 流程会执行所有步骤,但不会发布 Release。
- 当你将代码推送到
- 创建新标签:
- 当你发布一个版本标签(如
v1.0.0)时,CI 流程将执行所有步骤,并且还会生成变更日志,并发布新的 GitHub Release。
- 当你发布一个版本标签(如
- 创建拉取请求:
- 当创建指向
master分支的拉取请求时,CI 流程将执行所有步骤,但不会发布 Release。
- 当创建指向
从模板新建
经过刚才的配置 , 现在的项目目录看起来应该像是下面这样:
.
├── CHANGELOG.md
├── Cargo.toml
├── Makefile.toml
├── deny.toml
├── README.md
├── src
│ └── main.rs
└── typos.toml
generate 让我们可以将这个项目目录作为模本使用 , 首先将这个项目 push到 github , 然后下载 generate 并通过它创建一个新的项目
$ cargo install cargo-generate
$ cargo generate --git 模板的github地址
视频版: 小破站