Skip to content

Commit

Permalink
feat: Pipelines as Code - initial support (pack)
Browse files Browse the repository at this point in the history
Signed-off-by: Zbynek Roubalik <zroubalik@gmail.com>
  • Loading branch information
zroubalik committed Mar 3, 2023
1 parent 850adf3 commit c590a85
Show file tree
Hide file tree
Showing 9,152 changed files with 92,179 additions and 16,530 deletions.
The diff you're trying to view is too large. We only load the first 3000 changed files.
18 changes: 14 additions & 4 deletions cmd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ func (s standardLoaderSaver) Save(f fn.Function) error {

var defaultLoaderSaver standardLoaderSaver

func NewConfigCmd(loadSaver functionLoaderSaver) *cobra.Command {
func NewConfigCmd(loadSaver functionLoaderSaver, newClient ClientFactory) *cobra.Command {
cmd := &cobra.Command{
Use: "config",
Short: "Configure a function",
Long: `Configure a function
Interactive prompt that allows configuration of Volume mounts, Environment
Interactive prompt that allows configuration of Git configuration, Volume mounts, Environment
variables, and Labels for a function project present in the current directory
or from the directory specified with --path.
`,
Expand All @@ -65,6 +65,7 @@ or from the directory specified with --path.
addPathFlag(cmd)
addVerboseFlag(cmd, cfg.Verbose)

cmd.AddCommand(NewConfigGitCmd(newClient))
cmd.AddCommand(NewConfigLabelsCmd(loadSaver))
cmd.AddCommand(NewConfigEnvsCmd(loadSaver))
cmd.AddCommand(NewConfigVolumesCmd())
Expand All @@ -84,8 +85,8 @@ func runConfigCmd(cmd *cobra.Command, args []string) (err error) {
Name: "selectedConfig",
Prompt: &survey.Select{
Message: "What do you want to configure?",
Options: []string{"Environment variables", "Volumes", "Labels"},
Default: "Environment variables",
Options: []string{"Git", "Environment variables", "Volumes", "Labels"},
Default: "Git",
},
},
{
Expand Down Expand Up @@ -117,6 +118,9 @@ func runConfigCmd(cmd *cobra.Command, args []string) (err error) {
} else if answers.SelectedConfig == "Labels" {
err = runAddLabelsPrompt(cmd.Context(), function, defaultLoaderSaver)
}
// } else if answers.SelectedConfig == "Git" {
// printGitStatus(function)
// }
case "Remove":
if answers.SelectedConfig == "Volumes" {
err = runRemoveVolumesPrompt(function)
Expand All @@ -125,6 +129,9 @@ func runConfigCmd(cmd *cobra.Command, args []string) (err error) {
} else if answers.SelectedConfig == "Labels" {
err = runRemoveLabelsPrompt(function, defaultLoaderSaver)
}
// } else if answers.SelectedConfig == "Git" {
// printGitStatus(function)
// }
case "List":
if answers.SelectedConfig == "Volumes" {
listVolumes(function)
Expand All @@ -133,6 +140,9 @@ func runConfigCmd(cmd *cobra.Command, args []string) (err error) {
} else if answers.SelectedConfig == "Labels" {
listLabels(function)
}
// } else if answers.SelectedConfig == "Git" {
// printGitStatus(function)
// }
}

return
Expand Down
62 changes: 62 additions & 0 deletions cmd/config_git.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package cmd

import (
"fmt"

"github.com/spf13/cobra"

"knative.dev/func/pkg/config"
fn "knative.dev/func/pkg/functions"
)

func NewConfigGitCmd(newClient ClientFactory) *cobra.Command {
cmd := &cobra.Command{
Use: "git",
Short: "Manage Git configuration of a function",
Long: `Manage Git configuration of a function
Prints Git configuration for a function project present in
the current directory or from the directory specified with --path.
`,
SuggestFor: []string{"gti", "Git", "Gti"},
PreRunE: bindEnv("path"),
RunE: func(cmd *cobra.Command, args []string) (err error) {
return runConfigGitCmd(cmd, newClient)
},
}
// Global Config
cfg, err := config.NewDefault()
if err != nil {
fmt.Fprintf(cmd.OutOrStdout(), "error loading config at '%v'. %v\n", config.File(), err)
}

// Function Context
f, _ := fn.NewFunction(effectivePath())
if f.Initialized() {
cfg = cfg.Apply(f)
}

configGitSetCmd := NewConfigGitSetCmd(newClient)
//configGitRemoveCmd := NewConfigGitRemoveCmd()

addPathFlag(cmd)
addVerboseFlag(cmd, cfg.Verbose)

cmd.AddCommand(configGitSetCmd)

return cmd
}

func runConfigGitCmd(cmd *cobra.Command, newClient ClientFactory) (err error) {
// TODO implement, this is just a mock:
// fmt.Printf("--------------------------- Function Git config ---------------------------\n")
// fmt.Printf("STATUS\t PROPERTY\tVALUE\n")
// fmt.Printf(" ✅\t Git URL:\t%s\n", f.Build.Git.URL)
// fmt.Printf(" ❌\t Builder:\t%s\n", f.Build.Builder)
// fmt.Printf(" \t\t\t - Function configuration has %q but generated Pipelines have \"s2i\", please regenerate.\n\n", f.Build.Builder)
// fmt.Printf(" ✅\t Image: \t%s\n", f.Image)
// fmt.Printf("\n")
// end of mock

return nil
}
259 changes: 259 additions & 0 deletions cmd/config_git_set.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
package cmd

import (
"fmt"

"github.com/AlecAivazis/survey/v2"
"github.com/ory/viper"
"github.com/spf13/cobra"
"knative.dev/func/pkg/config"
fn "knative.dev/func/pkg/functions"
"knative.dev/func/pkg/pipelines"
)

func NewConfigGitSetCmd(newClient ClientFactory) *cobra.Command {
cmd := &cobra.Command{
Use: "set",
Short: "Set Git settings in the function configuration",
Long: `Set Git settings in the function configuration
Interactive prompt to set Git settings in the function project in the current
directory or from the directory specified with --path.
`,
SuggestFor: []string{"add", "ad", "update", "create", "insert", "append"},
PreRunE: bindEnv("path", "builder", "builder-image", "image", "registry"),
RunE: func(cmd *cobra.Command, args []string) (err error) {
return runConfigGitSetCmd(cmd, newClient)
},
}

// Global Config
cfg, err := config.NewDefault()
if err != nil {
fmt.Fprintf(cmd.OutOrStdout(), "error loading config at '%v'. %v\n", config.File(), err)
}

// Function Context
f, _ := fn.NewFunction(effectivePath())
if f.Initialized() {
cfg = cfg.Apply(f)
}

// Flags
//
// Globally-Configurable Flags:
// Options whose value may be defined globally may also exist on the
// contextually relevant function; but sets are flattened via cfg.Apply(f)
cmd.Flags().StringP("builder", "b", cfg.Builder,
fmt.Sprintf("Builder to use when creating the function's container. Currently supported builders are %s.", KnownBuilders()))
cmd.Flags().StringP("registry", "r", cfg.Registry,
"Container registry + registry namespace. (ex 'ghcr.io/myuser'). The full image name is automatically determined using this along with function name. (Env: $FUNC_REGISTRY)")
cmd.Flags().StringP("namespace", "n", cfg.Namespace,
"Deploy into a specific namespace. Will use function's current namespace by default if already deployed, and the currently active namespace if it can be determined. (Env: $FUNC_NAMESPACE)")

// Function-Context Flags:
// Options whose value is avaolable on the function with context only
// (persisted but not globally configurable)
builderImage := f.Build.BuilderImages[f.Build.Builder]
cmd.Flags().StringP("builder-image", "", builderImage,
"Specify a custom builder image for use by the builder other than its default. ($FUNC_BUILDER_IMAGE)")
cmd.Flags().StringP("image", "i", f.Image, "Full image name in the form [registry]/[namespace]/[name]:[tag]@[digest]. This option takes precedence over --registry. Specifying digest is optional, but if it is given, 'build' and 'push' phases are disabled. (Env: $FUNC_IMAGE)")

// TODO enable flags
// cmd.Flags().StringP("git-url", "g", f.Build.Git.URL,
// "Repo url to push the code to be built (Env: $FUNC_GIT_URL)")
// cmd.Flags().StringP("git-branch", "t", f.Build.Git.Revision,
// "Git revision (branch) to be used when deploying via a git repository (Env: $FUNC_GIT_BRANCH)")
// cmd.Flags().StringP("git-dir", "d", f.Build.Git.ContextDir,
// "Directory in the repo to find the function (default is the root) (Env: $FUNC_GIT_DIR)")
// cmd.Flags().BoolP("remote", "", f.Deploy.Remote,
// "Trigger a remote deployment. Default is to deploy and build from the local system (Env: $FUNC_REMOTE)")

addPathFlag(cmd)
addVerboseFlag(cmd, cfg.Verbose)

return cmd
}

type configGitSetConfig struct {
buildConfig // further embeds config.Global

Namespace string

GitURL string
GitRevision string
GitContextDir string

WebhookTrigger bool
WebhookTriggerSet bool // whether WebhookTrigger value has been set
WebhookTriggerAutoConfig bool // whether to configure WebhookTrigger automatically

metadata pipelines.PacMetadata
}

// newConfigGitSetConfig creates a buildConfig populated from command flags and
// environment variables; in that precedence.
func newConfigGitSetConfig(cmd *cobra.Command) (c configGitSetConfig) {
c = configGitSetConfig{
buildConfig: newBuildConfig(),
// TODO enable flags
// GitBranch: viper.GetString("git-branch"),
// GitDir: viper.GetString("git-dir"),
// GitURL: viper.GetString("git-url"),

Namespace: viper.GetString("namespace"),

metadata: pipelines.PacMetadata{
// TODO create cli args to specify whether to configure only specific options
ConfigureLocalResources: true,
ConfigureClusterResources: true,
ConfigureRemoteResources: true,
},
}

return c
}

func (c configGitSetConfig) Prompt(f fn.Function) (configGitSetConfig, error) {
var err error
if c.buildConfig, err = c.buildConfig.Prompt(); err != nil {
return c, err
}

// prompt if git URL hasn't been set previously
if c.GitURL == "" {
// TODO we can try to read git url from the local .git settings
url := f.Build.Git.URL
if err := survey.AskOne(&survey.Input{
Message: "The URL to Git repository with the function source code:",
Default: url,
}, &url, survey.WithValidator(survey.Required)); err != nil {
return c, err
}
c.GitURL = url
}

// prompt if git revision hasn't been set previously
if c.GitRevision == "" {
// TODO we can try to read git url from the local .git settings
revision := f.Build.Git.Revision
if err := survey.AskOne(&survey.Input{
Message: "The Git branch or tag we are targeting:",
Help: "ie: main, refs/tags/*",
Default: revision,
}, &revision); err != nil {
return c, err
}
c.GitRevision = revision
}

// prompt if contextDir hasn't been set previously
if c.GitContextDir == "" {
contextDir := f.Build.Git.ContextDir
if err := survey.AskOne(&survey.Input{
Message: "A subpath within the repository:",
Help: "A subpath within the repository where the source code of a function is located.",
Default: contextDir,
}, &contextDir); err != nil {
return c, err
}
c.GitContextDir = contextDir
}

// prompt if webhook trigger setting hasn't been set previously
if !c.WebhookTriggerSet {
trigger := true
if err := survey.AskOne(&survey.Confirm{
Message: "Do you want to configure webhook trigger?",
Help: "Webhook trigger also running pipeline on a git event, ie: commit, push",
Default: trigger,
}, &trigger, survey.WithValidator(survey.Required)); err != nil {
return c, err
}
c.WebhookTrigger = trigger
c.WebhookTriggerSet = true
}

if c.WebhookTrigger {
// prompt if PersonalAccessToken hasn't been set previously
if c.metadata.PersonalAccessToken == "" {
var personalAccessToken string
if err := survey.AskOne(&survey.Password{
Message: "Please enter the GitHub access token:",
}, &personalAccessToken, survey.WithValidator(survey.Required)); err != nil {
return c, err
}
c.metadata.PersonalAccessToken = personalAccessToken
}

// TODO prompt here if user want to configure remote webhook automatically (default)
// or manauly - print neccesary info then
// ie: c.WebhookTriggerAutoConfig
}

return c, nil
}

func (c configGitSetConfig) Validate(cmd *cobra.Command) (err error) {
// Bubble validation
if err = c.buildConfig.Validate(); err != nil {
return
}

return
}

// Configure the given function. Updates a function struct with all
// configurable values. Note that the config already includes function's
// current values, as they were passed through via flag defaults.
func (c configGitSetConfig) Configure(f fn.Function) (fn.Function, error) {
var err error

// Bubble configure request
//
// The member values on the config object now take absolute precidence
// because they include 1) static config 2) user's global config
// 3) Environment variables and 4) flag values (which were set with their
// default being 1-3).
f = c.buildConfig.Configure(f) // also configures .buildConfig.Global

// Configure basic members
f.Build.Git.URL = c.GitURL
f.Build.Git.ContextDir = c.GitContextDir
f.Build.Git.Revision = c.GitRevision // TODO: should match; perhaps "refSpec"

// Save the function which has now been updated with flags/config
if err = f.Write(); err != nil { // TODO: remove when client API uses 'f'
return f, err
}

return f, nil
}

func runConfigGitSetCmd(cmd *cobra.Command, newClient ClientFactory) (err error) {
var (
cfg configGitSetConfig
f fn.Function
)
if err = config.CreatePaths(); err != nil { // for possible auth.json usage
return
}
cfg = newConfigGitSetConfig(cmd)
if f, err = fn.NewFunction(cfg.Path); err != nil {
return
}
if cfg, err = cfg.Prompt(f); err != nil {
return
}
if err = cfg.Validate(cmd); err != nil {
return
}
if f, err = cfg.Configure(f); err != nil { // Updates f with deploy cfg
return
}

client, done := newClient(ClientConfig{Namespace: cfg.Namespace, Verbose: cfg.Verbose}, fn.WithRegistry(cfg.Registry))
defer done()

return client.ConfigurePAC(cmd.Context(), f, cfg.metadata)
}
Loading

0 comments on commit c590a85

Please sign in to comment.