forked from actions/act_runner
Compare commits
1 Commits
54308690d0
...
main
Author | SHA1 | Date | |
---|---|---|---|
f58a6daa6c |
2
Makefile
2
Makefile
@ -103,7 +103,7 @@ fmt-check:
|
|||||||
fi;
|
fi;
|
||||||
|
|
||||||
test: fmt-check
|
test: fmt-check
|
||||||
@$(GO) test -v -cover -coverprofile coverage.txt ./... && echo "\n==>\033[32m Ok\033[m\n" || exit 1
|
@$(GO) test -v -cover -coverprofile coverage.txt ./... && echo -e "\n===> \e[32mOk\e[m\n" || exit 1
|
||||||
|
|
||||||
.PHONY: vet
|
.PHONY: vet
|
||||||
vet:
|
vet:
|
||||||
|
@ -261,7 +261,7 @@ func registerInteractive(ctx context.Context, configFile string, regArgs *regist
|
|||||||
}
|
}
|
||||||
|
|
||||||
if stage <= StageUnknown {
|
if stage <= StageUnknown {
|
||||||
log.Errorf("无效输入,请重新运行 act 命令。")
|
log.Errorf("无效输入,请重新运行命令。")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -307,7 +307,7 @@ func registerNoInteractive(ctx context.Context, configFile string, regArgs *regi
|
|||||||
log.Infof("运行器名称为空,使用主机名 '%s'。", inputs.RunnerName)
|
log.Infof("运行器名称为空,使用主机名 '%s'。", inputs.RunnerName)
|
||||||
}
|
}
|
||||||
if err := inputs.validate(); err != nil {
|
if err := inputs.validate(); err != nil {
|
||||||
log.WithError(err).Errorf("无效输入,请重新运行 act 命令。")
|
log.WithError(err).Errorf("无效输入,请重新运行命令。")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := doRegister(ctx, cfg, inputs); err != nil {
|
if err := doRegister(ctx, cfg, inputs); err != nil {
|
||||||
|
@ -11,9 +11,9 @@ import (
|
|||||||
|
|
||||||
func TestRegisterNonInteractiveReturnsLabelValidationError(t *testing.T) {
|
func TestRegisterNonInteractiveReturnsLabelValidationError(t *testing.T) {
|
||||||
err := registerNoInteractive(t.Context(), "", ®isterArgs{
|
err := registerNoInteractive(t.Context(), "", ®isterArgs{
|
||||||
Labels: "label:invalid",
|
Labels: "标签:无效",
|
||||||
Token: "token",
|
Token: "token",
|
||||||
InstanceAddr: "http://localhost:3000",
|
InstanceAddr: "http://localhost:3000",
|
||||||
})
|
})
|
||||||
assert.Error(t, err, "unsupported schema: invalid")
|
assert.Error(t, err, "不支持的标签: 无效")
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ import (
|
|||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_generateWorkflow(t *testing.T) {
|
func Test_生成工作流(t *testing.T) {
|
||||||
type args struct {
|
type args struct {
|
||||||
task *runnerv1.Task
|
task *runnerv1.Task
|
||||||
}
|
}
|
||||||
@ -24,32 +24,32 @@ func Test_generateWorkflow(t *testing.T) {
|
|||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "has needs",
|
name: "有需求",
|
||||||
args: args{
|
args: args{
|
||||||
task: &runnerv1.Task{
|
task: &runnerv1.Task{
|
||||||
WorkflowPayload: []byte(`
|
WorkflowPayload: []byte(`
|
||||||
name: Build and deploy
|
name: 构建部署测试
|
||||||
on: push
|
on: push
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
job9:
|
job9:
|
||||||
needs: build
|
needs: build
|
||||||
runs-on: ubuntu-latest
|
runs-on: linux-loong64
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
- run: ./deploy --build ${{ needs.job1.outputs.output1 }}
|
- run: ./deploy --build ${{ needs.job1.outputs.output1 }}
|
||||||
- run: ./deploy --build ${{ needs.job2.outputs.output2 }}
|
- run: ./deploy --build ${{ needs.job2.outputs.output2 }}
|
||||||
`),
|
`),
|
||||||
Needs: map[string]*runnerv1.TaskNeed{
|
Needs: map[string]*runnerv1.TaskNeed{
|
||||||
"job1": {
|
"job1": {
|
||||||
Outputs: map[string]string{
|
Outputs: map[string]string{
|
||||||
"output1": "output1 value",
|
"output1": "输出1值",
|
||||||
},
|
},
|
||||||
Result: runnerv1.Result_RESULT_SUCCESS,
|
Result: runnerv1.Result_RESULT_SUCCESS,
|
||||||
},
|
},
|
||||||
"job2": {
|
"job2": {
|
||||||
Outputs: map[string]string{
|
Outputs: map[string]string{
|
||||||
"output2": "output2 value",
|
"output2": "输出2值",
|
||||||
},
|
},
|
||||||
Result: runnerv1.Result_RESULT_SUCCESS,
|
Result: runnerv1.Result_RESULT_SUCCESS,
|
||||||
},
|
},
|
||||||
|
@ -36,7 +36,7 @@ func Parse(str string) (*Label, error) {
|
|||||||
label.Arg = splits[2]
|
label.Arg = splits[2]
|
||||||
}
|
}
|
||||||
if label.Schema != SchemeHost && label.Schema != SchemeDocker {
|
if label.Schema != SchemeHost && label.Schema != SchemeDocker {
|
||||||
return nil, fmt.Errorf("不支持的 schema: %s", label.Schema)
|
return nil, fmt.Errorf("不支持的标签: %s", label.Schema)
|
||||||
}
|
}
|
||||||
return label, nil
|
return label, nil
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ import (
|
|||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestParse(t *testing.T) {
|
func Test解析(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
args string
|
args string
|
||||||
want *Label
|
want *Label
|
||||||
|
@ -19,122 +19,133 @@ import (
|
|||||||
"git.whlug.cn/LAA/loong_runner/internal/pkg/client/mocks"
|
"git.whlug.cn/LAA/loong_runner/internal/pkg/client/mocks"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestReporter_parseLogRow(t *testing.T) {
|
func Test记录器_解析输出日志(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string // 测试用例名称
|
||||||
debugOutputEnabled bool
|
debugOutputEnabled bool // 是否启用调试输出
|
||||||
args []string
|
args []string // 输入的日志行
|
||||||
want []string
|
want []string // 期望的输出结果
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"No command", false,
|
name: "无命令",
|
||||||
[]string{"Hello, world!"},
|
debugOutputEnabled: false,
|
||||||
[]string{"Hello, world!"},
|
args: []string{"你好,世界!"},
|
||||||
|
want: []string{"你好,世界!"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Add-mask", false,
|
name: "添加掩码",
|
||||||
[]string{
|
debugOutputEnabled: false,
|
||||||
"foo mysecret bar",
|
args: []string{
|
||||||
"::add-mask::mysecret",
|
"foo 我的密钥 bar", // 输入日志:普通日志行
|
||||||
"foo mysecret bar",
|
"::add-mask::我的密钥", // 输入命令:添加掩码
|
||||||
|
"foo 我的密钥 bar", // 输入日志:再次普通日志行
|
||||||
},
|
},
|
||||||
[]string{
|
want: []string{
|
||||||
"foo mysecret bar",
|
"foo 我的密钥 bar", // 原始日志直接输出
|
||||||
"<nil>",
|
"<nil>", // 添加掩码命令处理结果(无输出内容)
|
||||||
"foo *** bar",
|
"foo *** bar", // 掩码替换后的日志行
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Debug enabled", true,
|
name: "启用调试",
|
||||||
[]string{
|
debugOutputEnabled: true,
|
||||||
"::debug::GitHub Actions runtime token access controls",
|
args: []string{
|
||||||
|
"::debug::GitHub Actions 运行时令牌访问控制",
|
||||||
},
|
},
|
||||||
[]string{
|
want: []string{
|
||||||
"GitHub Actions runtime token access controls",
|
"GitHub Actions 运行时令牌访问控制", // 调试信息直接输出
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Debug not enabled", false,
|
name: "禁用调试",
|
||||||
[]string{
|
debugOutputEnabled: false,
|
||||||
"::debug::GitHub Actions runtime token access controls",
|
args: []string{
|
||||||
|
"::debug::GitHub Actions 运行时令牌访问控制",
|
||||||
},
|
},
|
||||||
[]string{
|
want: []string{
|
||||||
"<nil>",
|
"<nil>", // 调试信息被忽略
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"notice", false,
|
name: "通知",
|
||||||
[]string{
|
debugOutputEnabled: false,
|
||||||
"::notice file=file.name,line=42,endLine=48,title=Cool Title::Gosh, that's not going to work",
|
args: []string{
|
||||||
|
"::notice file=文件.name,line=42,endLine=48,title=酷标题::天啊,这行不通",
|
||||||
},
|
},
|
||||||
[]string{
|
want: []string{
|
||||||
"::notice file=file.name,line=42,endLine=48,title=Cool Title::Gosh, that's not going to work",
|
"::notice file=文件.name,line=42,endLine=48,title=酷标题::天啊,这行不通", // 通知日志原样输出
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"warning", false,
|
name: "警告",
|
||||||
[]string{
|
debugOutputEnabled: false,
|
||||||
"::warning file=file.name,line=42,endLine=48,title=Cool Title::Gosh, that's not going to work",
|
args: []string{
|
||||||
|
"::warning file=文件.name,line=42,endLine=48,title=酷标题::天啊,这行不通",
|
||||||
},
|
},
|
||||||
[]string{
|
want: []string{
|
||||||
"::warning file=file.name,line=42,endLine=48,title=Cool Title::Gosh, that's not going to work",
|
"::warning file=文件.name,line=42,endLine=48,title=酷标题::天啊,这行不通", // 警告日志原样输出
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"error", false,
|
name: "错误",
|
||||||
[]string{
|
debugOutputEnabled: false,
|
||||||
"::error file=file.name,line=42,endLine=48,title=Cool Title::Gosh, that's not going to work",
|
args: []string{
|
||||||
|
"::error file=文件.name,line=42,endLine=48,title=酷标题::天啊,这行不通",
|
||||||
},
|
},
|
||||||
[]string{
|
want: []string{
|
||||||
"::error file=file.name,line=42,endLine=48,title=Cool Title::Gosh, that's not going to work",
|
"::error file=文件.name,line=42,endLine=48,title=酷标题::天啊,这行不通", // 错误日志原样输出
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"group", false,
|
name: "分组",
|
||||||
[]string{
|
debugOutputEnabled: false,
|
||||||
"::group::",
|
args: []string{
|
||||||
"::endgroup::",
|
"::group::", // 开始分组
|
||||||
|
"::endgroup::", // 结束分组
|
||||||
},
|
},
|
||||||
[]string{
|
want: []string{
|
||||||
"::group::",
|
"::group::", // 分组开始标记原样输出
|
||||||
"::endgroup::",
|
"::endgroup::", // 分组结束标记原样输出
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"stop-commands", false,
|
name: "停止命令",
|
||||||
[]string{
|
debugOutputEnabled: false,
|
||||||
"::add-mask::foo",
|
args: []string{
|
||||||
"::stop-commands::myverycoolstoptoken",
|
"::add-mask::foo", // 添加掩码命令
|
||||||
"::add-mask::bar",
|
"::stop-commands::我的停止令牌", // 停止命令标记
|
||||||
"::debug::Stuff",
|
"::add-mask::bar", // 被忽略的添加掩码命令
|
||||||
"myverycoolstoptoken",
|
"::debug::调试信息", // 被忽略的调试信息
|
||||||
"::add-mask::baz",
|
"我的停止令牌", // 停止命令标记结束
|
||||||
"::myverycoolstoptoken::",
|
"::add-mask::baz", // 恢复处理的添加掩码命令
|
||||||
"::add-mask::wibble",
|
"::我的停止令牌::", // 另一种停止命令标记
|
||||||
"foo bar baz wibble",
|
"::add-mask::wibble", // 被忽略的添加掩码命令
|
||||||
|
"foo bar baz wibble", // 普通日志行
|
||||||
},
|
},
|
||||||
[]string{
|
want: []string{
|
||||||
"<nil>",
|
"<nil>", // 第一个添加掩码命令处理结果
|
||||||
"<nil>",
|
"<nil>", // 停止命令标记处理结果
|
||||||
"::add-mask::bar",
|
"::add-mask::bar", // 被忽略的命令原样输出
|
||||||
"::debug::Stuff",
|
"::debug::调试信息", // 被忽略的调试信息原样输出
|
||||||
"myverycoolstoptoken",
|
"我的停止令牌", // 停止标记结束原样输出
|
||||||
"::add-mask::baz",
|
"::add-mask::baz", // 恢复处理的添加掩码命令
|
||||||
"<nil>",
|
"<nil>", // 无效停止命令标记处理结果
|
||||||
"<nil>",
|
"<nil>", // 被忽略的添加掩码命令处理结果
|
||||||
"*** bar baz ***",
|
"*** bar baz ***", // 掩码替换后的日志行
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"unknown command", false,
|
name: "未知命令",
|
||||||
[]string{
|
debugOutputEnabled: false,
|
||||||
"::set-mask::foo",
|
args: []string{
|
||||||
|
"::set-mask::foo", // 未知命令
|
||||||
},
|
},
|
||||||
[]string{
|
want: []string{
|
||||||
"::set-mask::foo",
|
"::set-mask::foo", // 未知命令原样输出
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
r := &Reporter{
|
r := &Reporter{
|
||||||
@ -155,43 +166,58 @@ func TestReporter_parseLogRow(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReporter_Fire(t *testing.T) {
|
// 测试 Reporter 的 Fire 方法(验证命令行忽略逻辑)
|
||||||
t.Run("ignore command lines", func(t *testing.T) {
|
func Test记录器_触发(t *testing.T) {
|
||||||
|
t.Run("忽略命令行", func(t *testing.T) { // 测试场景:验证是否正确处理需要忽略的命令行日志
|
||||||
|
// 创建模拟客户端
|
||||||
client := mocks.NewClient(t)
|
client := mocks.NewClient(t)
|
||||||
|
|
||||||
|
// 模拟 UpdateLog 接口调用,记录请求内容并返回响应
|
||||||
client.On("UpdateLog", mock.Anything, mock.Anything).Return(func(_ context.Context, req *connect_go.Request[runnerv1.UpdateLogRequest]) (*connect_go.Response[runnerv1.UpdateLogResponse], error) {
|
client.On("UpdateLog", mock.Anything, mock.Anything).Return(func(_ context.Context, req *connect_go.Request[runnerv1.UpdateLogRequest]) (*connect_go.Response[runnerv1.UpdateLogResponse], error) {
|
||||||
t.Logf("Received UpdateLog: %s", req.Msg.String())
|
t.Logf("收到 UpdateLog 请求:%s", req.Msg.String()) // 记录日志请求内容
|
||||||
return connect_go.NewResponse(&runnerv1.UpdateLogResponse{
|
return connect_go.NewResponse(&runnerv1.UpdateLogResponse{
|
||||||
AckIndex: req.Msg.Index + int64(len(req.Msg.Rows)),
|
AckIndex: req.Msg.Index + int64(len(req.Msg.Rows)), // 计算确认索引
|
||||||
}), nil
|
}), nil
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 模拟 UpdateTask 接口调用
|
||||||
client.On("UpdateTask", mock.Anything, mock.Anything).Return(func(_ context.Context, req *connect_go.Request[runnerv1.UpdateTaskRequest]) (*connect_go.Response[runnerv1.UpdateTaskResponse], error) {
|
client.On("UpdateTask", mock.Anything, mock.Anything).Return(func(_ context.Context, req *connect_go.Request[runnerv1.UpdateTaskRequest]) (*connect_go.Response[runnerv1.UpdateTaskResponse], error) {
|
||||||
t.Logf("Received UpdateTask: %s", req.Msg.String())
|
t.Logf("收到 UpdateTask 请求:%s", req.Msg.String()) // 记录任务更新请求
|
||||||
return connect_go.NewResponse(&runnerv1.UpdateTaskResponse{}), nil
|
return connect_go.NewResponse(&runnerv1.UpdateTaskResponse{}), nil
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 初始化上下文和任务
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
taskCtx, err := structpb.NewStruct(map[string]interface{}{})
|
taskCtx, err := structpb.NewStruct(map[string]interface{}{}) // 创建空任务上下文
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// 创建 Reporter 实例
|
||||||
reporter := NewReporter(ctx, cancel, client, &runnerv1.Task{
|
reporter := NewReporter(ctx, cancel, client, &runnerv1.Task{
|
||||||
Context: taskCtx,
|
Context: taskCtx, // 注入任务上下文
|
||||||
})
|
})
|
||||||
defer func() {
|
defer func() {
|
||||||
assert.NoError(t, reporter.Close(""))
|
assert.NoError(t, reporter.Close("")) // 测试结束关闭 Reporter
|
||||||
}()
|
}()
|
||||||
reporter.ResetSteps(5)
|
|
||||||
|
|
||||||
|
reporter.ResetSteps(5) // 初始化5个步骤的日志存储
|
||||||
|
|
||||||
|
// 定义步骤0的日志元数据
|
||||||
dataStep0 := map[string]interface{}{
|
dataStep0 := map[string]interface{}{
|
||||||
"stage": "Main",
|
"stage": "Main", // 阶段名称
|
||||||
"stepNumber": 0,
|
"stepNumber": 0, // 步骤编号
|
||||||
"raw_output": true,
|
"raw_output": true, // 启用原始输出模式
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.NoError(t, reporter.Fire(&log.Entry{Message: "regular log line", Data: dataStep0}))
|
// 发送混合类型的日志条目 ---------------------------------------------------
|
||||||
assert.NoError(t, reporter.Fire(&log.Entry{Message: "::debug::debug log line", Data: dataStep0}))
|
// 预期:普通日志被记录,调试日志被忽略
|
||||||
assert.NoError(t, reporter.Fire(&log.Entry{Message: "regular log line", Data: dataStep0}))
|
assert.NoError(t, reporter.Fire(&log.Entry{Message: "普通日志行", Data: dataStep0}))
|
||||||
assert.NoError(t, reporter.Fire(&log.Entry{Message: "::debug::debug log line", Data: dataStep0}))
|
assert.NoError(t, reporter.Fire(&log.Entry{Message: "::debug::调试日志行", Data: dataStep0})) // 应被忽略
|
||||||
assert.NoError(t, reporter.Fire(&log.Entry{Message: "::debug::debug log line", Data: dataStep0}))
|
assert.NoError(t, reporter.Fire(&log.Entry{Message: "普通日志行", Data: dataStep0}))
|
||||||
assert.NoError(t, reporter.Fire(&log.Entry{Message: "regular log line", Data: dataStep0}))
|
assert.NoError(t, reporter.Fire(&log.Entry{Message: "::debug::调试日志行", Data: dataStep0})) // 应被忽略
|
||||||
|
assert.NoError(t, reporter.Fire(&log.Entry{Message: "::debug::调试日志行", Data: dataStep0})) // 应被忽略
|
||||||
|
assert.NoError(t, reporter.Fire(&log.Entry{Message: "普通日志行", Data: dataStep0}))
|
||||||
|
|
||||||
assert.Equal(t, int64(3), reporter.state.Steps[0].LogLength)
|
// 验证结果:步骤0应只有3条普通日志(调试日志被过滤)
|
||||||
|
assert.Equal(t, int64(3), reporter.state.Steps[0].LogLength, "普通日志数量不符预期")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user