diff --git a/README.md b/README.md index c53b5f7c..7ea8d00f 100644 --- a/README.md +++ b/README.md @@ -171,6 +171,27 @@ curl -fsSL https://raw.githubusercontent.com/Azure/draft/main/scripts/install.sh * Windows isn't currently supported (you can use WSL) + +## Draft as a Dependency + +If you are looking to leverage Draft's file generation capabilities and templating within another project instead of using the CLI, you have two options: importing the Draft go packages, and wrapping the binary + +### Importing Draft Go Packages +This option will provide the cleanest integration, as it directly builds Draft into your project. However, it requires that your project is written in Go. + +Dockerfiles can be generated following the example in `examples/dockerfile.go` + +Deployment files can be generated following the example in `examples/deployment.go` + +### Wrapping the Binary +For projects written in languages other than Go, or for projects that prefer to not import the packages directly, you can wrap the Draft binary. + +Several features have been implemented to make consuming draft as easy as possible: +- `draft info` prints supported language and field information in json format for easy parsing +- `--dry-run` and `--dry-run-file` flags can be used on the `create` command to generate a summary of the files that would be written to disk, and the variables that would be used in the templates +- `draft update` accepts takes a repeatable `--variable` flag that can be used to set template variables +- `draft create` takes a `--create-config` flag that can be used to input variables through a yaml file instead of interactively + ## Contributing Draft is fully compatible with [Azure Kubernetes Service](https://docs.microsoft.com/azure/aks/draft). We strongly encourage contributions to make Draft available to other cloud providers 😊! diff --git a/example/deployment.go b/example/deployment.go new file mode 100644 index 00000000..6ded0084 --- /dev/null +++ b/example/deployment.go @@ -0,0 +1,65 @@ +package example + +import ( + "fmt" + + "github.com/Azure/draft/pkg/deployments" + "github.com/Azure/draft/pkg/templatewriter" + "github.com/Azure/draft/pkg/templatewriter/writers" + "github.com/Azure/draft/template" +) + +// WriteDeploymentFiles generates Deployment Files using Draft, writing to a Draft TemplateWriter. See the corresponding draft.yaml file in templates/deployments/[deployType] for the template inputs. +func WriteDeploymentFiles(w templatewriter.TemplateWriter, deploymentOutputPath string, deploymentInputs map[string]string, deploymentType string) error { + d := deployments.CreateDeploymentsFromEmbedFS(template.Deployments, deploymentOutputPath) + + err := d.CopyDeploymentFiles(deploymentType, deploymentInputs, w) + if err != nil { + return fmt.Errorf("failed to generate manifest: %e", err) + } + return nil +} + +// WriteDeploymentFilesExample shows how to set up a fileWriter and generate a fileMap using WriteDeploymentFiles +func WriteDeploymentFilesExample() error { + // Create a file map + fileMap := make(map[string][]byte) + + // Create a template writer that writes to the file map + w := writers.FileMapWriter{ + FileMap: fileMap, + } + + // Select the deployment type to generate the files for (must correspond to a directory in the template/deployments directory) + deploymentType := "manifests" + + // Create a map of inputs to the template (must correspond to the inputs in the template/deployments//draft.yaml file) + deploymentInputs := map[string]string{ + "PORT": "8080", + "APPNAME": "example-app", + "SERVICEPORT": "8080", + "NAMESPACE": "example-namespace", + "IMAGENAME": "example-image", + "IMAGETAG": "latest", + } + + // Set the output path for the deployment files + outputPath := "./" + + // Write the deployment files + err := WriteDeploymentFiles(&w, outputPath, deploymentInputs, deploymentType) + if err != nil { + return err + } + + // Read written files from the file map + fmt.Printf("Files written in WriteDeploymentFilesExample:\n") + for filePath, fileContents := range fileMap { + if fileContents == nil { + return fmt.Errorf("file contents for %s is nil", filePath) + } + fmt.Printf(" %s\n", filePath) // Print the file path + } + + return nil +} diff --git a/example/deployment_test.go b/example/deployment_test.go new file mode 100644 index 00000000..d604093a --- /dev/null +++ b/example/deployment_test.go @@ -0,0 +1,64 @@ +package example + +import ( + "fmt" + "testing" + + "github.com/Azure/draft/pkg/templatewriter/writers" +) + +func TestWriteDeploymentFiles(t *testing.T) { + filewriter := writers.FileMapWriter{} + outputPath := "test/path" + + testCases := []struct { + name string + inputVariables map[string]string + deploymentType string + expectError bool + }{ + { + name: "Test Valid Manifests Deployment Generation", + inputVariables: map[string]string{ + "PORT": "8080", + "APPNAME": "testapp", + "SERVICEPORT": "8080", + "NAMESPACE": "testnamespace", + "IMAGENAME": "testimage", + "IMAGETAG": "latest", + }, + deploymentType: "manifests", + expectError: false, + }, + { + name: "Test Invalid Manifests Deployment Generation", + inputVariables: map[string]string{ + "PORT": "8080", + }, + deploymentType: "manifests", + expectError: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := WriteDeploymentFiles(&filewriter, outputPath, tc.inputVariables, tc.deploymentType) + errored := err != nil + if err != nil { + fmt.Printf("WriteDeploymentFiles failed: %e\n", err) + } + if errored != tc.expectError { + t.Errorf("WriteDeploymentFiles failed: expected error %t, got %t", tc.expectError, errored) + t.Fail() + } + }) + } +} + +func TestWriteDeploymentFilesExample(t *testing.T) { + err := WriteDeploymentFilesExample() + if err != nil { + t.Errorf("WriteDockerfileExample failed: %e", err) + t.Fail() + } +} diff --git a/example/dockerfile.go b/example/dockerfile.go new file mode 100644 index 00000000..c6cd6789 --- /dev/null +++ b/example/dockerfile.go @@ -0,0 +1,61 @@ +package example + +import ( + "fmt" + + "github.com/Azure/draft/pkg/languages" + "github.com/Azure/draft/pkg/templatewriter" + "github.com/Azure/draft/pkg/templatewriter/writers" + "github.com/Azure/draft/template" +) + +// WriteDockerfile generates a Dockerfile and dockerignore using Draft, writing to a Draft TemplateWriter. See the corresponding draft.yaml file in templates/dockerfiles/[language] for the template inputs. +func WriteDockerfile(w templatewriter.TemplateWriter, dockerfileOutputPath string, dockerfileInputs map[string]string, generationLanguage string) error { + l := languages.CreateLanguagesFromEmbedFS(template.Dockerfiles, dockerfileOutputPath) + + err := l.CreateDockerfileForLanguage(generationLanguage, dockerfileInputs, w) + if err != nil { + return fmt.Errorf("failed to generate dockerfile: %e", err) + } + return nil +} + +// WriteDockerfileExample shows how to set up a fileWriter and generate a fileMap using WriteDockerfile +func WriteDockerfileExample() error { + // Create a file map + fileMap := make(map[string][]byte) + + // Create a template writer that writes to the file map + w := writers.FileMapWriter{ + FileMap: fileMap, + } + + // Select the language to generate the Dockerfile for (must correspond to a directory in the template/dockerfiles directory) + generationLanguage := "go" + + // Create a map of inputs to the template (must correspond to the inputs in the template/dockerfiles//draft.yaml file) + dockerfileInputs := map[string]string{ + "PORT": "8080", + "VERSION": "1.20", + } + + // Set the output path for the Dockerfile + outputPath := "./" + + // Write the Dockerfile + err := WriteDockerfile(&w, outputPath, dockerfileInputs, generationLanguage) + if err != nil { + return err + } + + // Read written files from the file map + fmt.Printf("Files written in WriteDockerfileExample:\n") + for filePath, fileContents := range fileMap { + if fileContents == nil { + return fmt.Errorf("file contents for %s is nil", filePath) + } + fmt.Printf(" %s\n", filePath) // Print the file path + } + + return nil +} diff --git a/example/dockerfile_test.go b/example/dockerfile_test.go new file mode 100644 index 00000000..624f9952 --- /dev/null +++ b/example/dockerfile_test.go @@ -0,0 +1,69 @@ +package example + +import ( + "fmt" + "testing" + + "github.com/Azure/draft/pkg/templatewriter/writers" +) + +func TestWriteDockerfile(t *testing.T) { + templateWriter := writers.FileMapWriter{} + outputPath := "test/path" + + testCases := []struct { + name string + inputVariables map[string]string + generationLanguage string + expectError bool + }{ + + { + name: "Test Valid Go Dockerfile Generation", + inputVariables: map[string]string{ + "PORT": "8080", + "VERSION": "1.20", + }, + generationLanguage: "go", + expectError: false, + }, + { + name: "Test Invalid Go Dockerfile Generation", + inputVariables: map[string]string{ + "PORT": "8080", + }, + generationLanguage: "go", + expectError: true, + }, + { + name: "Test Invalid GenerationLanguage", + inputVariables: map[string]string{ + "PORT": "8080", + "VERSION": "1.20", + }, + generationLanguage: "invalid", + expectError: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := WriteDockerfile(&templateWriter, outputPath, tc.inputVariables, tc.generationLanguage) + errored := err != nil + if err != nil { + fmt.Printf("WriteDockerfile failed: %e\n", err) + } + if errored != tc.expectError { + t.Errorf("WriteDockerfile failed: expected error %t, got %t", tc.expectError, errored) + t.Fail() + } + }) + } +} + +func TestWriteDockerfileExample(t *testing.T) { + err := WriteDockerfileExample() + if err != nil { + t.Errorf("WriteDockerfileExample failed: %e", err) + } +} diff --git a/pkg/linguist/data/vendor.yml b/pkg/linguist/data/vendor.yml index 26348732..9f23e4cb 100644 --- a/pkg/linguist/data/vendor.yml +++ b/pkg/linguist/data/vendor.yml @@ -328,7 +328,7 @@ - (^|/)extjs/docs/ - (^|/)extjs/builds/ - (^|/)extjs/cmd/ -- (^|/)extjs/examples/ +- (^|/)extjs/example/ - (^|/)extjs/locale/ - (^|/)extjs/packages/ - (^|/)extjs/plugins/ diff --git a/pkg/linguist/static.go b/pkg/linguist/static.go index 95a882d0..8af3e025 100644 --- a/pkg/linguist/static.go +++ b/pkg/linguist/static.go @@ -7741,7 +7741,7 @@ xBase: - (^|/)extjs/docs/ - (^|/)extjs/builds/ - (^|/)extjs/cmd/ -- (^|/)extjs/examples/ +- (^|/)extjs/example/ - (^|/)extjs/locale/ - (^|/)extjs/packages/ - (^|/)extjs/plugins/