@@ -364,29 +364,70 @@ func (c *Client) ReadFileFromContainer(containerName, filePath string) (string,
364364}
365365
366366// AppendLineToFileInContainer reads a file from a container, appends a line
367- // after the first occurrence of `afterLine`, and writes it back. Uses the
368- // Docker copy API so no shell interpolation occurs.
367+ // after the last list item in the block started by `afterLine`, and writes it
368+ // back. Uses the Docker copy API so no shell interpolation occurs.
369+ //
370+ // For YAML list blocks (e.g. sourceRange:), the new entry is inserted after the
371+ // last existing "- " item in the block so that indentation stays consistent.
369372func (c * Client ) AppendLineToFileInContainer (containerName , filePath , afterLine , newLine string ) error {
370373 content , err := c .ReadFileFromContainer (containerName , filePath )
371374 if err != nil {
372375 return fmt .Errorf ("failed to read file: %w" , err )
373376 }
374377
375378 lines := strings .Split (content , "\n " )
376- var result [] string
377- inserted := false
378- for _ , line := range lines {
379- result = append ( result , line )
380- if ! inserted && strings .Contains (line , afterLine ) {
381- result = append ( result , newLine )
382- inserted = true
379+
380+ // Find the index of the section header.
381+ sectionIdx := - 1
382+ for i , line := range lines {
383+ if strings .Contains (line , afterLine ) {
384+ sectionIdx = i
385+ break
383386 }
384387 }
385-
386- if ! inserted {
388+ if sectionIdx == - 1 {
387389 return fmt .Errorf ("pattern %q not found in %s" , afterLine , filePath )
388390 }
389391
392+ // Scan forward to find the last list item ("- ") in this block.
393+ // A line that is non-empty, not a list item, and has less or equal
394+ // indentation than the section header signals the end of the block.
395+ // The indentation of the first found list item is captured so the new
396+ // entry can match it exactly, regardless of what the caller passes.
397+ sectionIndent := len (lines [sectionIdx ]) - len (strings .TrimLeft (lines [sectionIdx ], " \t " ))
398+ lastListIdx := sectionIdx // insert right after header if no items found
399+ detectedIndent := ""
400+ for i := sectionIdx + 1 ; i < len (lines ); i ++ {
401+ trimmed := strings .TrimLeft (lines [i ], " \t " )
402+ if trimmed == "" {
403+ continue
404+ }
405+ lineIndent := len (lines [i ]) - len (trimmed )
406+ if lineIndent <= sectionIndent {
407+ // Left the block.
408+ break
409+ }
410+ if strings .HasPrefix (trimmed , "- " ) || trimmed == "-" {
411+ lastListIdx = i
412+ if detectedIndent == "" {
413+ detectedIndent = lines [i ][:lineIndent ]
414+ }
415+ }
416+ }
417+
418+ // Apply detected indentation so the new entry always matches existing items.
419+ // If the block has no existing items, use newLine verbatim.
420+ insertLine := newLine
421+ if detectedIndent != "" {
422+ insertLine = detectedIndent + strings .TrimLeft (newLine , " \t " )
423+ }
424+
425+ // Insert after the last list item (or after the header if none exist).
426+ result := make ([]string , 0 , len (lines )+ 1 )
427+ result = append (result , lines [:lastListIdx + 1 ]... )
428+ result = append (result , insertLine )
429+ result = append (result , lines [lastListIdx + 1 :]... )
430+
390431 return c .WriteFileToContainer (containerName , filePath , []byte (strings .Join (result , "\n " )))
391432}
392433
0 commit comments