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

Method writeWorkflowOutput

pkg/workflow/compiler.go:252–304  ·  view source on GitHub ↗

writeWorkflowOutput writes the compiled workflow to the lock file and handles console output formatting.

(lockFile, yamlContent string, markdownPath string)

Source from the content-addressed store, hash-verified

250// writeWorkflowOutput writes the compiled workflow to the lock file
251// and handles console output formatting.
252func (c *Compiler) writeWorkflowOutput(lockFile, yamlContent string, markdownPath string) error {
253 // Write to lock file (unless noEmit is enabled)
254 if c.noEmit {
255 workflowLog.Print("Validation completed - no lock file generated (--no-emit enabled)")
256 } else {
257 workflowLog.Printf("Writing output to: %s", lockFile)
258
259 // Check if content has actually changed
260 contentUnchanged := false
261 if existingContent, err := os.ReadFile(lockFile); err == nil {
262 if normalizeHeredocDelimiters(string(existingContent)) == normalizeHeredocDelimiters(yamlContent) {
263 // Content is identical (modulo random heredoc tokens) - skip write to preserve timestamp
264 contentUnchanged = true
265 workflowLog.Print("Lock file content unchanged - skipping write to preserve timestamp")
266 }
267 }
268
269 // Only write if content has changed
270 if !contentUnchanged {
271 if err := os.WriteFile(lockFile, []byte(yamlContent), constants.FilePermPublic); err != nil {
272 return formatCompilerError(lockFile, "error", fmt.Sprintf("failed to write lock file: %v", err), err)
273 }
274 workflowLog.Print("Lock file written successfully")
275 }
276
277 // Validate file size after writing
278 if lockFileInfo, err := os.Stat(lockFile); err == nil {
279 if lockFileInfo.Size() > MaxLockFileSize {
280 lockSize := console.FormatFileSize(lockFileInfo.Size())
281 maxSize := console.FormatFileSize(MaxLockFileSize)
282 warningMsg := fmt.Sprintf("Generated lock file size (%s) exceeds recommended maximum size (%s)", lockSize, maxSize)
283 fmt.Fprintln(os.Stderr, console.FormatWarningMessage(warningMsg))
284 }
285 }
286 }
287
288 // Display success message with file size if we generated a lock file (unless quiet mode)
289 if !c.quiet {
290 if c.noEmit {
291 fmt.Fprintln(os.Stderr, console.FormatSuccessMessage(console.ToRelativePath(markdownPath)))
292 } else {
293 // Get the size of the generated lock file for display
294 if lockFileInfo, err := os.Stat(lockFile); err == nil {
295 lockSize := console.FormatFileSize(lockFileInfo.Size())
296 fmt.Fprintln(os.Stderr, console.FormatSuccessMessage(fmt.Sprintf("%s (%s)", console.ToRelativePath(markdownPath), lockSize)))
297 } else {
298 // Fallback to original display if we can't get file info
299 fmt.Fprintln(os.Stderr, console.FormatSuccessMessage(console.ToRelativePath(markdownPath)))
300 }
301 }
302 }
303 return nil
304}
305
306// validateTemplateInjection checks compiled YAML for template injection vulnerabilities
307// (unsafe GitHub Actions expressions used directly in run: blocks).

Callers 3

TestWriteWorkflowOutputFunction · 0.95
CompileWorkflowDataMethod · 0.95

Calls 8

FormatFileSizeFunction · 0.92
FormatWarningMessageFunction · 0.92
FormatSuccessMessageFunction · 0.92
ToRelativePathFunction · 0.92
formatCompilerErrorFunction · 0.85
PrintMethod · 0.80
PrintfMethod · 0.45

Tested by 2

TestWriteWorkflowOutputFunction · 0.76