Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 50 additions & 5 deletions cmd/ci/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,39 +14,64 @@ const (
DefaultGitHubWorkflowDir = ".github/workflows"
DefaultGitHubWorkflowFilename = "func-deploy.yaml"

WorkflowNameFlag = "workflow-name"
DefaultWorkflowName = "Func Deploy"

BranchFlag = "branch"
DefaultBranch = "main"

WorkflowNameFlag = "workflow-name"
DefaultWorkflowName = "Func Deploy"

KubeconfigSecretNameFlag = "kubeconfig-secret-name"
DefaultKubeconfigSecretName = "KUBECONFIG"

RegistryLoginUrlVariableNameFlag = "registry-login-url-variable-name"
DefaultRegistryLoginUrlVariableName = "REGISTRY_LOGIN_URL"

RegistryUserVariableNameFlag = "registry-user-variable-name"
DefaultRegistryUserVariableName = "REGISTRY_USERNAME"

RegistryPassSecretNameFlag = "registry-pass-secret-name"
DefaultRegistryPassSecretName = "REGISTRY_PASSWORD"

RegistryUrlVariableNameFlag = "registry-url-variable-name"
DefaultRegistryUrlVariableName = "REGISTRY_URL"

UseRegistryLoginFlag = "use-registry-login"
DefaultUseRegistryLogin = true

UseSelfHostedRunnerFlag = "self-hosted-runner"
DefaultUseSelfHostedRunner = false
)

// CIConfig readonly configuration
type CIConfig struct {
githubWorkflowDir,
githubWorkflowFilename,
path,
workflowName,
branch,
workflowName,
kubeconfigSecret,
registryLoginUrlVar,
registryUserVar,
registryPassSecret,
registryUrlVar string
useRegistryLogin,
useSelfHostedRunner bool
}

func NewCIGitHubConfig() CIConfig {
return CIConfig{
githubWorkflowDir: DefaultGitHubWorkflowDir,
githubWorkflowFilename: DefaultGitHubWorkflowFilename,
path: viper.GetString(PathFlag),
workflowName: viper.GetString(WorkflowNameFlag),
branch: viper.GetString(BranchFlag),
workflowName: viper.GetString(WorkflowNameFlag),
kubeconfigSecret: viper.GetString(KubeconfigSecretNameFlag),
registryLoginUrlVar: viper.GetString(RegistryLoginUrlVariableNameFlag),
registryUserVar: viper.GetString(RegistryUserVariableNameFlag),
registryPassSecret: viper.GetString(RegistryPassSecretNameFlag),
registryUrlVar: viper.GetString(RegistryUrlVariableNameFlag),
useRegistryLogin: viper.GetBool(UseRegistryLoginFlag),
useSelfHostedRunner: viper.GetBool(UseSelfHostedRunnerFlag),
}
}

Expand All @@ -70,10 +95,30 @@ func (cc *CIConfig) Branch() string {
return cc.branch
}

func (cc *CIConfig) UseRegistryLogin() bool {
return cc.useRegistryLogin
}

func (cc *CIConfig) UseSelfHostedRunner() bool {
return cc.useSelfHostedRunner
}

func (cc *CIConfig) KubeconfigSecret() string {
return cc.kubeconfigSecret
}

func (cc *CIConfig) RegistryLoginUrlVar() string {
return cc.registryLoginUrlVar
}

func (cc *CIConfig) RegistryUserVar() string {
return cc.registryUserVar
}

func (cc *CIConfig) RegistryPassSecret() string {
return cc.registryPassSecret
}

func (cc *CIConfig) RegistryUrlVar() string {
return cc.registryUrlVar
}
89 changes: 66 additions & 23 deletions cmd/ci/workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,30 +34,15 @@ type step struct {
}

func NewGitHubWorkflow(conf CIConfig) *githubWorkflow {
runsOn := "ubuntu-latest"

pushTrigger := newPushTrigger(conf.Branch())
runsOn := createRunsOn(conf.UseSelfHostedRunner())
pushTrigger := createPushTrigger(conf.Branch())

var steps []step
checkoutCode := newStep("Checkout code").
withUses("actions/checkout@v4")
steps = append(steps, *checkoutCode)

setupK8Context := newStep("Setup Kubernetes context").
withUses("azure/k8s-set-context@v4").
withActionConfig("method", "kubeconfig").
withActionConfig("kubeconfig", newSecret(conf.KubeconfigSecret()))
steps = append(steps, *setupK8Context)

installFuncCli := newStep("Install func cli").
withUses("gauron99/knative-func-action@main").
withActionConfig("version", "knative-v1.19.1").
withActionConfig("name", "func")
steps = append(steps, *installFuncCli)

deployFunc := newStep("Deploy function").
withRun("func deploy --registry=" + newVariable(conf.RegistryUrlVar()) + " -v")
steps = append(steps, *deployFunc)
steps = createCheckoutStep(steps)
steps = createK8ContextStep(conf, steps)
steps = createRegistryLoginStep(conf, steps)
steps = createFuncCLIInstallStep(steps)
steps = createFuncDeployStep(conf, steps)
Comment on lines +41 to +45
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like these one line steps, much cleaner :)


return &githubWorkflow{
Name: conf.WorkflowName(),
Expand All @@ -71,14 +56,72 @@ func NewGitHubWorkflow(conf CIConfig) *githubWorkflow {
}
}

func newPushTrigger(branch string) workflowTriggers {
func createRunsOn(useSelfHostedRunner bool) string {
runsOn := "ubuntu-latest"
if useSelfHostedRunner {
runsOn = "self-hosted"
}
return runsOn
}

func createPushTrigger(branch string) workflowTriggers {
result := workflowTriggers{
Push: &pushTrigger{Branches: []string{branch}},
}

return result
}

func createCheckoutStep(steps []step) []step {
checkoutCode := newStep("Checkout code").
withUses("actions/checkout@v4")

return append(steps, *checkoutCode)
}

func createK8ContextStep(conf CIConfig, steps []step) []step {
setupK8Context := newStep("Setup Kubernetes context").
withUses("azure/k8s-set-context@v4").
withActionConfig("method", "kubeconfig").
withActionConfig("kubeconfig", newSecret(conf.KubeconfigSecret()))

return append(steps, *setupK8Context)
}

func createRegistryLoginStep(conf CIConfig, steps []step) []step {
if !conf.UseRegistryLogin() {
return steps
}

loginToContainerRegistry := newStep("Login to container registry").
withUses("docker/login-action@v3").
withActionConfig("registry", newVariable(conf.RegistryLoginUrlVar())).
withActionConfig("username", newVariable(conf.RegistryUserVar())).
withActionConfig("password", newSecret(conf.RegistryPassSecret()))

return append(steps, *loginToContainerRegistry)
}

func createFuncDeployStep(conf CIConfig, steps []step) []step {
registryUrl := newVariable(conf.RegistryUrlVar())
if conf.UseRegistryLogin() {
registryUrl = newVariable(conf.RegistryLoginUrlVar()) + "/" + newVariable(conf.RegistryUserVar())
}
deployFunc := newStep("Deploy function").
withRun("func deploy --registry=" + registryUrl + " -v")

return append(steps, *deployFunc)
}

func createFuncCLIInstallStep(steps []step) []step {
installFuncCli := newStep("Install func cli").
withUses("gauron99/knative-func-action@main").
withActionConfig("version", "knative-v1.19.1").
withActionConfig("name", "func")

return append(steps, *installFuncCli)
}

func newStep(name string) *step {
return &step{Name: name}
}
Expand Down
35 changes: 35 additions & 0 deletions cmd/config_ci.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,14 @@ func NewConfigCICmd(loaderSaver common.FunctionLoaderSaver, writer ci.WorkflowWr
Short: "Generate a GitHub Workflow for function deployment",
PreRunE: bindEnv(
ci.PathFlag,
ci.UseRegistryLoginFlag,
ci.UseSelfHostedRunnerFlag,
ci.WorkflowNameFlag,
ci.BranchFlag,
ci.KubeconfigSecretNameFlag,
ci.RegistryLoginUrlVariableNameFlag,
ci.RegistryUserVariableNameFlag,
ci.RegistryPassSecretNameFlag,
ci.RegistryUrlVariableNameFlag,
),
RunE: func(cmd *cobra.Command, args []string) (err error) {
Expand All @@ -27,6 +32,18 @@ func NewConfigCICmd(loaderSaver common.FunctionLoaderSaver, writer ci.WorkflowWr

addPathFlag(cmd)

cmd.Flags().Bool(
ci.UseRegistryLoginFlag,
ci.DefaultUseRegistryLogin,
"Add a registry login step in the github workflow",
)

cmd.Flags().Bool(
ci.UseSelfHostedRunnerFlag,
ci.DefaultUseSelfHostedRunner,
"Use a 'self-hosted' runner instead of the default 'ubuntu-latest' for local runner execution",
)

cmd.Flags().String(
ci.WorkflowNameFlag,
ci.DefaultWorkflowName,
Expand All @@ -45,6 +62,24 @@ func NewConfigCICmd(loaderSaver common.FunctionLoaderSaver, writer ci.WorkflowWr
"Use a custom secret name in the workflow, e.g. secret.YOUR_CUSTOM_KUBECONFIG",
)

cmd.Flags().String(
ci.RegistryLoginUrlVariableNameFlag,
ci.DefaultRegistryLoginUrlVariableName,
"Use a custom registry login url variable name in the workflow, e.g. vars.YOUR_REGISTRY_LOGIN_URL",
)

cmd.Flags().String(
ci.RegistryUserVariableNameFlag,
ci.DefaultRegistryUserVariableName,
"Use a custom registry user variable name in the workflow, e.g. vars.YOUR_REGISTRY_USER",
)

cmd.Flags().String(
ci.RegistryPassSecretNameFlag,
ci.DefaultRegistryPassSecretName,
"Use a custom registry pass secret name in the workflow, e.g. secret.YOUR_REGISTRY_PASSWORD",
)

cmd.Flags().String(
ci.RegistryUrlVariableNameFlag,
ci.DefaultRegistryUrlVariableName,
Expand Down
62 changes: 58 additions & 4 deletions cmd/config_ci_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,46 @@ func TestNewConfigCICmd_WritesWorkflowFile(t *testing.T) {
}

func TestNewConfigCICmd_WorkflowYAMLHasCorrectStructure(t *testing.T) {
result := runConfigCiCmd(t, unitTestOpts())

assert.NilError(t, result.executeErr)
assertDefaultWorkflow(t, result.gwYamlString)
}

func TestNewConfigCICmd_WorkflowYAMLHasCustomValues(t *testing.T) {
// GIVEN
opts := unitTestOpts()
opts.args = append(opts.args,
"--self-hosted-runner",
"--workflow-name=Custom Deploy",
"--kubeconfig-secret-name=DEV_CLUSTER_KUBECONFIG",
"--registry-login-url-variable-name=DEV_REGISTRY_LOGIN_URL",
"--registry-user-variable-name=DEV_REGISTRY_USER",
"--registry-pass-secret-name=DEV_REGISTRY_PASS",
"--branch=master",
)

// WHEN
result := runConfigCiCmd(t, opts)

// THEN
assert.NilError(t, result.executeErr)
assertDefaultWorkflow(t, result.gwYamlString)
assertCustomWorkflow(t, result.gwYamlString)
}

func TestNewConfigCICmd_WorkflowHasNoRegistryLogin(t *testing.T) {
// GIVEN
opts := unitTestOpts()
opts.args = append(opts.args, "--use-registry-login=false")

// WHEN
result := runConfigCiCmd(t, opts)

// THEN
assert.NilError(t, result.executeErr)
assert.Assert(t, !strings.Contains(result.gwYamlString, "docker/login-action@v3"))
assert.Assert(t, !strings.Contains(result.gwYamlString, "Login to container registry"))
assert.Assert(t, yamlContains(result.gwYamlString, "--registry=${{ vars.REGISTRY_URL }}"))
}

// ---------------------
Expand Down Expand Up @@ -239,7 +274,10 @@ func runConfigCiCmd(
// including the default values which can be changed:
// - runs-on: ubuntu-latest
// - kubeconfig: ${{ secrets.KUBECONFIG }}
// - run: func deploy --registry=${{ vars.REGISTRY_URL }} -v
// - registry: ${{ vars.REGISTRY_LOGIN_URL }}")
// - username: ${{ vars.REGISTRY_USERNAME }}
// - password: ${{ secrets.REGISTRY_PASSWORD }}
// - run: func deploy --registry=${{ vars.REGISTRY_LOGIN_URL }}/${{ vars.REGISTRY_USERNAME }} -v
func assertDefaultWorkflow(t *testing.T, actualGw string) {
t.Helper()

Expand All @@ -248,7 +286,7 @@ func assertDefaultWorkflow(t *testing.T, actualGw string) {

assert.Assert(t, yamlContains(actualGw, "ubuntu-latest"))

assert.Assert(t, strings.Count(actualGw, "- name:") == 4)
assert.Assert(t, strings.Count(actualGw, "- name:") == 5)

assert.Assert(t, yamlContains(actualGw, "Checkout code"))
assert.Assert(t, yamlContains(actualGw, "actions/checkout@v4"))
Expand All @@ -258,13 +296,19 @@ func assertDefaultWorkflow(t *testing.T, actualGw string) {
assert.Assert(t, yamlContains(actualGw, "method: kubeconfig"))
assert.Assert(t, yamlContains(actualGw, "kubeconfig: ${{ secrets.KUBECONFIG }}"))

assert.Assert(t, yamlContains(actualGw, "Login to container registry"))
assert.Assert(t, yamlContains(actualGw, "docker/login-action@v3"))
assert.Assert(t, yamlContains(actualGw, "registry: ${{ vars.REGISTRY_LOGIN_URL }}"))
assert.Assert(t, yamlContains(actualGw, "username: ${{ vars.REGISTRY_USERNAME }}"))
assert.Assert(t, yamlContains(actualGw, "password: ${{ secrets.REGISTRY_PASSWORD }}"))

assert.Assert(t, yamlContains(actualGw, "Install func cli"))
assert.Assert(t, yamlContains(actualGw, "gauron99/knative-func-action@main"))
assert.Assert(t, yamlContains(actualGw, "version: knative-v1.19.1"))
assert.Assert(t, yamlContains(actualGw, "name: func"))

assert.Assert(t, yamlContains(actualGw, "Deploy function"))
assert.Assert(t, yamlContains(actualGw, "func deploy --registry=${{ vars.REGISTRY_URL }} -v"))
assert.Assert(t, yamlContains(actualGw, "func deploy --registry=${{ vars.REGISTRY_LOGIN_URL }}/${{ vars.REGISTRY_USERNAME }} -v"))
}

func yamlContains(yaml, substr string) cmp.Comparison {
Expand All @@ -278,5 +322,15 @@ func yamlContains(yaml, substr string) cmp.Comparison {
}
}

func assertCustomWorkflow(t *testing.T, actualGw string) {
assert.Assert(t, yamlContains(actualGw, "Custom Deploy"))
assert.Assert(t, yamlContains(actualGw, "self-hosted"))
assert.Assert(t, yamlContains(actualGw, "DEV_CLUSTER_KUBECONFIG"))
assert.Assert(t, yamlContains(actualGw, "DEV_REGISTRY_LOGIN_URL"))
assert.Assert(t, yamlContains(actualGw, "DEV_REGISTRY_USER"))
assert.Assert(t, yamlContains(actualGw, "DEV_REGISTRY_PASS"))
assert.Assert(t, yamlContains(actualGw, "- master"))
}

// ----------------------
// END: Testing Framework
Loading