github.com/Benchkram/bob@v0.0.0-20220321080157-7c8f3876e225/bob/playground.go (about) 1 package bob 2 3 import ( 4 "errors" 5 "fmt" 6 "io/ioutil" 7 "os" 8 "path/filepath" 9 "strings" 10 11 "github.com/Benchkram/errz" 12 13 "github.com/Benchkram/bob/bob/bobfile" 14 "github.com/Benchkram/bob/bob/global" 15 "github.com/Benchkram/bob/bobrun" 16 "github.com/Benchkram/bob/bobtask" 17 "github.com/Benchkram/bob/bobtask/export" 18 "github.com/Benchkram/bob/pkg/cmdutil" 19 "github.com/Benchkram/bob/pkg/file" 20 ) 21 22 const ( 23 BuildAllTargetName = "all" 24 BuildTargetwithdirsTargetName = "targetwithdirs" 25 BuildAlwaysTargetName = "always-build" 26 27 BuildTargetDockerImageName = "docker-image" 28 BuildTargetDockerImagePlusName = "docker-image-plus" 29 // BuildTargetBobTestImage intentionaly has a path separator 30 // in the image name to assure temporary tar archive generation 31 // works as intended (uses the image name as filename). 32 BuildTargetBobTestImage = "bob/testimage:latest" 33 BuildTargetBobTestImagePlus = "bob/testimage/plus:latest" 34 ) 35 36 func maingo(ver int) []byte { 37 return []byte(fmt.Sprintf(`package main 38 39 import ( 40 "os" 41 "os/signal" 42 ) 43 44 func main() { 45 println("Hello Playground v%d") 46 47 signalChannel := make(chan os.Signal, 1) 48 signal.Notify(signalChannel, os.Interrupt) 49 <-signalChannel 50 println("Byebye Playground v%d") 51 } 52 `, ver, ver)) 53 } 54 55 var gomod = []byte(`module example.com/m 56 57 go 1.16 58 `) 59 60 var openapi = []byte(`openapi: 3.0.3 61 info: 62 version: 1.0.0 63 title: Playground 64 license: 65 name: Benchkram Software GmbH 66 67 paths: 68 /health: 69 get: 70 tags: 71 - system 72 operationId: health 73 responses: 74 200: 75 description: OK 76 503: 77 description: Service Unavailable 78 `) 79 80 var openapiSecondLevel = []byte(`openapi: 3.0.3 81 info: 82 version: 1.0.0 83 title: Playground Second Level 84 license: 85 name: Benchkram Software GmbH 86 87 paths: 88 /second/level/health: 89 get: 90 tags: 91 - system 92 operationId: health 93 responses: 94 200: 95 description: OK 96 503: 97 description: Service Unavailable 98 `) 99 100 var dockerfileAlpine = []byte(`FROM alpine 101 `) 102 103 var dockerfileAlpinePlus = []byte(`FROM alpine 104 RUN touch file 105 `) 106 107 const SecondLevelDir = "second-level" 108 const SecondLevelOpenapiProviderDir = "openapi-provider-project" 109 const ThirdLevelDir = "third-level" 110 111 // CreatePlayground creates a default playground 112 // to test bob workflows. 113 func CreatePlayground(dir string) error { 114 // TODO: check if dir is empty 115 // TODO: empty dir after consent 116 117 err := os.Chdir(dir) 118 errz.Fatal(err) 119 120 // first level 121 err = ioutil.WriteFile("go.mod", gomod, 0644) 122 errz.Fatal(err) 123 err = ioutil.WriteFile("main1.go", maingo(1), 0644) 124 errz.Fatal(err) 125 err = ioutil.WriteFile("openapi.yaml", openapi, 0644) 126 errz.Fatal(err) 127 err = ioutil.WriteFile("docker-compose.yml", dockercompose, 0644) 128 errz.Fatal(err) 129 err = ioutil.WriteFile("docker-compose.whoami.yml", dockercomposewhoami, 0644) 130 errz.Fatal(err) 131 err = ioutil.WriteFile("Dockerfile", dockerfileAlpine, 0644) 132 errz.Fatal(err) 133 err = ioutil.WriteFile("Dockerfile.plus", dockerfileAlpinePlus, 0644) 134 errz.Fatal(err) 135 136 err = createPlaygroundBobfile(".", true) 137 errz.Fatal(err) 138 139 b := newBob() 140 err = b.Init() 141 if err != nil { 142 if !errors.Is(err, ErrWorkspaceAlreadyInitialised) { 143 errz.Fatal(err) 144 } 145 } 146 147 // Create Git repo 148 err = ioutil.WriteFile(filepath.Join(b.dir, ".gitignore"), []byte( 149 ""+ 150 SecondLevelDir+"\n"+ 151 SecondLevelOpenapiProviderDir+"\n", 152 ), 0644) 153 errz.Fatal(err) 154 err = cmdutil.RunGit(b.dir, "init") 155 errz.Fatal(err) 156 err = cmdutil.RunGit(b.dir, "add", "-A") 157 errz.Fatal(err) 158 err = cmdutil.RunGit(b.dir, "commit", "-m", "Initial commit") 159 errz.Fatal(err) 160 161 // second level 162 err = os.MkdirAll(SecondLevelDir, 0755) 163 errz.Fatal(err) 164 err = ioutil.WriteFile(filepath.Join(SecondLevelDir, "go.mod"), gomod, 0644) 165 errz.Fatal(err) 166 err = ioutil.WriteFile(filepath.Join(SecondLevelDir, "main2.go"), maingo(2), 0644) 167 errz.Fatal(err) 168 169 b = newBob() 170 b.dir = filepath.Join(b.dir, SecondLevelDir) 171 err = b.init() 172 if err != nil { 173 if !errors.Is(err, ErrWorkspaceAlreadyInitialised) { 174 errz.Fatal(err) 175 } 176 } 177 178 err = createPlaygroundBobfileSecondLevel(b.dir, true) 179 errz.Fatal(err) 180 181 err = ioutil.WriteFile(filepath.Join(SecondLevelDir, "openapi.yaml"), openapiSecondLevel, 0644) 182 errz.Fatal(err) 183 184 // Create Git repo 185 err = ioutil.WriteFile(filepath.Join(b.dir, ".gitignore"), []byte( 186 ""+ 187 ThirdLevelDir+"\n", 188 ), 0644) 189 errz.Fatal(err) 190 err = cmdutil.RunGit(b.dir, "init") 191 errz.Fatal(err) 192 err = cmdutil.RunGit(b.dir, "add", "-A") 193 errz.Fatal(err) 194 err = cmdutil.RunGit(b.dir, "commit", "-m", "Initial commit") 195 errz.Fatal(err) 196 197 // second level - openapi-provider 198 err = os.MkdirAll(SecondLevelOpenapiProviderDir, 0755) 199 errz.Fatal(err) 200 err = ioutil.WriteFile(filepath.Join(SecondLevelOpenapiProviderDir, "openapi.yaml"), openapi, 0644) 201 errz.Fatal(err) 202 err = ioutil.WriteFile(filepath.Join(SecondLevelOpenapiProviderDir, "openapi2.yaml"), openapi, 0644) 203 errz.Fatal(err) 204 err = createPlaygroundBobfileSecondLevelOpenapiProvider(SecondLevelOpenapiProviderDir, true) 205 errz.Fatal(err) 206 207 // Create Git repo 208 err = cmdutil.RunGit(SecondLevelOpenapiProviderDir, "init") 209 errz.Fatal(err) 210 err = cmdutil.RunGit(SecondLevelOpenapiProviderDir, "add", "-A") 211 errz.Fatal(err) 212 err = cmdutil.RunGit(SecondLevelOpenapiProviderDir, "commit", "-m", "Initial commit") 213 errz.Fatal(err) 214 215 // third level 216 thirdDir := filepath.Join(SecondLevelDir, ThirdLevelDir) 217 err = os.MkdirAll(thirdDir, 0755) 218 errz.Fatal(err) 219 err = ioutil.WriteFile(filepath.Join(thirdDir, "go.mod"), gomod, 0644) 220 errz.Fatal(err) 221 err = ioutil.WriteFile(filepath.Join(thirdDir, "main3.go"), maingo(3), 0644) 222 errz.Fatal(err) 223 224 b3 := newBob() 225 b3.dir = filepath.Join(b3.dir, thirdDir) 226 err = b3.init() 227 if err != nil { 228 if !errors.Is(err, ErrWorkspaceAlreadyInitialised) { 229 errz.Fatal(err) 230 } 231 } 232 233 err = createPlaygroundBobfileThirdLevel(b3.dir, true) 234 errz.Fatal(err) 235 236 err = ioutil.WriteFile(filepath.Join(thirdDir, "openapi.yaml"), openapiSecondLevel, 0644) 237 errz.Fatal(err) 238 239 // Create Git repo 240 err = cmdutil.RunGit(b3.dir, "init") 241 errz.Fatal(err) 242 err = cmdutil.RunGit(b3.dir, "add", "-A") 243 errz.Fatal(err) 244 err = cmdutil.RunGit(b3.dir, "commit", "-m", "Initial commit") 245 errz.Fatal(err) 246 247 return nil 248 } 249 250 func createPlaygroundBobfile(dir string, overwrite bool) (err error) { 251 // Prevent accidential bobfile override 252 if file.Exists(global.BobFileName) && !overwrite { 253 return bobfile.ErrBobfileExists 254 } 255 256 bobfile := bobfile.NewBobfile() 257 258 bobfile.Variables["helloworld"] = "Hello World!" 259 260 bobfile.BTasks[global.DefaultBuildTask] = bobtask.Task{ 261 InputDirty: "./main1.go" + "\n" + "go.mod", 262 CmdDirty: "go build -o run", 263 TargetDirty: "run", 264 RebuildDirty: string(bobtask.RebuildOnChange), 265 } 266 267 bobfile.BTasks[BuildAllTargetName] = bobtask.Task{ 268 InputDirty: "./main1.go", 269 CmdDirty: "go build -o run", 270 DependsOn: []string{ 271 filepath.Join(SecondLevelDir, fmt.Sprintf("%s2", global.DefaultBuildTask)), 272 filepath.Join(SecondLevelDir, ThirdLevelDir, "print"), 273 }, 274 TargetDirty: "run", 275 RebuildDirty: string(bobtask.RebuildOnChange), 276 } 277 278 bobfile.BTasks[BuildAlwaysTargetName] = bobtask.Task{ 279 InputDirty: "./main1.go" + "\n" + "go.mod", 280 CmdDirty: "go build -o run", 281 TargetDirty: "run", 282 RebuildDirty: string(bobtask.RebuildAlways), 283 } 284 285 bobfile.BTasks["generate"] = bobtask.Task{ 286 InputDirty: "openapi.yaml", 287 CmdDirty: strings.Join([]string{ 288 "mkdir -p rest-server/generated", 289 "oapi-codegen -package generated -generate server \\\n\t${OPENAPI_PROVIDER_PROJECT_OPENAPI_OPENAPI} \\\n\t\t> rest-server/generated/server.gen.go", 290 "oapi-codegen -package generated -generate types \\\n\t${OPENAPI_PROVIDER_PROJECT_OPENAPI_OPENAPI} \\\n\t\t> rest-server/generated/types.gen.go", 291 "oapi-codegen -package generated -generate client \\\n\t${OPENAPI_PROVIDER_PROJECT_OPENAPI_OPENAPI} \\\n\t\t> rest-server/generated/client.gen.go", 292 }, "\n"), 293 DependsOn: []string{ 294 filepath.Join(SecondLevelOpenapiProviderDir, "openapi"), 295 }, 296 TargetDirty: strings.Join([]string{ 297 "rest-server/generated/server.gen.go", 298 "rest-server/generated/types.gen.go", 299 "rest-server/generated/client.gen.go", 300 }, "\n"), 301 } 302 303 bobfile.BTasks["slow"] = bobtask.Task{ 304 CmdDirty: strings.Join([]string{ 305 "sleep 2", 306 "touch slowdone", 307 }, "\n"), 308 TargetDirty: "slowdone", 309 } 310 311 // A run command to run a environment from a compose file 312 bobfile.RTasks["environment"] = &bobrun.Run{ 313 Type: bobrun.RunTypeCompose, 314 } 315 316 bobfile.RTasks["whoami"] = &bobrun.Run{ 317 Type: bobrun.RunTypeCompose, 318 Path: "docker-compose.whoami.yml", 319 DependsOn: []string{ 320 "all", 321 "environment", 322 }, 323 } 324 325 // A run command to run a binary 326 bobfile.RTasks["binary"] = &bobrun.Run{ 327 Type: bobrun.RunTypeBinary, 328 Path: "./run", 329 DependsOn: []string{ 330 "all", 331 "environment", 332 }, 333 } 334 335 bobfile.BTasks["print"] = bobtask.Task{ 336 CmdDirty: "echo ${HELLOWORLD}", 337 } 338 339 bobfile.BTasks["multilinetouch"] = bobtask.Task{ 340 CmdDirty: strings.Join([]string{ 341 "mkdir -p \\\nmultilinetouch", 342 "touch \\\n\tmultilinefile1 \\\n\tmultilinefile2 \\\n\t\tmultilinefile3 \\\n multilinefile4", 343 "touch \\\n multilinefile5", 344 }, "\n"), 345 } 346 347 bobfile.BTasks["ignoredInputs"] = bobtask.Task{ 348 InputDirty: "fileToWatch" + "\n" + "!fileToIgnore", 349 CmdDirty: "echo \"Hello from ignored inputs task\"", 350 } 351 352 bobfile.BTasks[BuildTargetwithdirsTargetName] = bobtask.Task{ 353 CmdDirty: strings.Join([]string{ 354 "mkdir -p .bbuild/dirone/dirtwo", 355 "touch .bbuild/dirone/fileone", 356 "touch .bbuild/dirone/filetwo", 357 "touch .bbuild/dirone/dirtwo/fileone", 358 "touch .bbuild/dirone/dirtwo/filetwo", 359 }, "\n"), 360 TargetDirty: ".bbuild/dirone/", 361 } 362 363 m := make(map[string]interface{}) 364 m["image"] = BuildTargetBobTestImage 365 bobfile.BTasks[BuildTargetDockerImageName] = bobtask.Task{ 366 CmdDirty: strings.Join([]string{ 367 fmt.Sprintf("docker build -t %s .", BuildTargetBobTestImage), 368 }, "\n"), 369 TargetDirty: m, 370 } 371 372 m = make(map[string]interface{}) 373 m["image"] = BuildTargetBobTestImagePlus 374 bobfile.BTasks[BuildTargetDockerImagePlusName] = bobtask.Task{ 375 CmdDirty: strings.Join([]string{ 376 fmt.Sprintf("docker build -f Dockerfile.plus -t %s .", BuildTargetBobTestImagePlus), 377 }, "\n"), 378 TargetDirty: m, 379 } 380 381 return bobfile.BobfileSave(dir) 382 } 383 384 func createPlaygroundBobfileSecondLevelOpenapiProvider(dir string, overwrite bool) (err error) { 385 // Prevent accidential bobfile override 386 if file.Exists(global.BobFileName) && !overwrite { 387 return bobfile.ErrBobfileExists 388 } 389 390 bobfile := bobfile.NewBobfile() 391 392 exports := make(export.Map) 393 exports["openapi"] = "openapi.yaml" 394 exports["openapi2"] = "openapi2.yaml" 395 bobfile.BTasks["openapi"] = bobtask.Task{ 396 Exports: exports, 397 } 398 return bobfile.BobfileSave(dir) 399 } 400 401 func createPlaygroundBobfileSecondLevel(dir string, overwrite bool) (err error) { 402 // Prevent accidential bobfile override 403 if file.Exists(global.BobFileName) && !overwrite { 404 return bobfile.ErrBobfileExists 405 } 406 407 bobfile := bobfile.NewBobfile() 408 bobfile.Version = "1.2.3" 409 410 bobfile.BTasks[fmt.Sprintf("%s2", global.DefaultBuildTask)] = bobtask.Task{ 411 InputDirty: "./main2.go", 412 DependsOn: []string{ 413 filepath.Join(ThirdLevelDir, fmt.Sprintf("%s3", global.DefaultBuildTask)), 414 }, 415 CmdDirty: "go build -o runsecondlevel", 416 TargetDirty: "runsecondlevel", 417 } 418 return bobfile.BobfileSave(dir) 419 } 420 421 func createPlaygroundBobfileThirdLevel(dir string, overwrite bool) (err error) { 422 // Prevent accidential bobfile override 423 if file.Exists(global.BobFileName) && !overwrite { 424 return bobfile.ErrBobfileExists 425 } 426 427 bobfile := bobfile.NewBobfile() 428 bobfile.Version = "4.5.6" 429 430 bobfile.BTasks[fmt.Sprintf("%s3", global.DefaultBuildTask)] = bobtask.Task{ 431 InputDirty: "*", 432 CmdDirty: "go build -o runthirdlevel", 433 TargetDirty: "runthirdlevel", 434 } 435 436 bobfile.BTasks["print"] = bobtask.Task{ 437 CmdDirty: "echo hello-third-level", 438 } 439 440 return bobfile.BobfileSave(dir) 441 }