mirror of
https://gitea.com/gitea/act_runner.git
synced 2026-07-02 00:54:31 +00:00
Reviewed-on: https://gitea.com/gitea/runner/pulls/1055 Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com> Co-authored-by: bircni <bircni@icloud.com>
221 lines
5.6 KiB
Go
221 lines
5.6 KiB
Go
// Copyright 2026 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package cmd
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"gitea.com/gitea/runner/act/model"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
"go.yaml.in/yaml/v4"
|
|
)
|
|
|
|
func TestExecuteArgsResolve(t *testing.T) {
|
|
workdir := t.TempDir()
|
|
args := &executeArgs{workdir: workdir}
|
|
|
|
require.Empty(t, args.resolve(""))
|
|
require.Equal(t, filepath.Join(workdir, "sub", "file"), args.resolve("sub/file"))
|
|
|
|
abs := filepath.Join(workdir, "abs")
|
|
require.Equal(t, abs, args.resolve(abs))
|
|
}
|
|
|
|
func TestExecuteArgsPaths(t *testing.T) {
|
|
workdir := t.TempDir()
|
|
args := &executeArgs{
|
|
workdir: workdir,
|
|
workflowsPath: ".gitea/workflows",
|
|
envfile: ".env",
|
|
}
|
|
|
|
require.Equal(t, filepath.Join(workdir, ".gitea/workflows"), args.WorkflowsPath())
|
|
require.Equal(t, filepath.Join(workdir, ".env"), args.Envfile())
|
|
require.Equal(t, workdir, args.Workdir())
|
|
}
|
|
|
|
func TestExecuteArgsLoadVars(t *testing.T) {
|
|
require.Empty(t, (&executeArgs{}).LoadVars())
|
|
|
|
args := &executeArgs{vars: []string{"FOO=bar", "EMPTY", "WITH=eq=sign"}}
|
|
require.Equal(t, map[string]string{
|
|
"FOO": "bar",
|
|
"EMPTY": "",
|
|
"WITH": "eq=sign",
|
|
}, args.LoadVars())
|
|
}
|
|
|
|
func TestExecuteArgsLoadSecrets(t *testing.T) {
|
|
t.Setenv("FROMENV", "from-env-value")
|
|
|
|
args := &executeArgs{secrets: []string{"token=abc", "fromenv"}}
|
|
require.Equal(t, map[string]string{
|
|
"TOKEN": "abc",
|
|
"FROMENV": "from-env-value",
|
|
}, args.LoadSecrets())
|
|
}
|
|
|
|
func TestReadEnvs(t *testing.T) {
|
|
dir := t.TempDir()
|
|
envFile := filepath.Join(dir, ".env")
|
|
require.NoError(t, os.WriteFile(envFile, []byte("FOO=bar\nBAZ=qux\n"), 0o600))
|
|
|
|
envs := map[string]string{"EXISTING": "keep"}
|
|
require.True(t, readEnvs(envFile, envs))
|
|
require.Equal(t, map[string]string{
|
|
"EXISTING": "keep",
|
|
"FOO": "bar",
|
|
"BAZ": "qux",
|
|
}, envs)
|
|
|
|
missing := map[string]string{}
|
|
require.False(t, readEnvs(filepath.Join(dir, "does-not-exist"), missing))
|
|
require.Empty(t, missing)
|
|
}
|
|
|
|
func TestRunExecListUsesJobEventAndAllPlans(t *testing.T) {
|
|
planner := &fakeWorkflowPlanner{
|
|
events: []string{"push", "pull_request"},
|
|
plans: map[string]*model.Plan{
|
|
"job:build": listPlan("build", "Build", "push"),
|
|
"event:push": listPlan("test", "Test", "push"),
|
|
"all": listPlan("lint", "Lint", "push"),
|
|
},
|
|
}
|
|
|
|
out := captureStdout(t, func() {
|
|
require.NoError(t, runExecList(planner, &executeArgs{job: "build"}))
|
|
require.NoError(t, runExecList(planner, &executeArgs{event: "push"}))
|
|
require.NoError(t, runExecList(planner, &executeArgs{autodetectEvent: true}))
|
|
require.NoError(t, runExecList(planner, &executeArgs{}))
|
|
})
|
|
|
|
require.Contains(t, out, "Build")
|
|
require.Contains(t, out, "Test")
|
|
require.Contains(t, out, "Lint")
|
|
require.Equal(t, []string{"job:build", "event:push", "event:push", "all"}, planner.calls)
|
|
}
|
|
|
|
func TestPrintListReportsDuplicateJobIDs(t *testing.T) {
|
|
workflowA := workflowForList("A", "a.yml", "push", "build", "Build A")
|
|
workflowB := workflowForList("B", "b.yml", "pull_request", "build", "Build B")
|
|
plan := &model.Plan{Stages: []*model.Stage{{
|
|
Runs: []*model.Run{
|
|
{Workflow: workflowA, JobID: "build"},
|
|
{Workflow: workflowB, JobID: "build"},
|
|
},
|
|
}}}
|
|
|
|
out := captureStdout(t, func() {
|
|
printList(plan)
|
|
})
|
|
|
|
require.Contains(t, out, "Workflow file")
|
|
require.Contains(t, out, "Build A")
|
|
require.Contains(t, out, "Build B")
|
|
require.Contains(t, out, "Detected multiple jobs with the same job name")
|
|
}
|
|
|
|
func TestLoadExecCmdDefinesExpectedFlags(t *testing.T) {
|
|
cmd := loadExecCmd(context.Background())
|
|
|
|
for _, name := range []string{
|
|
"list",
|
|
"job",
|
|
"event",
|
|
"workflows",
|
|
"directory",
|
|
"env",
|
|
"secret",
|
|
"var",
|
|
"dryrun",
|
|
"image",
|
|
"gitea-instance",
|
|
} {
|
|
if cmd.Flags().Lookup(name) == nil && cmd.PersistentFlags().Lookup(name) == nil {
|
|
t.Fatalf("expected flag %q to be registered", name)
|
|
}
|
|
}
|
|
|
|
require.Equal(t, "exec", cmd.Use)
|
|
require.NoError(t, cmd.Args(cmd, strings.Split("a b c", " ")))
|
|
require.Error(t, cmd.Args(cmd, strings.Fields(strings.Repeat("arg ", 21))))
|
|
}
|
|
|
|
type fakeWorkflowPlanner struct {
|
|
events []string
|
|
plans map[string]*model.Plan
|
|
calls []string
|
|
}
|
|
|
|
func (p *fakeWorkflowPlanner) PlanEvent(eventName string) (*model.Plan, error) {
|
|
p.calls = append(p.calls, "event:"+eventName)
|
|
return p.plans["event:"+eventName], nil
|
|
}
|
|
|
|
func (p *fakeWorkflowPlanner) PlanJob(jobName string) (*model.Plan, error) {
|
|
p.calls = append(p.calls, "job:"+jobName)
|
|
return p.plans["job:"+jobName], nil
|
|
}
|
|
|
|
func (p *fakeWorkflowPlanner) PlanAll() (*model.Plan, error) {
|
|
p.calls = append(p.calls, "all")
|
|
return p.plans["all"], nil
|
|
}
|
|
|
|
func (p *fakeWorkflowPlanner) GetEvents() []string {
|
|
return p.events
|
|
}
|
|
|
|
func listPlan(jobID, jobName, event string) *model.Plan {
|
|
workflow := workflowForList("Workflow "+jobID, jobID+".yml", event, jobID, jobName)
|
|
return &model.Plan{Stages: []*model.Stage{{Runs: []*model.Run{{Workflow: workflow, JobID: jobID}}}}}
|
|
}
|
|
|
|
func workflowForList(name, file, event, jobID, jobName string) *model.Workflow {
|
|
return &model.Workflow{
|
|
Name: name,
|
|
File: file,
|
|
RawOn: rawOnNode(event),
|
|
Jobs: map[string]*model.Job{
|
|
jobID: {Name: jobName},
|
|
},
|
|
}
|
|
}
|
|
|
|
func rawOnNode(event string) yaml.Node {
|
|
var node yaml.Node
|
|
if err := yaml.Unmarshal([]byte(event), &node); err != nil {
|
|
panic(err)
|
|
}
|
|
return *node.Content[0]
|
|
}
|
|
|
|
func captureStdout(t *testing.T, fn func()) string {
|
|
t.Helper()
|
|
|
|
old := os.Stdout
|
|
r, w, err := os.Pipe()
|
|
require.NoError(t, err)
|
|
os.Stdout = w
|
|
|
|
fn()
|
|
|
|
require.NoError(t, w.Close())
|
|
os.Stdout = old
|
|
|
|
var buf bytes.Buffer
|
|
_, err = io.Copy(&buf, r)
|
|
require.NoError(t, err)
|
|
require.NoError(t, r.Close())
|
|
return buf.String()
|
|
}
|