completed phase 2b

This commit is contained in:
2026-05-11 20:10:45 +02:00
parent 83d96d0a1e
commit 4002a3b84d
20 changed files with 1566 additions and 50 deletions
+79
View File
@@ -0,0 +1,79 @@
package ci
import (
"fmt"
"strings"
gitdomain "github.com/forgeo/forgebucket/internal/domain/git"
"gopkg.in/yaml.v3"
)
const workflowDir = ".forgebucket/workflows"
// ListWorkflows returns the file paths of all workflow YAML files in a repo at a
// given ref. Returns nil (no error) when the workflows directory doesn't exist.
func ListWorkflows(repoPath, ref string) ([]string, error) {
entries, err := gitdomain.TreeLS(repoPath, ref, workflowDir)
if err != nil {
// Directory does not exist at this ref — no workflows, not an error.
return nil, nil
}
var paths []string
for _, e := range entries {
if e.Type == "blob" && (strings.HasSuffix(e.Name, ".yml") || strings.HasSuffix(e.Name, ".yaml")) {
paths = append(paths, workflowDir+"/"+e.Name)
}
}
return paths, nil
}
// ParseWorkflow reads and parses a single workflow YAML file from the repo at ref.
func ParseWorkflow(repoPath, ref, filePath string) (*WorkflowFile, error) {
data, err := gitdomain.BlobCat(repoPath, ref, filePath)
if err != nil {
return nil, fmt.Errorf("read %s: %w", filePath, err)
}
var wf WorkflowFile
if err := yaml.Unmarshal(data, &wf); err != nil {
return nil, fmt.Errorf("parse %s: %w", filePath, err)
}
return &wf, nil
}
// MatchesPushTrigger reports whether a workflow should run for a push to ref.
// ref is the full ref name, e.g. "refs/heads/main".
func MatchesPushTrigger(wf *WorkflowFile, ref string) bool {
if wf.On.Push == nil {
return false
}
trigger := wf.On.Push
// No branch filter means "all branches".
if len(trigger.Branches) == 0 && len(trigger.Tags) == 0 {
return true
}
branch := strings.TrimPrefix(ref, "refs/heads/")
for _, pattern := range trigger.Branches {
if matchGlob(pattern, branch) {
return true
}
}
tag := strings.TrimPrefix(ref, "refs/tags/")
for _, pattern := range trigger.Tags {
if matchGlob(pattern, tag) {
return true
}
}
return false
}
// matchGlob supports simple "*" wildcards (not full glob).
func matchGlob(pattern, s string) bool {
if pattern == "*" {
return true
}
if !strings.Contains(pattern, "*") {
return pattern == s
}
parts := strings.SplitN(pattern, "*", 2)
return strings.HasPrefix(s, parts[0]) && strings.HasSuffix(s, parts[1])
}