ci_workflow_test.go
Rama dev · réplica de lectura del repositorio original.
package main
import (
"os"
"os/exec"
"strings"
"testing"
)
// Execute the workflow's actual gate after resolving its two GitHub contexts.
// Both inline expressions and step env are resolved, so putting a ref back into
// shell source would exercise the same expansion as a pull-request run.
func TestCIMainSourceGateTreatsBranchNamesAsData(t *testing.T) {
contents, err := os.ReadFile(".github/workflows/ci.yml")
if err != nil {
t.Fatal(err)
}
var script strings.Builder
stepEnv := make(map[string]string)
inStep, inRun, inEnv := false, false, false
for _, line := range strings.Split(string(contents), "\n") {
if line == " - name: Require staging source for main" {
inStep = true
continue
}
if !inStep {
continue
}
if strings.TrimSpace(line) != "" && !strings.HasPrefix(line, " ") {
break
}
if line == " run: |" {
inRun, inEnv = true, false
continue
}
if inRun {
if strings.TrimSpace(line) != "" && !strings.HasPrefix(line, " ") {
break
}
script.WriteString(strings.TrimPrefix(line, " ") + "\n")
continue
}
if line == " env:" {
inEnv = true
continue
}
if inEnv && strings.HasPrefix(line, " ") {
name, value, ok := strings.Cut(strings.TrimSpace(line), ":")
if !ok {
t.Fatalf("invalid gate environment entry: %q", line)
}
stepEnv[name] = strings.TrimSpace(value)
} else {
inEnv = false
}
}
if script.Len() == 0 {
t.Fatal("main source gate script was not found")
}
for _, tc := range []struct {
name, base, head string
allowed bool
}{
{"promotion", "main", "staging", true},
{"wrong source", "main", "dev", false},
{"development", "dev", "feature/change", true},
{"staging", "staging", "dev", true},
{"substitution", "main", "topic$(>gate-marker)", false},
{"backticks", "main", "topic`>gate-marker`", false},
{"development substitution", "dev", "topic$(>gate-marker)", true},
} {
t.Run(tc.name, func(t *testing.T) {
if output, err := exec.Command("git", "check-ref-format", "--branch", tc.head).CombinedOutput(); err != nil {
t.Fatalf("test branch is not a valid Git ref: %v: %s", err, output)
}
expand := strings.NewReplacer("${{ github.base_ref }}", tc.base, "${{ github.head_ref }}", tc.head)
cmd := exec.Command("bash", "-c", expand.Replace(script.String()))
cmd.Dir = t.TempDir()
cmd.Env = os.Environ()
for name, value := range stepEnv {
cmd.Env = append(cmd.Env, name+"="+expand.Replace(value))
}
output, err := cmd.CombinedOutput()
if _, markerErr := os.Stat(cmd.Dir + "/gate-marker"); !os.IsNotExist(markerErr) {
t.Fatal("branch name executed shell syntax")
}
if (err == nil) != tc.allowed {
t.Fatalf("gate allowed=%v, want %v: %v: %s", err == nil, tc.allowed, err, output)
}
})
}
}