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  }