@@ -2,6 +2,7 @@ package main
22
33import (
44 "embed"
5+ "errors"
56 "fmt"
67 "github.com/pelletier/go-toml"
78 "github.com/rs/zerolog"
@@ -51,7 +52,6 @@ func main() {
5152 Aliases : []string {"d" },
5253 Usage : "Control docker containers marked with 'framework=ctf' label" ,
5354 Subcommands : []* cli.Command {
54-
5555 {
5656 Name : "clean" ,
5757 Aliases : []string {"rm" },
@@ -64,6 +64,48 @@ func main() {
6464 return nil
6565 },
6666 },
67+ {
68+ Name : "build" ,
69+ Aliases : []string {"c" },
70+ Flags : []cli.Flag {
71+ & cli.StringFlag {
72+ Name : "dockerfile" ,
73+ Aliases : []string {"f" },
74+ Usage : "Path to the Dockerfile" ,
75+ },
76+ & cli.StringFlag {
77+ Name : "context" ,
78+ Aliases : []string {"c" },
79+ Usage : "Build context for the Docker image" ,
80+ },
81+ & cli.StringFlag {
82+ Name : "image_name" ,
83+ Aliases : []string {"n" },
84+ Usage : "Image name" ,
85+ },
86+ },
87+ Usage : "Builds you image and pushes it to a local registry" ,
88+ UsageText : `
89+ Builds your image and pushes it to a local registry.
90+ If you don't have a registry spins it up, default registry is localhost:5050.
91+ It always build with one tag - "latest" and it is useful if you'd like to quickly rebuild some images
92+
93+ Example command for Chainlink image (e2e/capabilities dir):
94+ ctf docker build -f ../../core/chainlink.Dockerfile -c ../.. -n chainlink
95+
96+ You can reference this image in config as:
97+ localhost:5050/chainlink:latest` ,
98+
99+ Action : func (c * cli.Context ) error {
100+ dockerfile := c .String ("dockerfile" )
101+ buildContext := c .String ("context" )
102+ imgName := c .String ("image_name" )
103+ if dockerfile == "" || buildContext == "" || imgName == "" {
104+ return errors .New (`dockerfile, build context and image name must be provided\nex.: -f ./core/chainlink.Dockerfile -c . -n chainlink` )
105+ }
106+ return BuildDocker (dockerfile , buildContext , imgName )
107+ },
108+ },
67109 },
68110 },
69111 {
@@ -234,3 +276,53 @@ func PrettyPrintTOML(inputFile string, outputFile string) error {
234276 framework .L .Info ().Str ("File" , outputFile ).Msg ("File cleaned up and saved" )
235277 return nil
236278}
279+
280+ // BuildDocker runs Docker commands to set up a local registry, build an image, and push it.
281+ func BuildDocker (dockerfile string , buildContext string , imageName string ) error {
282+ registryRunning := isContainerRunning ("local-registry" )
283+ if registryRunning {
284+ fmt .Println ("Local registry container is already running." )
285+ } else {
286+ framework .L .Info ().Msg ("Starting local registry container..." )
287+ err := runCommand ("docker" , "run" , "-d" , "-p" , "5050:5000" , "--name" , "local-registry" , "registry:2" )
288+ if err != nil {
289+ return fmt .Errorf ("failed to start local registry: %w" , err )
290+ }
291+ framework .L .Info ().Msg ("Local registry started" )
292+ }
293+
294+ img := fmt .Sprintf ("localhost:5050/%s:latest" , imageName )
295+ framework .L .Info ().Str ("DockerFile" , dockerfile ).Str ("Context" , buildContext ).Msg ("Building Docker image" )
296+ err := runCommand ("docker" , "build" , "-t" , fmt .Sprintf ("localhost:5050/%s:latest" , imageName ), "-f" , dockerfile , buildContext )
297+ if err != nil {
298+ return fmt .Errorf ("failed to build Docker image: %w" , err )
299+ }
300+ framework .L .Info ().Msg ("Docker image built successfully" )
301+
302+ framework .L .Info ().Str ("Image" , img ).Msg ("Pushing Docker image to local registry" )
303+ fmt .Println ("Pushing Docker image to local registry..." )
304+ err = runCommand ("docker" , "push" , img )
305+ if err != nil {
306+ return fmt .Errorf ("failed to push Docker image: %w" , err )
307+ }
308+ framework .L .Info ().Msg ("Docker image pushed successfully" )
309+ return nil
310+ }
311+
312+ // isContainerRunning checks if a Docker container with the given name is running.
313+ func isContainerRunning (containerName string ) bool {
314+ cmd := exec .Command ("docker" , "ps" , "--filter" , fmt .Sprintf ("name=%s" , containerName ), "--format" , "{{.Names}}" )
315+ output , err := cmd .Output ()
316+ if err != nil {
317+ return false
318+ }
319+ return strings .Contains (string (output ), containerName )
320+ }
321+
322+ // runCommand executes a command and prints the output.
323+ func runCommand (name string , args ... string ) error {
324+ cmd := exec .Command (name , args ... )
325+ cmd .Stdout = os .Stdout
326+ cmd .Stderr = os .Stderr
327+ return cmd .Run ()
328+ }
0 commit comments