MCPcopy Create free account
hub / github.com/github/gh-aw / hasLocalModifications

Function hasLocalModifications

pkg/cli/update_merge.go:24–92  ·  view source on GitHub ↗

hasLocalModifications checks if the local workflow file has been modified from its source It resolves the source field and imports on the remote content, then compares with local Note: stop-after field is ignored during comparison as it's a deployment-specific setting localWorkflowDir, if non-empty,

(sourceContent, localContent, sourceSpec, localWorkflowDir string, verbose bool)

Source from the content-addressed store, hash-verified

22// localWorkflowDir, if non-empty, is passed to import processing so that relative import paths
23// whose files exist locally are preserved — giving an accurate comparison against local content.
24func hasLocalModifications(sourceContent, localContent, sourceSpec, localWorkflowDir string, verbose bool) bool {
25 updateMergeLog.Printf("Checking for local modifications: source_spec=%s", sourceSpec)
26 // Normalize both contents
27 sourceNormalized := stringutil.NormalizeWhitespace(sourceContent)
28 localNormalized := stringutil.NormalizeWhitespace(localContent)
29
30 // Remove stop-after field from both contents for comparison
31 // This field is deployment-specific and should not trigger "local modifications" warnings
32 sourceNormalized, _ = RemoveFieldFromOnTrigger(sourceNormalized, "stop-after")
33 localNormalized, _ = RemoveFieldFromOnTrigger(localNormalized, "stop-after")
34
35 // Parse the source spec to get repo and ref information
36 parsedSourceSpec, err := parseSourceSpec(sourceSpec)
37 if err != nil {
38 if verbose {
39 fmt.Fprintln(os.Stderr, console.FormatVerboseMessage(fmt.Sprintf("Failed to parse source spec: %v", err)))
40 }
41 // Fall back to simple comparison
42 return sourceNormalized != localNormalized
43 }
44
45 // Add the source field to the remote content
46 sourceWithSource, err := UpdateFieldInFrontmatter(sourceNormalized, "source", sourceSpec)
47 if err != nil {
48 if verbose {
49 fmt.Fprintln(os.Stderr, console.FormatVerboseMessage(fmt.Sprintf("Failed to add source field to remote content: %v", err)))
50 }
51 // Fall back to simple comparison
52 return sourceNormalized != localNormalized
53 }
54
55 // Resolve imports on the remote content
56 workflow := &WorkflowSpec{
57 RepoSpec: RepoSpec{
58 RepoSlug: parsedSourceSpec.Repo,
59 Version: parsedSourceSpec.Ref,
60 },
61 WorkflowPath: parsedSourceSpec.Path,
62 }
63
64 sourceResolved, err := processIncludesInContent(sourceWithSource, workflow, parsedSourceSpec.Ref, localWorkflowDir, verbose)
65 if err != nil {
66 if verbose {
67 fmt.Fprintln(os.Stderr, console.FormatVerboseMessage(fmt.Sprintf("Failed to process imports on remote content: %v", err)))
68 }
69 // Use the version with source field but without resolved imports
70 sourceResolved = sourceWithSource
71 }
72
73 // Normalize again after processing
74 sourceResolvedNormalized := stringutil.NormalizeWhitespace(sourceResolved)
75 if normalized, normalizeErr := UpdateFieldInFrontmatter(sourceResolvedNormalized, "source", "__gh_aw_source__"); normalizeErr == nil {
76 sourceResolvedNormalized = normalized
77 }
78 if normalized, normalizeErr := UpdateFieldInFrontmatter(localNormalized, "source", "__gh_aw_source__"); normalizeErr == nil {
79 localNormalized = normalized
80 }
81

Callers 3

updateWorkflowFunction · 0.85

Calls 7

NormalizeWhitespaceFunction · 0.92
FormatVerboseMessageFunction · 0.92
RemoveFieldFromOnTriggerFunction · 0.85
parseSourceSpecFunction · 0.85
UpdateFieldInFrontmatterFunction · 0.85
processIncludesInContentFunction · 0.85
PrintfMethod · 0.45

Tested by 1