80 lines
2.2 KiB
Go
80 lines
2.2 KiB
Go
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])
|
|
}
|