mirror of
https://github.com/ivuorinen/gh-action-readme.git
synced 2026-01-26 11:14:04 +00:00
* feat: ignore vendored directories * chore: cr tweaks * fix: sonarcloud detected issues * fix: sonarcloud detected issues
142 lines
3.9 KiB
Go
142 lines
3.9 KiB
Go
package internal
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/goccy/go-yaml"
|
|
|
|
"github.com/ivuorinen/gh-action-readme/appconstants"
|
|
)
|
|
|
|
// ActionYML models the action.yml metadata (fields are updateable as schema evolves).
|
|
type ActionYML struct {
|
|
Name string `yaml:"name"`
|
|
Description string `yaml:"description"`
|
|
Inputs map[string]ActionInput `yaml:"inputs"`
|
|
Outputs map[string]ActionOutput `yaml:"outputs"`
|
|
Runs map[string]any `yaml:"runs"`
|
|
Branding *Branding `yaml:"branding,omitempty"`
|
|
// Add more fields as the schema evolves
|
|
}
|
|
|
|
// ActionInput represents an input parameter for a GitHub Action.
|
|
type ActionInput struct {
|
|
Description string `yaml:"description"`
|
|
Required bool `yaml:"required"`
|
|
Default any `yaml:"default"`
|
|
}
|
|
|
|
// ActionOutput represents an output parameter for a GitHub Action.
|
|
type ActionOutput struct {
|
|
Description string `yaml:"description"`
|
|
}
|
|
|
|
// Branding represents the branding configuration for a GitHub Action.
|
|
type Branding struct {
|
|
Icon string `yaml:"icon"`
|
|
Color string `yaml:"color"`
|
|
}
|
|
|
|
// ParseActionYML reads and parses action.yml from given path.
|
|
func ParseActionYML(path string) (*ActionYML, error) {
|
|
f, err := os.Open(path) // #nosec G304 -- path from function parameter
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer func() {
|
|
_ = f.Close() // Ignore close error in defer
|
|
}()
|
|
var a ActionYML
|
|
dec := yaml.NewDecoder(f)
|
|
if err := dec.Decode(&a); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &a, nil
|
|
}
|
|
|
|
// shouldIgnoreDirectory checks if a directory name matches the ignore list.
|
|
func shouldIgnoreDirectory(dirName string, ignoredDirs []string) bool {
|
|
for _, ignored := range ignoredDirs {
|
|
if strings.HasPrefix(ignored, ".") {
|
|
// Pattern match: ".git" matches ".git", ".github", etc.
|
|
if strings.HasPrefix(dirName, ignored) {
|
|
return true
|
|
}
|
|
} else {
|
|
// Exact match for non-hidden dirs
|
|
if dirName == ignored {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// actionFileWalker encapsulates the logic for walking directories and finding action files.
|
|
type actionFileWalker struct {
|
|
ignoredDirs []string
|
|
actionFiles []string
|
|
}
|
|
|
|
// walkFunc is the callback function for filepath.Walk.
|
|
func (w *actionFileWalker) walkFunc(path string, info os.FileInfo, err error) error {
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if info.IsDir() {
|
|
if shouldIgnoreDirectory(info.Name(), w.ignoredDirs) {
|
|
return filepath.SkipDir
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Check for action.yml or action.yaml files
|
|
filename := strings.ToLower(info.Name())
|
|
if filename == appconstants.ActionFileNameYML || filename == appconstants.ActionFileNameYAML {
|
|
w.actionFiles = append(w.actionFiles, path)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// DiscoverActionFiles finds action.yml and action.yaml files in the given directory.
|
|
// This consolidates the file discovery logic from both generator.go and dependencies/parser.go.
|
|
func DiscoverActionFiles(dir string, recursive bool, ignoredDirs []string) ([]string, error) {
|
|
// Check if dir exists
|
|
if _, err := os.Stat(dir); os.IsNotExist(err) {
|
|
return nil, fmt.Errorf("directory does not exist: %s", dir)
|
|
}
|
|
|
|
if recursive {
|
|
walker := &actionFileWalker{ignoredDirs: ignoredDirs}
|
|
if err := filepath.Walk(dir, walker.walkFunc); err != nil {
|
|
return nil, fmt.Errorf("failed to walk directory %s: %w", dir, err)
|
|
}
|
|
|
|
return walker.actionFiles, nil
|
|
}
|
|
|
|
// Check only the specified directory (non-recursive)
|
|
return discoverActionFilesNonRecursive(dir), nil
|
|
}
|
|
|
|
// discoverActionFilesNonRecursive finds action files in a single directory.
|
|
func discoverActionFilesNonRecursive(dir string) []string {
|
|
var actionFiles []string
|
|
for _, filename := range []string{appconstants.ActionFileNameYML, appconstants.ActionFileNameYAML} {
|
|
path := filepath.Join(dir, filename)
|
|
if _, err := os.Stat(path); err == nil {
|
|
actionFiles = append(actionFiles, path)
|
|
}
|
|
}
|
|
|
|
return actionFiles
|
|
}
|