Bullseye是一个基于.NET的轻量级构建目标定义库,它允许开发者用C#代码直接定义构建任务,无需依赖复杂的外部构建工具,非常适合.NET生态下的项目构建需求。通过Bullseye,我们可以把编译、测试、打包、部署等步骤都定义为独立的构建目标,还能设置目标之间的执行顺序和依赖关系。

安装Bullseye依赖
首先需要在.NET项目中引入Bullseye的NuGet包,我们可以通过dotnet命令行或者NuGet包管理器来完成安装。以下是命令行安装的方式:
dotnet add package Bullseye
安装完成后,项目就可以使用Bullseye提供的API来定义构建目标了。
定义基础构建目标
Bullseye的核心是通过Targets类来定义和管理构建目标,我们可以使用Target方法添加单个目标,每个目标包含名称和对应的执行逻辑。下面是一个最简单的定义示例:
using Bullseye;
using System;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
// 定义构建目标
Targets.Target("hello", async () =>
{
Console.WriteLine("执行hello构建目标");
await Task.CompletedTask;
});
// 执行构建目标,默认执行第一个定义的目标,也可以通过命令行参数指定执行的目标
await Targets.RunAsync(args);
}
}
运行这个程序后,如果直接执行dotnet run,就会执行hello目标,输出对应的内容。如果需要在命令行指定执行的目标,可以运行dotnet run -- hello。
设置目标依赖关系
实际的构建流程中,很多任务是有先后顺序的,比如打包任务需要先执行编译任务,测试任务也需要先编译完成。Bullseye支持为目标设置依赖项,只有依赖的目标执行完成后,当前目标才会执行。我们可以通过Target方法的重载来设置依赖:
using Bullseye;
using System;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
// 定义编译目标
Targets.Target("build", async () =>
{
Console.WriteLine("执行项目编译");
await Task.Delay(1000); // 模拟编译耗时
Console.WriteLine("编译完成");
});
// 定义测试目标,依赖build目标
Targets.Target("test", async () =>
{
Console.WriteLine("执行项目测试");
await Task.Delay(500); // 模拟测试耗时
Console.WriteLine("测试完成");
}, "build");
// 定义打包目标,依赖build和test目标
Targets.Target("pack", async () =>
{
Console.WriteLine("执行项目打包");
await Task.Delay(800); // 模拟打包耗时
Console.WriteLine("打包完成");
}, "build", "test");
// 执行构建目标,指定执行pack目标时,会先执行build,再执行test,最后执行pack
await Targets.RunAsync(args);
}
}
当我们运行dotnet run -- pack时,执行顺序会是build -> test -> pack,Bullseye会自动处理依赖的执行顺序,不需要我们手动控制。
传递参数给构建目标
有时候构建任务需要接收外部参数,比如指定打包的版本号、输出目录等,Bullseye支持从命令行参数中读取自定义参数,我们可以在目标逻辑中获取这些参数。以下是参数传递的示例:
using Bullseye;
using System;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
Targets.Target("pack", async () =>
{
// 从命令行参数中获取version和output参数
var version = Targets.GetFlag("version") ?? "1.0.0";
var output = Targets.GetFlag("output") ?? "./output";
Console.WriteLine($"开始打包,版本号:{version},输出目录:{output}");
await Task.Delay(1000);
Console.WriteLine("打包完成");
});
await Targets.RunAsync(args);
}
}
运行时可以通过dotnet run -- pack --version 2.0.0 --output ./dist来传递参数,目标逻辑中就能获取到对应的值。
常用进阶用法
默认目标设置
如果希望不指定目标名称时默认执行某个目标,可以在RunAsync之前设置默认目标:
using Bullseye;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
Targets.Target("build", async () => { /* 编译逻辑 */ await Task.CompletedTask; });
Targets.Target("test", async () => { /* 测试逻辑 */ await Task.CompletedTask; }, "build");
// 设置默认执行test目标
Targets.Default("test");
await Targets.RunAsync(args);
}
}
并行执行无依赖目标
如果多个目标之间没有依赖关系,Bullseye默认会并行执行它们,提升构建效率,我们不需要额外做配置,只要确保目标之间没有设置依赖即可。
总结
Bullseye提供了非常简单直观的方式来定义.NET项目的构建目标,开发者可以用熟悉的C#代码来组织构建流程,不需要学习额外的构建脚本语法。无论是小型项目的简单构建任务,还是大型项目的复杂构建流程,都可以通过Bullseye灵活实现,有效降低构建配置的维护成本。