99 "io"
1010 "os/exec"
1111 "path"
12- "strings "
12+ "regexp "
1313
1414 "github.com/djherbis/buffer"
1515 "github.com/djherbis/nio/v3"
@@ -91,7 +91,7 @@ func BuildReleaseArtifacts(ctx context.Context, opts BuildReleaseArtifactsOpts,
9191 return fmt .Errorf ("unable to set cli args: %w" , err ), nil
9292 }
9393
94- if err := RunCliBuild (contextReader , opts .TarWriter , args ... ); err != nil {
94+ if err := RunCliBuild (ctx , contextReader , opts .TarWriter , args ... ); err != nil {
9595 return fmt .Errorf ("can't build artifacts: %w" , err ), nil
9696 }
9797
@@ -106,9 +106,9 @@ func BuildReleaseArtifacts(ctx context.Context, opts BuildReleaseArtifactsOpts,
106106 return nil , cleanupFunc
107107}
108108
109- func RunCliBuild (contextReader * nio.PipeReader , tarWriter * nio.PipeWriter , args ... string ) error {
109+ func RunCliBuild (ctx context. Context , contextReader * nio.PipeReader , tarWriter * nio.PipeWriter , args ... string ) error {
110110 finalArgs := append ([]string {"buildx" , "build" }, args ... )
111- cmd := exec .Command ( "docker" , finalArgs ... )
111+ cmd := exec .CommandContext ( ctx , "docker" , finalArgs ... )
112112 cmd .Stdout = tarWriter
113113 cmd .Stdin = contextReader
114114
@@ -121,31 +121,54 @@ func RunCliBuild(contextReader *nio.PipeReader, tarWriter *nio.PipeWriter, args
121121 return fmt .Errorf ("error starting command: %w" , err )
122122 }
123123
124- var stderr bytes.Buffer
125- io .Copy (& stderr , stderrPipe )
124+ errSection , scanErr := extractRelevantLogs (stderrPipe )
125+ if scanErr != nil {
126+ return scanErr
127+ }
126128
127129 if err := cmd .Wait (); err != nil {
128- var errMsg string
129- if stderr .Len () > 0 {
130- errMsg = extractErrorMessage (stderr .String ())
130+ if errSection .Len () == 0 {
131+ return fmt .Errorf ("build failed with error(s):\n %s\n %w" , errSection .String (), err )
131132 }
132- return fmt .Errorf ("error executing command: %s %w" , errMsg , err )
133+ return fmt .Errorf ("build failed: \n %s \n %w" , errSection . String () , err )
133134 }
134135
135136 return nil
136137}
137138
138- func extractErrorMessage (stderr string ) string {
139- scanner := bufio .NewScanner (strings .NewReader (stderr ))
140- var errors []string
139+ // this needs for parsing buildx logs due to the fact that buildx writes all to stderr
140+ // it will look for the first error section of the logs that contains the error
141+ // or if not found just lines starts with "error:" or "ERROR:"
142+ func extractRelevantLogs (stderr io.ReadCloser ) (bytes.Buffer , error ) {
143+ scanner := bufio .NewScanner (stderr )
144+
145+ var errSection bytes.Buffer
146+ var foundSection bool
147+ reSectionStart := regexp .MustCompile (`^------$` )
148+ reError := regexp .MustCompile (`(?i)^error:` )
141149
142150 for scanner .Scan () {
143151 line := scanner .Text ()
144- if strings .HasPrefix (line , "ERROR:" ) || strings .HasPrefix (line , "error:" ) {
145- errors = append (errors , line )
152+
153+ if reSectionStart .MatchString (line ) {
154+ if errSection .Len () > 0 {
155+ break
156+ }
157+ foundSection = true
146158 }
159+
160+ if foundSection {
161+ errSection .WriteString (line + "\n " )
162+ } else if reError .MatchString (line ) {
163+ errSection .WriteString (line + "\n " )
164+ }
165+ }
166+
167+ if err := scanner .Err (); err != nil {
168+ return errSection , fmt .Errorf ("error reading stderr: %w" , err )
147169 }
148- return strings .Join (errors , " " )
170+
171+ return errSection , nil
149172}
150173
151174func setCliArgs (serviceDockerfilePathInContext string , secrets []secrets.Secret ) ([]string , error ) {
0 commit comments