Skip to content

Commit fa6bc4a

Browse files
authored
Merge pull request #18077 from justinsb/aiconformance_html_output
[aiconformance]: render markdown to HTML
2 parents 0675862 + 7089cd1 commit fa6bc4a

5 files changed

Lines changed: 200 additions & 11 deletions

File tree

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
module k8s.io/kops/tests/e2e/scenarios/ai-conformance
2+
3+
go 1.25.8
4+
5+
require (
6+
github.com/yuin/goldmark v1.7.16
7+
k8s.io/apimachinery v0.35.2
8+
k8s.io/client-go v0.35.2
9+
)
10+
11+
require (
12+
github.com/davecgh/go-spew v1.1.1 // indirect
13+
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
14+
github.com/go-logr/logr v1.4.3 // indirect
15+
github.com/json-iterator/go v1.1.12 // indirect
16+
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
17+
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
18+
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
19+
github.com/spf13/pflag v1.0.9 // indirect
20+
github.com/x448/float16 v0.8.4 // indirect
21+
go.yaml.in/yaml/v2 v2.4.3 // indirect
22+
golang.org/x/net v0.47.0 // indirect
23+
golang.org/x/oauth2 v0.30.0 // indirect
24+
golang.org/x/sys v0.38.0 // indirect
25+
golang.org/x/term v0.37.0 // indirect
26+
golang.org/x/text v0.31.0 // indirect
27+
golang.org/x/time v0.9.0 // indirect
28+
gopkg.in/inf.v0 v0.9.1 // indirect
29+
k8s.io/klog/v2 v2.130.1 // indirect
30+
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 // indirect
31+
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect
32+
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
33+
sigs.k8s.io/randfill v1.0.0 // indirect
34+
sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect
35+
sigs.k8s.io/yaml v1.6.0 // indirect
36+
)
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
2+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
3+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
4+
github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU=
5+
github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
6+
github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
7+
github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
8+
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
9+
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
10+
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
11+
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
12+
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
13+
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
14+
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
15+
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
16+
github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo=
17+
github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ=
18+
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
19+
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
20+
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
21+
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
22+
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
23+
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
24+
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
25+
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
26+
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
27+
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
28+
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
29+
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
30+
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
31+
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
32+
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
33+
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8=
34+
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
35+
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
36+
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
37+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
38+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
39+
github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY=
40+
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
41+
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
42+
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
43+
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
44+
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
45+
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
46+
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
47+
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
48+
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
49+
github.com/yuin/goldmark v1.7.16 h1:n+CJdUxaFMiDUNnWC3dMWCIQJSkxH4uz3ZwQBkAlVNE=
50+
github.com/yuin/goldmark v1.7.16/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg=
51+
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
52+
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
53+
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
54+
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
55+
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
56+
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
57+
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
58+
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
59+
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
60+
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
61+
golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
62+
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
63+
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
64+
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
65+
golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=
66+
golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
67+
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
68+
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
69+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
70+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
71+
gopkg.in/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo=
72+
gopkg.in/evanphx/json-patch.v4 v4.13.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
73+
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
74+
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
75+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
76+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
77+
k8s.io/api v0.35.2 h1:tW7mWc2RpxW7HS4CoRXhtYHSzme1PN1UjGHJ1bdrtdw=
78+
k8s.io/api v0.35.2/go.mod h1:7AJfqGoAZcwSFhOjcGM7WV05QxMMgUaChNfLTXDRE60=
79+
k8s.io/apimachinery v0.35.2 h1:NqsM/mmZA7sHW02JZ9RTtk3wInRgbVxL8MPfzSANAK8=
80+
k8s.io/apimachinery v0.35.2/go.mod h1:jQCgFZFR1F4Ik7hvr2g84RTJSZegBc8yHgFWKn//hns=
81+
k8s.io/client-go v0.35.2 h1:YUfPefdGJA4aljDdayAXkc98DnPkIetMl4PrKX97W9o=
82+
k8s.io/client-go v0.35.2/go.mod h1:4QqEwh4oQpeK8AaefZ0jwTFJw/9kIjdQi0jpKeYvz7g=
83+
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
84+
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
85+
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 h1:Y3gxNAuB0OBLImH611+UDZcmKS3g6CthxToOb37KgwE=
86+
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ=
87+
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck=
88+
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
89+
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg=
90+
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
91+
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
92+
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
93+
sigs.k8s.io/structured-merge-diff/v6 v6.3.0 h1:jTijUJbW353oVOd9oTlifJqOGEkUw2jB/fXCbTiQEco=
94+
sigs.k8s.io/structured-merge-diff/v6 v6.3.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
95+
sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=
96+
sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=

tests/e2e/scenarios/ai-conformance/validators/exec.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ func (h *ValidatorHarness) ShellExec(shellCommand string) *CommandResult {
3030
var stderr bytes.Buffer
3131
cmd.Stderr = &stderr
3232

33-
h.Logf("ShellExec(%q)", shellCommand)
33+
h.output.BeforeShellExec(shellCommand)
3434
err := cmd.Run()
3535

3636
result := &CommandResult{
@@ -39,7 +39,7 @@ func (h *ValidatorHarness) ShellExec(shellCommand string) *CommandResult {
3939
err: err,
4040
}
4141

42-
h.output.OnShellExec(shellCommand, result)
42+
h.output.AfterShellExec(shellCommand, result)
4343

4444
if err != nil {
4545
h.Logf("Command failed: %q", shellCommand)

tests/e2e/scenarios/ai-conformance/validators/markdown.go

Lines changed: 62 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,23 @@ limitations under the License.
1717
package validators
1818

1919
import (
20+
"bytes"
2021
"fmt"
2122
"os"
2223
"path/filepath"
2324
"strings"
2425
"testing"
26+
27+
"github.com/yuin/goldmark"
2528
)
2629

2730
// MarkdownOutput is an implementation of OutputSink that writes output in Markdown format to a file.
2831
type MarkdownOutput struct {
2932
f *os.File
3033
t *testing.T
34+
35+
// outputPath is the path to the markdown file being written, used for rendering HTML output alongside it.
36+
outputPath string
3137
}
3238

3339
// WriteText writes the given plain text to the markdown file.
@@ -46,22 +52,71 @@ func (o *MarkdownOutput) Skip(message string) {
4652
o.printf("&warning; SKIPPED: %s\n", message)
4753
}
4854

49-
// Close closes the underlying file. It should be called when all output is done.
55+
// Close closes the underlying file and renders an HTML version alongside it.
5056
func (o *MarkdownOutput) Close() error {
51-
return o.f.Close()
57+
if err := o.f.Close(); err != nil {
58+
return err
59+
}
60+
61+
if err := o.renderHTML(); err != nil {
62+
o.t.Errorf("failed to render HTML: %v", err)
63+
}
64+
65+
return nil
5266
}
5367

54-
// OnShellExec writes the executed shell command and its output to the markdown file in a formatted code block.
55-
func (o *MarkdownOutput) OnShellExec(command string, results *CommandResult) {
68+
// renderHTML reads the markdown file and renders an HTML version alongside it.
69+
func (o *MarkdownOutput) renderHTML() error {
70+
mdBytes, err := os.ReadFile(o.outputPath)
71+
if err != nil {
72+
return fmt.Errorf("reading markdown file: %w", err)
73+
}
74+
75+
var htmlBody bytes.Buffer
76+
if err := goldmark.Convert(mdBytes, &htmlBody); err != nil {
77+
return fmt.Errorf("converting markdown to HTML: %w", err)
78+
}
79+
80+
title := strings.TrimSuffix(filepath.Base(o.outputPath), ".md")
81+
82+
var htmlOut bytes.Buffer
83+
htmlOut.WriteString("<!DOCTYPE html>\n<html>\n<head>\n")
84+
htmlOut.WriteString("<meta charset=\"utf-8\">\n")
85+
fmt.Fprintf(&htmlOut, "<title>%s</title>\n", title)
86+
htmlOut.WriteString("<style>\n")
87+
htmlOut.WriteString("body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif; max-width: 900px; margin: 40px auto; padding: 0 20px; line-height: 1.6; color: #24292e; }\n")
88+
htmlOut.WriteString("pre { background: #f6f8fa; padding: 16px; border-radius: 6px; overflow-x: auto; }\n")
89+
htmlOut.WriteString("code { background: #f6f8fa; padding: 2px 6px; border-radius: 3px; font-size: 85%; }\n")
90+
htmlOut.WriteString("pre code { background: none; padding: 0; }\n")
91+
htmlOut.WriteString("</style>\n")
92+
htmlOut.WriteString("</head>\n<body>\n")
93+
htmlOut.Write(htmlBody.Bytes())
94+
htmlOut.WriteString("</body>\n</html>\n")
95+
96+
htmlPath := strings.TrimSuffix(o.outputPath, ".md") + ".html"
97+
if err := os.WriteFile(htmlPath, htmlOut.Bytes(), 0644); err != nil {
98+
return fmt.Errorf("writing HTML file: %w", err)
99+
}
100+
101+
return nil
102+
}
103+
104+
// BeforeShellExec writes the executed shell command to the markdown file in a formatted code block.
105+
func (o *MarkdownOutput) BeforeShellExec(command string) {
56106
o.printf("```bash\n> %s\n", command)
107+
o.printf("```\n")
108+
}
109+
110+
// AfterShellExec writes the result of the executed shell command to the markdown file in a formatted code block.
111+
func (o *MarkdownOutput) AfterShellExec(command string, results *CommandResult) {
112+
o.printf("```bash")
57113
o.printf("%s", results.Stdout())
58114
o.printf("%s", results.Stderr())
115+
o.printf("```\n")
59116

60117
if results.Err() != nil {
61118
o.printf("Error:\n```\n%v\n```\n", results.Err())
62119
}
63-
64-
o.printf("```\n")
65120
}
66121

67122
// printf is a helper method to write formatted text to the markdown file.
@@ -91,6 +146,6 @@ func createMarkdownOutput(t *testing.T) OutputSink {
91146
if err != nil {
92147
t.Fatalf("failed to create markdown file: %v", err)
93148
}
94-
output := &MarkdownOutput{f: outputFile, t: t}
149+
output := &MarkdownOutput{f: outputFile, t: t, outputPath: outputPath}
95150
return output
96151
}

tests/e2e/scenarios/ai-conformance/validators/output.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,10 @@ type OutputSink interface {
2727
// WriteText writes a text string to the output sink.
2828
WriteText(text string)
2929

30-
// OnShellExec is called when a shell command is executed, with the command, its stdout, stderr, and any error that occurred.
31-
OnShellExec(command string, results *CommandResult)
30+
// BeforeShellExec is called when a shell command is about to be executed, with the command string.
31+
BeforeShellExec(command string)
32+
// AfterShellExec is called when a shell command has been executed, with the command, its stdout, stderr, and any error that occurred.
33+
AfterShellExec(command string, results *CommandResult)
3234

3335
// Success indicates a successful check, allowing the output sink to format it accordingly.
3436
Success(text string)

0 commit comments

Comments
 (0)