From cab11939d0cc09d37ba72cd5767f59aa82f18502 Mon Sep 17 00:00:00 2001 From: Andreas Salhus Bakseter <141913422+baksetercx@users.noreply.github.com> Date: Wed, 4 Dec 2024 10:30:54 +0100 Subject: [PATCH] asdf --- pkg/create/create.go | 15 +++- pkg/githubactions/githubactions.go | 115 ++++++++++++++++++++++------- pkg/githubactions/values.yml.tmpl | 64 ++++++++++++++++ pkg/utils/utils.go | 9 ++- 4 files changed, 172 insertions(+), 31 deletions(-) create mode 100644 pkg/githubactions/values.yml.tmpl diff --git a/pkg/create/create.go b/pkg/create/create.go index b5eb436..97411a2 100644 --- a/pkg/create/create.go +++ b/pkg/create/create.go @@ -48,7 +48,7 @@ var Command *cli.Command = &cli.Command{ &cli.StringFlag{ Name: "github-actions-directory", Aliases: []string{"G"}, - Usage: "The directory where the GitHub Actions workflow should be created. Defaults to .github/workflows under the output directory.", + Usage: "The root directory of your GitHub repository. The path specified will be prepended to '.github/workflows'.", }, }, Action: Create, @@ -128,14 +128,21 @@ func Create(ctx context.Context, c *cli.Command) error { // TODO: depend on template projectDirectory := path.Join(outputDirectory, applicationNamePascalCase) + githubActionsDirectory := func() string { + if c.IsSet("github-actions-directory") { + return c.String("github-actions-directory") + } + return projectDirectory + }() + err := githubactions.CreateDeployWorkflow( - projectDirectory, + githubActionsDirectory, // TODO: depend on template - applicationName+".csproj", + path.Join(projectDirectory, applicationNamePascalCase+".csproj"), c.String("runtime-cloud-provider"), systemName, applicationName, - "", + "", // intentional defaultBranch, nonInteractive, ) diff --git a/pkg/githubactions/githubactions.go b/pkg/githubactions/githubactions.go index 9bf841c..1041ed6 100644 --- a/pkg/githubactions/githubactions.go +++ b/pkg/githubactions/githubactions.go @@ -2,6 +2,7 @@ package githubactions import ( "context" + "embed" "fmt" "io" "net/http" @@ -16,9 +17,13 @@ import ( "github.com/urfave/cli/v3" ) -const commandName = "github-actions" +const ( + commandName = "github-actions" + exampleWorkflowBaseURL = "https://raw.githubusercontent.com/3lvia/.github/refs/heads/trunk/workflow-templates" +) -const exampleWorkflowBaseURL = "https://raw.githubusercontent.com/3lvia/.github/refs/heads/trunk/workflow-templates" +//go:embed values.yml.tmpl +var helmValuesFileTemplate embed.FS var Command *cli.Command = &cli.Command{ Name: commandName, @@ -78,15 +83,15 @@ func CreateDeployWorkflow( nonInteractive bool, ) error { const githubActionsDir = ".github/workflows" - fullPath := path.Join(outputDirectory, githubActionsDir) + fullGithubActionsDir := path.Join(outputDirectory, githubActionsDir) - if _, err := os.Stat(fullPath); os.IsNotExist(err) { + if _, err := os.Stat(fullGithubActionsDir); os.IsNotExist(err) { style.Print( fmt.Sprintf("Creating directory '%s'.\n", githubActionsDir), nil, ) - if err := os.MkdirAll(fullPath, 0755); err != nil { - return fmt.Errorf("Failed to create directory '%s'.", fullPath) + if err := os.MkdirAll(fullGithubActionsDir, 0755); err != nil { + return fmt.Errorf("Failed to create directory '%s'.", fullGithubActionsDir) } } @@ -95,7 +100,15 @@ func CreateDeployWorkflow( return err } - helmValuesFile_, err := resolveHelmValuesFile(helmValuesFile, outputDirectory, nonInteractive) + helmValuesFile_, err := resolveHelmValuesFile( + applicationName, + systemName, + &ResolveHelmValuesFileOptions{ + OutputDirectory: outputDirectory, + HelmValuesFile: helmValuesFile, + NonInteractive: nonInteractive, + }, + ) if err != nil { return err } @@ -106,7 +119,7 @@ func CreateDeployWorkflow( } workflowFileName := fmt.Sprintf("build-deploy-%s.yml", applicationName) - workflowFilePath := filepath.Join(fullPath, workflowFileName) + workflowFilePath := filepath.Join(fullGithubActionsDir, workflowFileName) if err := downloadFile(exampleWorkflowFileURL, workflowFilePath); err != nil { return err @@ -209,6 +222,34 @@ func replaceWorkflowPlaceholders( ) } + // For analyze job + contentsString = strings.ReplaceAll( + contentsString, + fmt.Sprintf( + "# This can be set to a more specific path if you want to analyze only a part of the repository.\n%sworking-directory: '.'", + strings.Repeat(" ", 10), + ), + fmt.Sprintf( + "# This can be set to a more specific path if you want to analyze only a part of the repository.\n%sworking-directory: '%s'", + strings.Repeat(" ", 10), + path.Dir(projectFile), + ), + ) + + // For integration-tests job + contentsString = strings.ReplaceAll( + contentsString, + fmt.Sprintf( + "# This can be set to a more specific path if you want to search for tests in only a part of the repository.\n%sworking-directory: '.'", + strings.Repeat(" ", 10), + ), + fmt.Sprintf( + "# This can be set to a more specific path if you want to search for tests in only a part of the repository.\n%sworking-directory: '%s'", + strings.Repeat(" ", 10), + path.Dir(projectFile), + ), + ) + contentsString = fmt.Sprintf( "# This file was generated by the 3lvia CLI: https://github.com/3lvia/cli\n\n%s", contentsString, @@ -308,13 +349,26 @@ func getExampleWorkflowFileURL(language string, runtimeCloudProvider string) (st ) } -func resolveHelmValuesFile(outputDirectory string, helmValuesFile string, nonInteractive bool) (string, error) { - if helmValuesFile == "" { - const defaultHelmValuesFile = ".github/deploy/values.yml" +type ResolveHelmValuesFileOptions struct { + OutputDirectory string + HelmValuesFile string + NonInteractive bool +} + +func resolveHelmValuesFile( + applicationName string, + systemName string, + options *ResolveHelmValuesFileOptions, +) (string, error) { + if options == nil { + options = &ResolveHelmValuesFileOptions{} + } + if options.HelmValuesFile == "" { + defaultHelmValuesFile := fmt.Sprintf(".github/deploy/values-%s.yml", applicationName) yes, err := utils.PromptYesNo( "You have not provided a Helm values file, which is required for the deployment. Do you want to create a default Helm values file?", - nonInteractive, + options.NonInteractive, ) if err != nil { return "", err @@ -324,29 +378,40 @@ func resolveHelmValuesFile(outputDirectory string, helmValuesFile string, nonInt return "", fmt.Errorf("Helm values file is required for the deployment.") } - newHelmValuesFile := func() string { - if outputDirectory == "" { - return defaultHelmValuesFile - } - return filepath.Join(outputDirectory, defaultHelmValuesFile) - }() - - if err := os.MkdirAll(filepath.Dir(newHelmValuesFile), 0755); err != nil { + if err := os.MkdirAll( + filepath.Dir( + filepath.Join(options.OutputDirectory, defaultHelmValuesFile), + ), + 0755, + ); err != nil { return "", fmt.Errorf("Failed to create directory for Helm values file: %w", err) } - // TODO: use template file - if err := os.WriteFile(newHelmValuesFile, []byte("image:\n tag: latest\n"), 0644); err != nil { - return "", fmt.Errorf("Failed to create default Helm values file: %w", err) + const templateFile = "values.yml.tmpl" + newHelmValuesFile, err := utils.WriteFileWithTemplate( + options.OutputDirectory, + defaultHelmValuesFile, + templateFile, + helmValuesFileTemplate, + struct { + ApplicationName string + SystemName string + }{ + ApplicationName: applicationName, + SystemName: systemName, + }, + ) + if err != nil { + return "", err } style.Print( - fmt.Sprintf("Created default Helm values file at '%s'\n", newHelmValuesFile), + fmt.Sprintf("Created Helm values file at '%s'.\n", newHelmValuesFile), nil, ) return defaultHelmValuesFile, nil } - return helmValuesFile, nil + return options.HelmValuesFile, nil } diff --git a/pkg/githubactions/values.yml.tmpl b/pkg/githubactions/values.yml.tmpl new file mode 100644 index 0000000..1a75716 --- /dev/null +++ b/pkg/githubactions/values.yml.tmpl @@ -0,0 +1,64 @@ +## This is a minimal values file for the elvia-deployment chart. +## An example of all possible usages can be found here: +## https://github.com/3lvia/kubernetes-charts/blob/master/elvia-deployment/values.yaml + +name: {{ .ApplicationName }} +namespace: {{ .SystemName }} +microserviceType: webapi + +replicaCount: 1 + +resources: + limits: + cpu: 100m + memory: 128Mi + requests: + cpu: 100m + memory: 128Mi + +env: +- name: ASPNETCORE_URLS + value: http://+:8080 + +service: + port: 80 + targetPort: 8080 + +## Subdomains are created in https://github.com/3lvia/dns-terraform. +## The CLI does not currently support creating subdomains automatically. +# ingress: +# subdomain: my-subdomain +# path: "/" + +readinessProbe: + failureThreshold: 3 + httpGet: + path: /health + port: 8080 + scheme: HTTP + initialDelaySeconds: 15 + periodSeconds: 15 + successThreshold: 1 + timeoutSeconds: 3 + +livenessProbe: + failureThreshold: 5 + httpGet: + path: /health + port: 8080 + scheme: HTTP + initialDelaySeconds: 15 + periodSeconds: 15 + successThreshold: 1 + timeoutSeconds: 3 + +startupProbe: + failureThreshold: 30 + httpGet: + path: /health + port: 8080 + scheme: HTTP + initialDelaySeconds: 15 + periodSeconds: 3 + successThreshold: 1 + timeoutSeconds: 2 diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index d2f77d2..0eae36f 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -9,6 +9,8 @@ import ( "os/exec" "path" "strings" + + "github.com/3lvia/cli/pkg/style" ) func RemoveZeroValues(slice []string) []string { @@ -116,7 +118,10 @@ func WriteFileWithTemplate( // Will only return false if the response is "n" func PromptYesNo(question string, nonInteractive bool) (bool, error) { - fmt.Printf("%s (Y/n): ", question) + style.Print( + fmt.Sprintf("%s (y/n): ", question), + nil, + ) if nonInteractive { return true, nil } @@ -127,5 +132,5 @@ func PromptYesNo(question string, nonInteractive bool) (bool, error) { return false, fmt.Errorf("Failed to read response: %s", err) } - return strings.ToLower(response) != "n", nil + return strings.ToLower(response) == "y", nil }