Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 25 additions & 25 deletions pkg/actionpins/actionpins.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (
"github.com/github/gh-aw/pkg/semverutil"
)

var log = logger.New("workflow:action_pins")
var actionPinsLog = logger.New("actionpins:actionpins")

//go:embed data/action_pins.json
var actionPinsJSON []byte
Expand Down Expand Up @@ -109,16 +109,16 @@ var (

func getActionPins() []ActionPin {
actionPinsOnce.Do(func() {
log.Print("Unmarshaling action pins from embedded JSON (first call, will be cached)")
actionPinsLog.Print("Unmarshaling action pins from embedded JSON (first call, will be cached)")

var data ActionPinsData
if err := json.Unmarshal(actionPinsJSON, &data); err != nil {
log.Printf("Failed to unmarshal action pins JSON: %v", err)
actionPinsLog.Printf("Failed to unmarshal action pins JSON: %v", err)
panic(fmt.Sprintf("failed to load action pins: %v", err))
}

if n := countPinKeyMismatches(data.Entries); n > 0 {
log.Printf("Found %d key/version mismatches in action_pins.json", n)
actionPinsLog.Printf("Found %d key/version mismatches in action_pins.json", n)
}

pins := slices.Collect(maps.Values(data.Entries))
Expand All @@ -130,17 +130,17 @@ func getActionPins() []ActionPin {
return cmp.Compare(a.Repo, b.Repo)
})

log.Printf("Successfully unmarshaled and sorted %d action pins from JSON", len(pins))
actionPinsLog.Printf("Successfully unmarshaled and sorted %d action pins from JSON", len(pins))
cachedActionPins = pins

cachedActionPinsByRepo = buildByRepoIndex(pins)
log.Printf("Built per-repo action pin index for %d repos", len(cachedActionPinsByRepo))
actionPinsLog.Printf("Built per-repo action pin index for %d repos", len(cachedActionPinsByRepo))

cachedContainerPins = data.Containers
if cachedContainerPins == nil {
cachedContainerPins = make(map[string]ContainerPin)
}
log.Printf("Loaded %d container pins from JSON", len(cachedContainerPins))
actionPinsLog.Printf("Loaded %d container pins from JSON", len(cachedContainerPins))
})

return cachedActionPins
Expand All @@ -156,7 +156,7 @@ func countPinKeyMismatches(entries map[string]ActionPin) int {
if keyVersion != pin.Version {
count++
shortSHA := pin.SHA[:min(len(pin.SHA), 8)]
log.Printf("WARNING: Key/version mismatch in action_pins.json: key=%s has version=%s but pin.Version=%s (sha=%s)",
actionPinsLog.Printf("WARNING: Key/version mismatch in action_pins.json: key=%s has version=%s but pin.Version=%s (sha=%s)",
key, keyVersion, pin.Version, shortSHA)
}
}
Expand Down Expand Up @@ -309,62 +309,62 @@ func ResolveActionPin(actionRepo, version string, ctx *PinContext) (string, erro
if ctx == nil {
ctx = &PinContext{}
}
log.Printf("Resolving action pin: repo=%s, version=%s, strict_mode=%t", actionRepo, version, ctx.StrictMode)
actionPinsLog.Printf("Resolving action pin: repo=%s, version=%s, strict_mode=%t", actionRepo, version, ctx.StrictMode)

isAlreadySHA := isValidFullSHA(version)

if ctx.Resolver != nil && !isAlreadySHA {
log.Printf("Attempting dynamic resolution for %s@%s", actionRepo, version)
actionPinsLog.Printf("Attempting dynamic resolution for %s@%s", actionRepo, version)
sha, err := ctx.Resolver.ResolveSHA(cmp.Or(ctx.Ctx, context.Background()), actionRepo, version)
if err == nil && sha != "" {
log.Printf("Dynamic resolution succeeded: %s@%s → %s", actionRepo, version, sha)
actionPinsLog.Printf("Dynamic resolution succeeded: %s@%s → %s", actionRepo, version, sha)
resolvedVersion := findVersionBySHA(actionRepo, sha)
result := formatPinnedActionWithResolution(actionRepo, sha, version, resolvedVersion)
log.Printf("Returning pinned reference: %s", result)
actionPinsLog.Printf("Returning pinned reference: %s", result)
return result, nil
}
log.Printf("Dynamic resolution failed for %s@%s: %v", actionRepo, version, err)
actionPinsLog.Printf("Dynamic resolution failed for %s@%s: %v", actionRepo, version, err)
} else {
if isAlreadySHA {
log.Printf("Version is already a SHA, skipping dynamic resolution")
actionPinsLog.Printf("Version is already a SHA, skipping dynamic resolution")
} else {
log.Printf("No action resolver available, skipping dynamic resolution")
actionPinsLog.Printf("No action resolver available, skipping dynamic resolution")
}
}

log.Printf("Falling back to hardcoded pins for %s@%s", actionRepo, version)
actionPinsLog.Printf("Falling back to hardcoded pins for %s@%s", actionRepo, version)
matchingPins := GetActionPinsByRepo(actionRepo)

if len(matchingPins) == 0 {
log.Printf("No hardcoded pins found for %s", actionRepo)
actionPinsLog.Printf("No hardcoded pins found for %s", actionRepo)
} else {
log.Printf("Found %d hardcoded pin(s) for %s", len(matchingPins), actionRepo)
actionPinsLog.Printf("Found %d hardcoded pin(s) for %s", len(matchingPins), actionRepo)

for _, pin := range matchingPins {
if pin.Version == version {
log.Printf("Exact version match: requested=%s, found=%s", version, pin.Version)
actionPinsLog.Printf("Exact version match: requested=%s, found=%s", version, pin.Version)
return FormatPinnedActionReference(actionRepo, pin.SHA, pin.Version), nil
}
}

if isAlreadySHA {
for _, pin := range matchingPins {
if pin.SHA == version {
log.Printf("Exact SHA match: requested=%s, found version=%s", version, pin.Version)
actionPinsLog.Printf("Exact SHA match: requested=%s, found version=%s", version, pin.Version)
return FormatPinnedActionReference(actionRepo, pin.SHA, pin.Version), nil
}
}
log.Printf("SHA %s not found in hardcoded pins, returning as-is", version)
actionPinsLog.Printf("SHA %s not found in hardcoded pins, returning as-is", version)
return FormatPinnedActionReference(actionRepo, version, version), nil
}

if !ctx.StrictMode && len(matchingPins) > 0 {
selectedPin, foundCompatible := findCompatiblePin(matchingPins, version)
if foundCompatible {
log.Printf("No exact match for version %s, using highest semver-compatible version: %s", version, selectedPin.Version)
actionPinsLog.Printf("No exact match for version %s, using highest semver-compatible version: %s", version, selectedPin.Version)
} else {
selectedPin = matchingPins[0]
log.Printf("No exact match for version %s, no semver-compatible versions found, using highest available: %s", version, selectedPin.Version)
actionPinsLog.Printf("No exact match for version %s, no semver-compatible versions found, using highest available: %s", version, selectedPin.Version)
}

if !isAlreadySHA {
Expand All @@ -377,14 +377,14 @@ func ResolveActionPin(actionRepo, version string, ctx *PinContext) (string, erro
ctx.Warnings[cacheKey] = true
}
}
log.Printf("Using version in non-strict mode: %s@%s (requested) → %s@%s (used)",
actionPinsLog.Printf("Using version in non-strict mode: %s@%s (requested) → %s@%s (used)",
actionRepo, version, actionRepo, selectedPin.Version)
return formatPinnedActionWithResolution(actionRepo, selectedPin.SHA, version, selectedPin.Version), nil
}
}

if isAlreadySHA {
log.Printf("SHA %s not found in hardcoded pins, returning as-is", version)
actionPinsLog.Printf("SHA %s not found in hardcoded pins, returning as-is", version)
return FormatPinnedActionReference(actionRepo, version, version), nil
}

Expand Down
8 changes: 4 additions & 4 deletions pkg/parser/content_extractor.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ var contentExtractorLog = logger.New("parser:content_extractor")

// extractToolsFromContent extracts tools and mcp-servers sections from frontmatter as JSON string
func extractToolsFromContent(content string) (string, error) {
log.Printf("Extracting tools from content: size=%d bytes", len(content))
parserLog.Printf("Extracting tools from content: size=%d bytes", len(content))
result, err := ExtractFrontmatterFromContent(content)
if err != nil {
log.Printf("Failed to extract frontmatter: %v", err)
parserLog.Printf("Failed to extract frontmatter: %v", err)
return "{}", nil // Return empty object on error to match bash behavior
}

Expand All @@ -40,11 +40,11 @@ func extractToolsFromContent(content string) (string, error) {

// If nothing was extracted, return empty object
if len(extracted) == 0 {
log.Print("No tools or mcp-servers found in content")
parserLog.Print("No tools or mcp-servers found in content")
return "{}", nil
}

log.Printf("Extracted %d tool/server configurations", len(extracted))
parserLog.Printf("Extracted %d tool/server configurations", len(extracted))
// Convert to JSON string
extractedJSON, err := json.Marshal(extracted)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion pkg/parser/frontmatter.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ import (
"github.com/github/gh-aw/pkg/logger"
)

var log = logger.New("parser:frontmatter")
var parserLog = logger.New("parser:frontmatter")
24 changes: 12 additions & 12 deletions pkg/parser/frontmatter_content.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ type FrontmatterResult struct {

// ExtractFrontmatterFromContent parses YAML frontmatter from markdown content string
func ExtractFrontmatterFromContent(content string) (*FrontmatterResult, error) {
log.Printf("Extracting frontmatter from content: size=%d bytes", len(content))
parserLog.Printf("Extracting frontmatter from content: size=%d bytes", len(content))
// Fast-path: inspect only the first line to determine whether frontmatter exists.
firstNewline := strings.IndexByte(content, '\n')
firstLine := content
Expand All @@ -33,7 +33,7 @@ func ExtractFrontmatterFromContent(content string) (*FrontmatterResult, error) {

// Check if file starts with frontmatter delimiter.
if !isFrontmatterDelimiterLine(firstLine) {
log.Print("No frontmatter delimiter found, returning content as markdown")
parserLog.Print("No frontmatter delimiter found, returning content as markdown")
// No frontmatter, return entire content as markdown
return &FrontmatterResult{
Frontmatter: make(map[string]any),
Expand Down Expand Up @@ -113,7 +113,7 @@ func ExtractFrontmatterFromContent(content string) (*FrontmatterResult, error) {
markdown = content[markdownStart:]
}

log.Printf("Successfully extracted frontmatter: fields=%d, markdown_size=%d bytes", len(frontmatter), len(markdown))
parserLog.Printf("Successfully extracted frontmatter: fields=%d, markdown_size=%d bytes", len(frontmatter), len(markdown))
return &FrontmatterResult{
Frontmatter: frontmatter,
Markdown: strings.TrimSpace(markdown),
Expand Down Expand Up @@ -190,7 +190,7 @@ func ExtractFrontmatterFromBuiltinFile(path string, content []byte) (*Frontmatte
// ExtractMarkdownSection extracts a specific section from markdown content
// Supports H1-H3 headers and proper nesting (matches bash implementation)
func ExtractMarkdownSection(content, sectionName string) (string, error) {
log.Printf("Extracting markdown section: section=%s, content_size=%d bytes", sectionName, len(content))
parserLog.Printf("Extracting markdown section: section=%s, content_size=%d bytes", sectionName, len(content))
scanner := bufio.NewScanner(strings.NewReader(content))
var sectionContent bytes.Buffer
inSection := false
Expand Down Expand Up @@ -225,12 +225,12 @@ func ExtractMarkdownSection(content, sectionName string) (string, error) {
}

if !inSection {
log.Printf("Section not found: %s", sectionName)
parserLog.Printf("Section not found: %s", sectionName)
return "", fmt.Errorf("section '%s' not found", sectionName)
}

extractedContent := strings.TrimSpace(sectionContent.String())
log.Printf("Successfully extracted section: size=%d bytes", len(extractedContent))
parserLog.Printf("Successfully extracted section: size=%d bytes", len(extractedContent))
return extractedContent, nil
}

Expand Down Expand Up @@ -269,36 +269,36 @@ func findH1WorkflowName(markdownBody string) string {
// avoids the redundant file-read and YAML-parse that those functions perform when the caller
// already holds the parsed FrontmatterResult.
func ExtractWorkflowNameFromMarkdownBody(markdownBody string, virtualPath string) (string, error) {
log.Printf("Extracting workflow name from markdown body: virtualPath=%s, size=%d bytes", virtualPath, len(markdownBody))
parserLog.Printf("Extracting workflow name from markdown body: virtualPath=%s, size=%d bytes", virtualPath, len(markdownBody))

if name := findH1WorkflowName(markdownBody); name != "" {
log.Printf("Found workflow name from H1 header: %s", name)
parserLog.Printf("Found workflow name from H1 header: %s", name)
return name, nil
}

defaultName := generateDefaultWorkflowName(virtualPath)
log.Printf("No H1 header found, using default name: %s", defaultName)
parserLog.Printf("No H1 header found, using default name: %s", defaultName)
return defaultName, nil
}

// ExtractWorkflowNameFromContent extracts the workflow name from markdown content string.
// This is the in-memory equivalent of ExtractWorkflowNameFromMarkdown, used by Wasm builds
// where filesystem access is unavailable.
func ExtractWorkflowNameFromContent(content string, virtualPath string) (string, error) {
log.Printf("Extracting workflow name from content: virtualPath=%s, size=%d bytes", virtualPath, len(content))
parserLog.Printf("Extracting workflow name from content: virtualPath=%s, size=%d bytes", virtualPath, len(content))

markdownContent, err := ExtractMarkdownContent(content)
if err != nil {
return "", err
}

if name := findH1WorkflowName(markdownContent); name != "" {
log.Printf("Found workflow name from H1 header: %s", name)
parserLog.Printf("Found workflow name from H1 header: %s", name)
return name, nil
}

defaultName := generateDefaultWorkflowName(virtualPath)
log.Printf("No H1 header found, using default name: %s", defaultName)
parserLog.Printf("No H1 header found, using default name: %s", defaultName)
return defaultName, nil
}

Expand Down
Loading
Loading