diff --git a/.mockery.yml b/.mockery.yml
index fba11d2..77eb5b0 100644
--- a/.mockery.yml
+++ b/.mockery.yml
@@ -42,3 +42,7 @@ packages:
config:
all: true
interfaces:
+ github.com/codesphere-cloud/oms/pkg/codesphere:
+ config:
+ all: true
+ interfaces:
diff --git a/NOTICE b/NOTICE
index d7e513d..3bef1f0 100644
--- a/NOTICE
+++ b/NOTICE
@@ -22,10 +22,10 @@ License: MIT
License URL: https://github.com/clipperhouse/uax29/blob/v2.3.0/LICENSE
----------
-Module: github.com/codesphere-cloud/cs-go/pkg/io
-Version: v0.14.1
+Module: github.com/codesphere-cloud/cs-go
+Version: v0.15.0
License: Apache-2.0
-License URL: https://github.com/codesphere-cloud/cs-go/blob/v0.14.1/LICENSE
+License URL: https://github.com/codesphere-cloud/cs-go/blob/v0.15.0/LICENSE
----------
Module: github.com/codesphere-cloud/oms/internal/tmpl
@@ -77,9 +77,9 @@ License URL: https://github.com/inconshreveable/go-update/blob/8152e7eb6ccf/inte
----------
Module: github.com/jedib0t/go-pretty/v6
-Version: v6.7.5
+Version: v6.7.7
License: MIT
-License URL: https://github.com/jedib0t/go-pretty/blob/v6.7.5/LICENSE
+License URL: https://github.com/jedib0t/go-pretty/blob/v6.7.7/LICENSE
----------
Module: github.com/mattn/go-runewidth
@@ -155,9 +155,9 @@ License URL: https://github.com/yaml/go-yaml/blob/v3.0.4/LICENSE
----------
Module: golang.org/x/crypto
-Version: v0.45.0
+Version: v0.46.0
License: BSD-3-Clause
-License URL: https://cs.opensource.google/go/x/crypto/+/v0.45.0:LICENSE
+License URL: https://cs.opensource.google/go/x/crypto/+/v0.46.0:LICENSE
----------
Module: golang.org/x/oauth2
@@ -167,9 +167,15 @@ License URL: https://cs.opensource.google/go/x/oauth2/+/v0.33.0:LICENSE
----------
Module: golang.org/x/text
-Version: v0.31.0
+Version: v0.32.0
License: BSD-3-Clause
-License URL: https://cs.opensource.google/go/x/text/+/v0.31.0:LICENSE
+License URL: https://cs.opensource.google/go/x/text/+/v0.32.0:LICENSE
+
+----------
+Module: gopkg.in/validator.v2
+Version: v2.0.1
+License: Apache-2.0
+License URL: https://github.com/go-validator/validator/blob/v2.0.1/LICENSE
----------
Module: gopkg.in/yaml.v3
diff --git a/cli/cmd/root.go b/cli/cmd/root.go
index 43d08c3..10afd54 100644
--- a/cli/cmd/root.go
+++ b/cli/cmd/root.go
@@ -72,6 +72,9 @@ func GetRootCmd() *cobra.Command {
AddRegisterCmd(rootCmd, opts)
AddRevokeCmd(rootCmd, opts)
+ // Smoke test commands
+ AddSmoketestCmd(rootCmd, opts)
+
return rootCmd
}
diff --git a/cli/cmd/smoketest.go b/cli/cmd/smoketest.go
new file mode 100644
index 0000000..a19ba4a
--- /dev/null
+++ b/cli/cmd/smoketest.go
@@ -0,0 +1,27 @@
+// Copyright (c) Codesphere Inc.
+// SPDX-License-Identifier: Apache-2.0
+
+package cmd
+
+import (
+ "github.com/codesphere-cloud/cs-go/pkg/io"
+ "github.com/spf13/cobra"
+)
+
+// SmoketestCmd represents the smoketest command
+type SmoketestCmd struct {
+ cmd *cobra.Command
+}
+
+func AddSmoketestCmd(rootCmd *cobra.Command, opts *GlobalOptions) {
+ smoketest := SmoketestCmd{
+ cmd: &cobra.Command{
+ Use: "smoketest",
+ Short: "Run smoke tests for Codesphere components",
+ Long: io.Long(`Run automated smoke tests for Codesphere installations to verify functionality.`),
+ },
+ }
+ rootCmd.AddCommand(smoketest.cmd)
+
+ AddSmoketestCodesphereCmd(smoketest.cmd, opts)
+}
diff --git a/cli/cmd/smoketest_codesphere.go b/cli/cmd/smoketest_codesphere.go
new file mode 100644
index 0000000..caedace
--- /dev/null
+++ b/cli/cmd/smoketest_codesphere.go
@@ -0,0 +1,322 @@
+// Copyright (c) Codesphere Inc.
+// SPDX-License-Identifier: Apache-2.0
+
+package cmd
+
+import (
+ "context"
+ "fmt"
+ "slices"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/codesphere-cloud/cs-go/pkg/io"
+ "github.com/codesphere-cloud/oms/internal/codesphere"
+ "github.com/codesphere-cloud/oms/internal/util"
+ "github.com/spf13/cobra"
+)
+
+const (
+ defaultTimeout = 10 * time.Minute
+ defaultProfile = "ci.yml"
+ smoketestEnvVarKey = "TEST_VAR"
+ smoketestEnvVarValue = "smoketest"
+ smoketestPipelineStage = "run"
+
+ // Step names
+ stepCreateWorkspace = "createWorkspace"
+ stepSetEnvVar = "setEnvVar"
+ stepCreateFiles = "createFiles"
+ stepSyncLandscape = "syncLandscape"
+ stepStartPipeline = "startPipeline"
+ stepDeleteWorkspace = "deleteWorkspace"
+
+ ciYmlContent = `schemaVersion: v0.2
+prepare:
+ steps: []
+test:
+ steps: []
+run:
+ service:
+ steps:
+ - name: Run php server
+ command: php -S 0.0.0.0:3000 index.html
+ plan: 20
+ replicas: 1
+ network:
+ ports:
+ - port: 3000
+ isPublic: true
+ paths:
+ - port: 3000
+ path: /
+ env: {}
+`
+
+ indexHtmlContent = `
+
+
+ Smoketest
+
+
+ Smoketest Successful
+
+
+`
+
+ // ANSI color codes
+ colorGreen = "\033[32m"
+ colorRed = "\033[31m"
+ colorReset = "\033[0m"
+)
+
+type SmoketestCodesphereCmd struct {
+ cmd *cobra.Command
+ Opts *SmoketestCodesphereOpts
+ Client codesphere.Client
+}
+
+type SmoketestCodesphereOpts struct {
+ *GlobalOptions
+ BaseURL string
+ Token string
+ TeamID string
+ PlanID string
+ Quiet bool
+ Timeout time.Duration
+ Profile string
+ Steps string
+}
+
+func (c *SmoketestCodesphereCmd) RunE(_ *cobra.Command, args []string) error {
+ // Initialize client if not set (for testing)
+ if c.Client == nil {
+ client, err := codesphere.NewClient(c.Opts.BaseURL, c.Opts.Token)
+ if err != nil {
+ return fmt.Errorf("failed to create Codesphere client: %w", err)
+ }
+ c.Client = client
+ }
+
+ return c.RunSmoketest()
+}
+
+func AddSmoketestCodesphereCmd(parent *cobra.Command, opts *GlobalOptions) {
+ c := SmoketestCodesphereCmd{
+ cmd: &cobra.Command{
+ Use: "codesphere",
+ Short: "Run smoke tests for a Codesphere installation",
+ Long: io.Long(`Run automated smoke tests for a Codesphere installation by creating a workspace,
+ setting environment variables, executing commands, syncing landscape, and running a pipeline stage.
+ The workspace is automatically deleted after the test completes.`),
+ Example: formatExamplesWithBinary("smoketest codesphere", []io.Example{
+ {
+ Cmd: "--baseurl https://codesphere.example.com/api --token YOUR_TOKEN --team-id TEAM_ID --plan-id PLAN_ID",
+ Desc: "Run smoke tests against a Codesphere installation",
+ },
+ {
+ Cmd: "--baseurl https://codesphere.example.com/api --token YOUR_TOKEN --team-id TEAM_ID --plan-id PLAN_ID --quiet",
+ Desc: "Run smoke tests in quiet mode (no progress logging)",
+ },
+ {
+ Cmd: "--baseurl https://codesphere.example.com/api --token YOUR_TOKEN --team-id TEAM_ID --plan-id PLAN_ID --timeout 15m",
+ Desc: "Run smoke tests with custom timeout",
+ },
+ {
+ Cmd: "--baseurl https://codesphere.example.com/api --token YOUR_TOKEN --team-id TEAM_ID --plan-id PLAN_ID --steps createWorkspace,syncLandscape",
+ Desc: "Run only specific steps of the smoke test (workspace won't be deleted)",
+ },
+ {
+ Cmd: "--baseurl https://codesphere.example.com/api --token YOUR_TOKEN --team-id TEAM_ID --plan-id PLAN_ID --steps createWorkspace,syncLandscape,deleteWorkspace",
+ Desc: "Run specific steps and delete the workspace afterwards",
+ },
+ }, "oms-cli"),
+ },
+ Opts: &SmoketestCodesphereOpts{GlobalOptions: opts},
+ }
+ c.cmd.Flags().StringVar(&c.Opts.BaseURL, "baseurl", "", "Base URL of the Codesphere API")
+ c.cmd.Flags().StringVar(&c.Opts.Token, "token", "", "API token for authentication")
+ c.cmd.Flags().StringVar(&c.Opts.TeamID, "team-id", "", "Team ID for workspace creation")
+ c.cmd.Flags().StringVar(&c.Opts.PlanID, "plan-id", "", "Plan ID for workspace creation")
+ c.cmd.Flags().BoolVarP(&c.Opts.Quiet, "quiet", "q", false, "Suppress progress logging")
+ c.cmd.Flags().DurationVar(&c.Opts.Timeout, "timeout", defaultTimeout, "Timeout for the entire smoke test")
+ c.cmd.Flags().StringVar(&c.Opts.Profile, "profile", defaultProfile, "CI profile to use for landscape and pipeline")
+ c.cmd.Flags().StringVar(&c.Opts.Steps, "steps", "", "Comma-separated list of steps to run (createWorkspace,setEnvVar,createFiles,syncLandscape,startPipeline,deleteWorkspace). If empty, all steps including deleteWorkspace are run. If specified without deleteWorkspace, the workspace will be kept for manual inspection.")
+
+ util.MarkFlagRequired(c.cmd, "baseurl")
+ util.MarkFlagRequired(c.cmd, "token")
+ util.MarkFlagRequired(c.cmd, "team-id")
+ util.MarkFlagRequired(c.cmd, "plan-id")
+
+ c.cmd.RunE = c.RunE
+
+ parent.AddCommand(c.cmd)
+}
+
+func (c *SmoketestCodesphereCmd) RunSmoketest() (err error) {
+ ctx, cancel := context.WithTimeout(context.Background(), c.Opts.Timeout)
+ defer cancel()
+
+ teamID, parseErr := strconv.Atoi(c.Opts.TeamID)
+ if parseErr != nil {
+ return fmt.Errorf("invalid team-id: %w", parseErr)
+ }
+ planID, parseErr := strconv.Atoi(c.Opts.PlanID)
+ if parseErr != nil {
+ return fmt.Errorf("invalid plan-id: %w", parseErr)
+ }
+ steps := []string{stepCreateWorkspace, stepSetEnvVar, stepCreateFiles, stepSyncLandscape, stepStartPipeline, stepDeleteWorkspace}
+ if c.Opts.Steps != "" {
+ steps = strings.Split(c.Opts.Steps, ",")
+ for i := range steps {
+ steps[i] = strings.TrimSpace(steps[i])
+ }
+ }
+ workspaceName := fmt.Sprintf("smoketest-%s", time.Now().Format("20060102-150405"))
+
+ var workspaceID int
+ defer func() {
+ if err != nil {
+ c.logf("\n%sSmoketest failed: %s%s\n", colorRed, err.Error(), colorReset)
+ }
+
+ if workspaceID != 0 && slices.Contains(steps, stepDeleteWorkspace) {
+ c.logStep(fmt.Sprintf("\nDeleting workspace %d", workspaceID))
+ deleteErr := c.Client.DeleteWorkspace(context.Background(), workspaceID)
+ if deleteErr != nil {
+ c.logFailure()
+ if err == nil {
+ err = fmt.Errorf("failed to delete workspace: %w", deleteErr)
+ }
+ }
+ c.logSuccess()
+ }
+
+ if err == nil {
+ c.logf("\n%sSmoketest completed successfully!%s\n", colorGreen, colorReset)
+ }
+ }()
+
+ // Execute steps
+ for _, step := range steps {
+ switch step {
+ case stepCreateWorkspace:
+ if err = c.stepCreateWorkspace(ctx, teamID, planID, workspaceName, &workspaceID); err != nil {
+ return err
+ }
+ case stepSetEnvVar:
+ if err = c.stepSetEnvVar(ctx, workspaceID); err != nil {
+ return err
+ }
+ case stepCreateFiles:
+ if err = c.stepCreateFiles(ctx, workspaceID); err != nil {
+ return err
+ }
+ case stepSyncLandscape:
+ if err = c.stepSyncLandscape(ctx, workspaceID); err != nil {
+ return err
+ }
+ case stepStartPipeline:
+ if err = c.stepStartPipeline(ctx, workspaceID); err != nil {
+ return err
+ }
+ case stepDeleteWorkspace:
+ // Skip - handled in defer
+ continue
+ default:
+ return fmt.Errorf("unknown step: %s", step)
+ }
+ }
+
+ return nil
+}
+
+func (c *SmoketestCodesphereCmd) stepCreateWorkspace(ctx context.Context, teamID, planID int, workspaceName string, workspaceID *int) error {
+ c.logStep(fmt.Sprintf("Creating empty workspace '%s'", workspaceName))
+ id, err := c.Client.CreateWorkspace(ctx, teamID, planID, workspaceName, nil)
+ if err != nil {
+ c.logFailure()
+ return fmt.Errorf("failed to create workspace: %w", err)
+ }
+ *workspaceID = id
+ c.logSuccess()
+ return nil
+}
+
+func (c *SmoketestCodesphereCmd) stepSetEnvVar(ctx context.Context, workspaceID int) error {
+ c.logStep(fmt.Sprintf("Setting environment variable %s=%s", smoketestEnvVarKey, smoketestEnvVarValue))
+ if err := c.Client.SetEnvVar(ctx, workspaceID, smoketestEnvVarKey, smoketestEnvVarValue); err != nil {
+ c.logFailure()
+ return fmt.Errorf("failed to set environment variable: %w", err)
+ }
+ c.logSuccess()
+ return nil
+}
+
+func (c *SmoketestCodesphereCmd) stepCreateFiles(ctx context.Context, workspaceID int) error {
+ c.logStep("Creating ci.yml file")
+ ciYmlCmd := fmt.Sprintf(`echo '%s' > ci.yml`, ciYmlContent)
+ err := c.Client.ExecuteCommand(ctx, workspaceID, ciYmlCmd)
+ if err != nil {
+ c.logFailure()
+ return fmt.Errorf("failed to create ci.yml: %w", err)
+ }
+ c.logSuccess()
+
+ c.logStep("Creating index.html file")
+ indexHtmlCmd := fmt.Sprintf(`echo '%s' > index.html`, indexHtmlContent)
+ err = c.Client.ExecuteCommand(ctx, workspaceID, indexHtmlCmd)
+ if err != nil {
+ c.logFailure()
+ return fmt.Errorf("failed to create index.html: %w", err)
+ }
+ c.logSuccess()
+ return nil
+}
+
+func (c *SmoketestCodesphereCmd) stepSyncLandscape(ctx context.Context, workspaceID int) error {
+ c.logStep(fmt.Sprintf("Syncing landscape with profile '%s'", c.Opts.Profile))
+ if err := c.Client.SyncLandscape(ctx, workspaceID, c.Opts.Profile); err != nil {
+ c.logFailure()
+ return fmt.Errorf("failed to sync landscape: %w", err)
+ }
+ c.logSuccess()
+ return nil
+}
+
+func (c *SmoketestCodesphereCmd) stepStartPipeline(ctx context.Context, workspaceID int) error {
+ c.logStep(fmt.Sprintf("Starting '%s' pipeline stage", smoketestPipelineStage))
+ if err := c.Client.StartPipeline(ctx, workspaceID, c.Opts.Profile, smoketestPipelineStage); err != nil {
+ c.logFailure()
+ return fmt.Errorf("failed to start pipeline: %w", err)
+ }
+ c.logSuccess()
+ return nil
+}
+
+// Logging helpers
+
+func (c *SmoketestCodesphereCmd) logf(format string, args ...interface{}) {
+ if !c.Opts.Quiet {
+ fmt.Printf(format, args...)
+ }
+}
+
+func (c *SmoketestCodesphereCmd) logStep(message string) {
+ if !c.Opts.Quiet {
+ fmt.Printf("%s...", message)
+ }
+}
+
+func (c *SmoketestCodesphereCmd) logSuccess() {
+ if !c.Opts.Quiet {
+ fmt.Printf(" %ssucceeded%s\n", colorGreen, colorReset)
+ }
+}
+
+func (c *SmoketestCodesphereCmd) logFailure() {
+ if !c.Opts.Quiet {
+ fmt.Printf(" %sfailed%s\n", colorRed, colorReset)
+ }
+}
diff --git a/cli/cmd/smoketest_codesphere_test.go b/cli/cmd/smoketest_codesphere_test.go
new file mode 100644
index 0000000..c1d1822
--- /dev/null
+++ b/cli/cmd/smoketest_codesphere_test.go
@@ -0,0 +1,390 @@
+// Copyright (c) Codesphere Inc.
+// SPDX-License-Identifier: Apache-2.0
+
+package cmd_test
+
+import (
+ "fmt"
+ "strings"
+ "time"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+ "github.com/spf13/cobra"
+ "github.com/stretchr/testify/mock"
+
+ "github.com/codesphere-cloud/oms/cli/cmd"
+ "github.com/codesphere-cloud/oms/internal/codesphere"
+)
+
+var _ = Describe("SmoketestCodesphereCmd", func() {
+ var (
+ mockClient *codesphere.MockClient
+ c cmd.SmoketestCodesphereCmd
+ opts *cmd.SmoketestCodesphereOpts
+ )
+
+ BeforeEach(func() {
+ mockClient = codesphere.NewMockClient(GinkgoT())
+ opts = &cmd.SmoketestCodesphereOpts{
+ BaseURL: "https://test.codesphere.com/api",
+ Token: "test-token",
+ TeamID: "123",
+ PlanID: "456",
+ Quiet: true, // Suppress log output in tests
+ Timeout: 10 * time.Minute,
+ Profile: "ci.yml",
+ }
+ c = cmd.SmoketestCodesphereCmd{
+ Opts: opts,
+ Client: mockClient,
+ }
+ })
+
+ AfterEach(func() {
+ mockClient.AssertExpectations(GinkgoT())
+ })
+
+ Context("RunSmoketest", func() {
+ It("completes successfully with all steps", func() {
+ workspaceID := 789
+
+ // Expect all API calls in order
+ mockClient.EXPECT().CreateWorkspace(
+ mock.Anything,
+ 123, // teamID
+ 456, // planID
+ mock.AnythingOfType("string"), // workspace name is timestamped
+ (*string)(nil), // empty workspace
+ ).Return(workspaceID, nil).Once()
+
+ mockClient.EXPECT().SetEnvVar(
+ mock.Anything,
+ workspaceID,
+ "TEST_VAR",
+ "smoketest",
+ ).Return(nil).Once()
+
+ // Create ci.yml
+ mockClient.EXPECT().ExecuteCommand(
+ mock.Anything,
+ workspaceID,
+ mock.MatchedBy(func(cmd string) bool {
+ return strings.Contains(cmd, "> ci.yml")
+ }),
+ ).Return(nil).Once()
+
+ // Create index.html
+ mockClient.EXPECT().ExecuteCommand(
+ mock.Anything,
+ workspaceID,
+ mock.MatchedBy(func(cmd string) bool {
+ return strings.Contains(cmd, "> index.html")
+ }),
+ ).Return(nil).Once()
+
+ mockClient.EXPECT().SyncLandscape(
+ mock.Anything,
+ workspaceID,
+ "ci.yml",
+ ).Return(nil).Once()
+
+ mockClient.EXPECT().StartPipeline(
+ mock.Anything,
+ workspaceID,
+ "ci.yml",
+ "run",
+ ).Return(nil).Once()
+
+ mockClient.EXPECT().DeleteWorkspace(
+ mock.Anything,
+ workspaceID,
+ ).Return(nil).Once()
+
+ err := c.RunSmoketest()
+ Expect(err).To(BeNil())
+ })
+
+ It("deletes workspace even on CreateWorkspace failure", func() {
+ mockClient.EXPECT().CreateWorkspace(
+ mock.Anything,
+ 123, // teamID
+ 456, // planID
+ mock.AnythingOfType("string"),
+ (*string)(nil), // empty workspace
+ ).Return(0, fmt.Errorf("create failed")).Once()
+
+ err := c.RunSmoketest()
+ Expect(err).To(MatchError(ContainSubstring("failed to create workspace")))
+ })
+
+ It("deletes workspace on SetEnvVar failure", func() {
+ workspaceID := 789
+
+ mockClient.EXPECT().CreateWorkspace(
+ mock.Anything,
+ 123, // teamID
+ 456, // planID
+ mock.AnythingOfType("string"),
+ (*string)(nil), // empty workspace
+ ).Return(workspaceID, nil).Once()
+
+ mockClient.EXPECT().SetEnvVar(
+ mock.Anything,
+ workspaceID,
+ "TEST_VAR",
+ "smoketest",
+ ).Return(fmt.Errorf("setenv failed")).Once()
+
+ mockClient.EXPECT().DeleteWorkspace(
+ mock.Anything,
+ workspaceID,
+ ).Return(nil).Once()
+
+ err := c.RunSmoketest()
+ Expect(err).To(MatchError(ContainSubstring("failed to set environment variable")))
+ })
+
+ It("deletes workspace on ExecuteCommand failure", func() {
+ workspaceID := 789
+
+ mockClient.EXPECT().CreateWorkspace(
+ mock.Anything,
+ 123, // teamID
+ 456, // planID
+ mock.AnythingOfType("string"),
+ (*string)(nil), // empty workspace
+ ).Return(workspaceID, nil).Once()
+
+ mockClient.EXPECT().SetEnvVar(
+ mock.Anything,
+ workspaceID,
+ "TEST_VAR",
+ "smoketest",
+ ).Return(nil).Once()
+
+ // Create ci.yml fails
+ mockClient.EXPECT().ExecuteCommand(
+ mock.Anything,
+ workspaceID,
+ mock.MatchedBy(func(cmd string) bool {
+ return strings.Contains(cmd, "> ci.yml")
+ }),
+ ).Return(fmt.Errorf("exec failed")).Once()
+
+ mockClient.EXPECT().DeleteWorkspace(
+ mock.Anything,
+ workspaceID,
+ ).Return(nil).Once()
+
+ err := c.RunSmoketest()
+ Expect(err).To(MatchError(ContainSubstring("failed to create ci.yml")))
+ })
+
+ It("deletes workspace on SyncLandscape failure", func() {
+ workspaceID := 789
+
+ mockClient.EXPECT().CreateWorkspace(
+ mock.Anything,
+ 123, // teamID
+ 456, // planID
+ mock.AnythingOfType("string"),
+ (*string)(nil), // empty workspace
+ ).Return(workspaceID, nil).Once()
+
+ mockClient.EXPECT().SetEnvVar(
+ mock.Anything,
+ workspaceID,
+ "TEST_VAR",
+ "smoketest",
+ ).Return(nil).Once()
+
+ // Create ci.yml
+ mockClient.EXPECT().ExecuteCommand(
+ mock.Anything,
+ workspaceID,
+ mock.MatchedBy(func(cmd string) bool {
+ return strings.Contains(cmd, "> ci.yml")
+ }),
+ ).Return(nil).Once()
+
+ // Create index.html
+ mockClient.EXPECT().ExecuteCommand(
+ mock.Anything,
+ workspaceID,
+ mock.MatchedBy(func(cmd string) bool {
+ return strings.Contains(cmd, "> index.html")
+ }),
+ ).Return(nil).Once()
+
+ mockClient.EXPECT().SyncLandscape(
+ mock.Anything,
+ workspaceID,
+ "ci.yml",
+ ).Return(fmt.Errorf("sync failed")).Once()
+
+ mockClient.EXPECT().DeleteWorkspace(
+ mock.Anything,
+ workspaceID,
+ ).Return(nil).Once()
+
+ err := c.RunSmoketest()
+ Expect(err).To(MatchError(ContainSubstring("failed to sync landscape")))
+ })
+
+ It("deletes workspace on StartPipeline failure", func() {
+ workspaceID := 789
+
+ mockClient.EXPECT().CreateWorkspace(
+ mock.Anything,
+ 123, // teamID
+ 456, // planID
+ mock.AnythingOfType("string"),
+ (*string)(nil), // empty workspace
+ ).Return(workspaceID, nil).Once()
+
+ mockClient.EXPECT().SetEnvVar(
+ mock.Anything,
+ workspaceID,
+ "TEST_VAR",
+ "smoketest",
+ ).Return(nil).Once()
+
+ // Create ci.yml
+ mockClient.EXPECT().ExecuteCommand(
+ mock.Anything,
+ workspaceID,
+ mock.MatchedBy(func(cmd string) bool {
+ return strings.Contains(cmd, "> ci.yml")
+ }),
+ ).Return(nil).Once()
+
+ // Create index.html
+ mockClient.EXPECT().ExecuteCommand(
+ mock.Anything,
+ workspaceID,
+ mock.MatchedBy(func(cmd string) bool {
+ return strings.Contains(cmd, "> index.html")
+ }),
+ ).Return(nil).Once()
+
+ mockClient.EXPECT().SyncLandscape(
+ mock.Anything,
+ workspaceID,
+ "ci.yml",
+ ).Return(nil).Once()
+
+ mockClient.EXPECT().StartPipeline(
+ mock.Anything,
+ workspaceID,
+ "ci.yml",
+ "run",
+ ).Return(fmt.Errorf("pipeline failed")).Once()
+
+ mockClient.EXPECT().DeleteWorkspace(
+ mock.Anything,
+ workspaceID,
+ ).Return(nil).Once()
+
+ err := c.RunSmoketest()
+ Expect(err).To(MatchError(ContainSubstring("failed to start pipeline")))
+ })
+
+ It("returns cleanup error when DeleteWorkspace fails", func() {
+ workspaceID := 789
+
+ mockClient.EXPECT().CreateWorkspace(
+ mock.Anything,
+ 123, // teamID
+ 456, // planID
+ mock.AnythingOfType("string"),
+ (*string)(nil), // empty workspace
+ ).Return(workspaceID, nil).Once()
+
+ mockClient.EXPECT().SetEnvVar(
+ mock.Anything,
+ workspaceID,
+ "TEST_VAR",
+ "smoketest",
+ ).Return(nil).Once()
+
+ // Create ci.yml
+ mockClient.EXPECT().ExecuteCommand(
+ mock.Anything,
+ workspaceID,
+ mock.MatchedBy(func(cmd string) bool {
+ return strings.Contains(cmd, "> ci.yml")
+ }),
+ ).Return(nil).Once()
+
+ // Create index.html
+ mockClient.EXPECT().ExecuteCommand(
+ mock.Anything,
+ workspaceID,
+ mock.MatchedBy(func(cmd string) bool {
+ return strings.Contains(cmd, "> index.html")
+ }),
+ ).Return(nil).Once()
+
+ mockClient.EXPECT().SyncLandscape(
+ mock.Anything,
+ workspaceID,
+ "ci.yml",
+ ).Return(nil).Once()
+
+ mockClient.EXPECT().StartPipeline(
+ mock.Anything,
+ workspaceID,
+ "ci.yml",
+ "run",
+ ).Return(nil).Once()
+
+ mockClient.EXPECT().DeleteWorkspace(
+ mock.Anything,
+ workspaceID,
+ ).Return(fmt.Errorf("delete failed")).Once()
+
+ err := c.RunSmoketest()
+ Expect(err).To(MatchError(ContainSubstring("failed to delete workspace")))
+ })
+
+ It("runs only specified steps when steps flag is set", func() {
+ workspaceID := 789
+ opts.Steps = "createWorkspace,setEnvVar"
+
+ mockClient.EXPECT().CreateWorkspace(
+ mock.Anything,
+ 123, // teamID
+ 456, // planID
+ mock.AnythingOfType("string"),
+ (*string)(nil),
+ ).Return(workspaceID, nil).Once()
+
+ mockClient.EXPECT().SetEnvVar(
+ mock.Anything,
+ workspaceID,
+ "TEST_VAR",
+ "smoketest",
+ ).Return(nil).Once()
+
+ err := c.RunSmoketest()
+ Expect(err).To(BeNil())
+ })
+ })
+})
+
+var _ = Describe("AddSmoketestCodesphereCmd", func() {
+ It("adds the smoketest codesphere command to the parent", func() {
+ parent := &cobra.Command{}
+ opts := &cmd.GlobalOptions{}
+ cmd.AddSmoketestCodesphereCmd(parent, opts)
+ found := false
+ for _, c := range parent.Commands() {
+ if c.Use == "codesphere" {
+ found = true
+ break
+ }
+ }
+ Expect(found).To(BeTrue())
+ })
+})
diff --git a/docs/README.md b/docs/README.md
index 6408711..f24192c 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -26,6 +26,7 @@ like downloading new versions.
* [oms-cli list](oms-cli_list.md) - List resources available through OMS
* [oms-cli register](oms-cli_register.md) - Register a new API key
* [oms-cli revoke](oms-cli_revoke.md) - Revoke resources available through OMS
+* [oms-cli smoketest](oms-cli_smoketest.md) - Run smoke tests for Codesphere components
* [oms-cli update](oms-cli_update.md) - Update OMS related resources
* [oms-cli version](oms-cli_version.md) - Print version
diff --git a/docs/oms-cli.md b/docs/oms-cli.md
index 6408711..f24192c 100644
--- a/docs/oms-cli.md
+++ b/docs/oms-cli.md
@@ -26,6 +26,7 @@ like downloading new versions.
* [oms-cli list](oms-cli_list.md) - List resources available through OMS
* [oms-cli register](oms-cli_register.md) - Register a new API key
* [oms-cli revoke](oms-cli_revoke.md) - Revoke resources available through OMS
+* [oms-cli smoketest](oms-cli_smoketest.md) - Run smoke tests for Codesphere components
* [oms-cli update](oms-cli_update.md) - Update OMS related resources
* [oms-cli version](oms-cli_version.md) - Print version
diff --git a/docs/oms-cli_smoketest.md b/docs/oms-cli_smoketest.md
new file mode 100644
index 0000000..7b2c87d
--- /dev/null
+++ b/docs/oms-cli_smoketest.md
@@ -0,0 +1,19 @@
+## oms-cli smoketest
+
+Run smoke tests for Codesphere components
+
+### Synopsis
+
+Run automated smoke tests for Codesphere installations to verify functionality.
+
+### Options
+
+```
+ -h, --help help for smoketest
+```
+
+### SEE ALSO
+
+* [oms-cli](oms-cli.md) - Codesphere Operations Management System (OMS)
+* [oms-cli smoketest codesphere](oms-cli_smoketest_codesphere.md) - Run smoke tests for a Codesphere installation
+
diff --git a/docs/oms-cli_smoketest_codesphere.md b/docs/oms-cli_smoketest_codesphere.md
new file mode 100644
index 0000000..ac90f0f
--- /dev/null
+++ b/docs/oms-cli_smoketest_codesphere.md
@@ -0,0 +1,52 @@
+## oms-cli smoketest codesphere
+
+Run smoke tests for a Codesphere installation
+
+### Synopsis
+
+Run automated smoke tests for a Codesphere installation by creating a workspace,
+setting environment variables, executing commands, syncing landscape, and running a pipeline stage.
+The workspace is automatically deleted after the test completes.
+
+```
+oms-cli smoketest codesphere [flags]
+```
+
+### Examples
+
+```
+# Run smoke tests against a Codesphere installation
+$ oms-cli smoketest codesphere --baseurl https://codesphere.example.com/api --token YOUR_TOKEN --team-id TEAM_ID --plan-id PLAN_ID
+
+# Run smoke tests in quiet mode (no progress logging)
+$ oms-cli smoketest codesphere --baseurl https://codesphere.example.com/api --token YOUR_TOKEN --team-id TEAM_ID --plan-id PLAN_ID --quiet
+
+# Run smoke tests with custom timeout
+$ oms-cli smoketest codesphere --baseurl https://codesphere.example.com/api --token YOUR_TOKEN --team-id TEAM_ID --plan-id PLAN_ID --timeout 15m
+
+# Run only specific steps of the smoke test (workspace won't be deleted)
+$ oms-cli smoketest codesphere --baseurl https://codesphere.example.com/api --token YOUR_TOKEN --team-id TEAM_ID --plan-id PLAN_ID --steps createWorkspace,syncLandscape
+
+# Run specific steps and delete the workspace afterwards
+$ oms-cli smoketest codesphere --baseurl https://codesphere.example.com/api --token YOUR_TOKEN --team-id TEAM_ID --plan-id PLAN_ID --steps createWorkspace,syncLandscape,deleteWorkspace
+
+```
+
+### Options
+
+```
+ --baseurl string Base URL of the Codesphere API
+ -h, --help help for codesphere
+ --plan-id string Plan ID for workspace creation
+ --profile string CI profile to use for landscape and pipeline (default "ci.yml")
+ -q, --quiet Suppress progress logging
+ --steps string Comma-separated list of steps to run (createWorkspace,setEnvVar,createFiles,syncLandscape,startPipeline,deleteWorkspace). If empty, all steps including deleteWorkspace are run. If specified without deleteWorkspace, the workspace will be kept for manual inspection.
+ --team-id string Team ID for workspace creation
+ --timeout duration Timeout for the entire smoke test (default 10m0s)
+ --token string API token for authentication
+```
+
+### SEE ALSO
+
+* [oms-cli smoketest](oms-cli_smoketest.md) - Run smoke tests for Codesphere components
+
diff --git a/go.mod b/go.mod
index f1951b9..ef912ee 100644
--- a/go.mod
+++ b/go.mod
@@ -490,6 +490,7 @@ require (
google.golang.org/grpc v1.75.0 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/mail.v2 v2.3.1 // indirect
+ gopkg.in/validator.v2 v2.0.1 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
honnef.co/go/tools v0.6.1 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
diff --git a/go.sum b/go.sum
index 017a4cf..65eac84 100644
--- a/go.sum
+++ b/go.sum
@@ -1566,6 +1566,8 @@ gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMy
gopkg.in/mail.v2 v2.3.1 h1:WYFn/oANrAGP2C0dcV6/pbkPzv8yGzqTjPmTeO7qoXk=
gopkg.in/mail.v2 v2.3.1/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/validator.v2 v2.0.1 h1:xF0KWyGWXm/LM2G1TrEjqOu4pa6coO9AlWSf3msVfDY=
+gopkg.in/validator.v2 v2.0.1/go.mod h1:lIUZBlB3Im4s/eYp39Ry/wkR02yOPhZ9IwIRBjuPuG8=
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/internal/codesphere/codesphere.go b/internal/codesphere/codesphere.go
new file mode 100644
index 0000000..f25462c
--- /dev/null
+++ b/internal/codesphere/codesphere.go
@@ -0,0 +1,114 @@
+// Copyright (c) Codesphere Inc.
+// SPDX-License-Identifier: Apache-2.0
+
+package codesphere
+
+import (
+ "context"
+ "fmt"
+ "net/url"
+ "time"
+
+ "github.com/codesphere-cloud/cs-go/api"
+)
+
+// Client interface abstracts Codesphere API operations for testing
+type Client interface {
+ CreateWorkspace(ctx context.Context, teamID, planID int, name string, repoURL *string) (workspaceID int, err error)
+ SetEnvVar(ctx context.Context, workspaceID int, key, value string) error
+ ExecuteCommand(ctx context.Context, workspaceID int, command string) error
+ SyncLandscape(ctx context.Context, workspaceID int, profile string) error
+ StartPipeline(ctx context.Context, workspaceID int, profile, stage string) error
+ DeleteWorkspace(ctx context.Context, workspaceID int) error
+}
+
+// APIClient wraps the cs-go API client
+type APIClient struct {
+ client *api.Client
+}
+
+// NewClient creates a new Codesphere API client
+func NewClient(baseURL, token string) (Client, error) {
+ if baseURL == "" {
+ return nil, fmt.Errorf("baseURL is required")
+ }
+ if token == "" {
+ return nil, fmt.Errorf("token is required")
+ }
+
+ parsedURL, err := url.Parse(baseURL)
+ if err != nil {
+ return nil, fmt.Errorf("invalid baseURL: %w", err)
+ }
+
+ ctx := context.Background()
+ client := api.NewClient(ctx, api.Configuration{
+ BaseUrl: parsedURL,
+ Token: token,
+ })
+
+ return &APIClient{client: client}, nil
+}
+
+// CreateWorkspace creates a new workspace and waits for it to be running
+func (c *APIClient) CreateWorkspace(ctx context.Context, teamID, planID int, name string, repoURL *string) (int, error) {
+ workspace, err := c.client.DeployWorkspace(api.DeployWorkspaceArgs{
+ TeamId: teamID,
+ PlanId: planID,
+ Name: name,
+ GitUrl: repoURL,
+ Timeout: 10 * time.Minute,
+ EnvVars: map[string]string{}, // Empty map to avoid null
+ IsPrivateRepo: true,
+ })
+ if err != nil {
+ return 0, fmt.Errorf("failed to create workspace: %w", err)
+ }
+ return workspace.Id, nil
+}
+
+// SetEnvVar sets an environment variable in the workspace
+func (c *APIClient) SetEnvVar(ctx context.Context, workspaceID int, key, value string) error {
+ envVars := map[string]string{key: value}
+ err := c.client.SetEnvVarOnWorkspace(workspaceID, envVars)
+ if err != nil {
+ return fmt.Errorf("failed to set environment variable: %w", err)
+ }
+ return nil
+}
+
+// ExecuteCommand executes a command in the workspace
+func (c *APIClient) ExecuteCommand(ctx context.Context, workspaceID int, command string) error {
+ _, _, err := c.client.ExecCommand(workspaceID, command, "", map[string]string{})
+ if err != nil {
+ return fmt.Errorf("failed to execute command: %w", err)
+ }
+ return nil
+}
+
+// SyncLandscape syncs the landscape/CI configuration
+func (c *APIClient) SyncLandscape(ctx context.Context, workspaceID int, profile string) error {
+ err := c.client.DeployLandscape(workspaceID, profile)
+ if err != nil {
+ return fmt.Errorf("failed to sync landscape: %w", err)
+ }
+ return nil
+}
+
+// StartPipeline starts a pipeline stage
+func (c *APIClient) StartPipeline(ctx context.Context, workspaceID int, profile, stage string) error {
+ err := c.client.StartPipelineStage(workspaceID, profile, stage)
+ if err != nil {
+ return fmt.Errorf("failed to start pipeline: %w", err)
+ }
+ return nil
+}
+
+// DeleteWorkspace deletes a workspace
+func (c *APIClient) DeleteWorkspace(ctx context.Context, workspaceID int) error {
+ err := c.client.DeleteWorkspace(workspaceID)
+ if err != nil {
+ return fmt.Errorf("failed to delete workspace: %w", err)
+ }
+ return nil
+}
diff --git a/internal/codesphere/mocks.go b/internal/codesphere/mocks.go
new file mode 100644
index 0000000..bb486ef
--- /dev/null
+++ b/internal/codesphere/mocks.go
@@ -0,0 +1,331 @@
+// Code generated by mockery; DO NOT EDIT.
+// github.com/vektra/mockery
+// template: testify
+
+package codesphere
+
+import (
+ "context"
+ mock "github.com/stretchr/testify/mock"
+)
+
+// NewMockClient creates a new instance of MockClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
+// The first argument is typically a *testing.T value.
+func NewMockClient(t interface {
+ mock.TestingT
+ Cleanup(func())
+}) *MockClient {
+ mock := &MockClient{}
+ mock.Mock.Test(t)
+
+ t.Cleanup(func() { mock.AssertExpectations(t) })
+
+ return mock
+}
+
+// MockClient is an autogenerated mock type for the Client type
+type MockClient struct {
+ mock.Mock
+}
+
+type MockClient_Expecter struct {
+ mock *mock.Mock
+}
+
+func (_m *MockClient) EXPECT() *MockClient_Expecter {
+ return &MockClient_Expecter{mock: &_m.Mock}
+}
+
+// CreateWorkspace provides a mock function for the type MockClient
+func (_mock *MockClient) CreateWorkspace(ctx context.Context, teamID int, planID int, name string, repoURL *string) (int, error) {
+ ret := _mock.Called(ctx, teamID, planID, name, repoURL)
+
+ if len(ret) == 0 {
+ panic("no return value specified for CreateWorkspace")
+ }
+
+ var r0 int
+ var r1 error
+ if returnFunc, ok := ret.Get(0).(func(context.Context, int, int, string, *string) (int, error)); ok {
+ return returnFunc(ctx, teamID, planID, name, repoURL)
+ }
+ if returnFunc, ok := ret.Get(0).(func(context.Context, int, int, string, *string) int); ok {
+ r0 = returnFunc(ctx, teamID, planID, name, repoURL)
+ } else {
+ r0 = ret.Get(0).(int)
+ }
+ if returnFunc, ok := ret.Get(1).(func(context.Context, int, int, string, *string) error); ok {
+ r1 = returnFunc(ctx, teamID, planID, name, repoURL)
+ } else {
+ r1 = ret.Error(1)
+ }
+ return r0, r1
+}
+
+// MockClient_CreateWorkspace_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateWorkspace'
+type MockClient_CreateWorkspace_Call struct {
+ *mock.Call
+}
+
+// CreateWorkspace is a helper method to define mock.On call
+// - ctx
+// - teamID
+// - planID
+// - name
+// - repoURL
+func (_e *MockClient_Expecter) CreateWorkspace(ctx interface{}, teamID interface{}, planID interface{}, name interface{}, repoURL interface{}) *MockClient_CreateWorkspace_Call {
+ return &MockClient_CreateWorkspace_Call{Call: _e.mock.On("CreateWorkspace", ctx, teamID, planID, name, repoURL)}
+}
+
+func (_c *MockClient_CreateWorkspace_Call) Run(run func(ctx context.Context, teamID int, planID int, name string, repoURL *string)) *MockClient_CreateWorkspace_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].(int), args[2].(int), args[3].(string), args[4].(*string))
+ })
+ return _c
+}
+
+func (_c *MockClient_CreateWorkspace_Call) Return(workspaceID int, err error) *MockClient_CreateWorkspace_Call {
+ _c.Call.Return(workspaceID, err)
+ return _c
+}
+
+func (_c *MockClient_CreateWorkspace_Call) RunAndReturn(run func(ctx context.Context, teamID int, planID int, name string, repoURL *string) (int, error)) *MockClient_CreateWorkspace_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// DeleteWorkspace provides a mock function for the type MockClient
+func (_mock *MockClient) DeleteWorkspace(ctx context.Context, workspaceID int) error {
+ ret := _mock.Called(ctx, workspaceID)
+
+ if len(ret) == 0 {
+ panic("no return value specified for DeleteWorkspace")
+ }
+
+ var r0 error
+ if returnFunc, ok := ret.Get(0).(func(context.Context, int) error); ok {
+ r0 = returnFunc(ctx, workspaceID)
+ } else {
+ r0 = ret.Error(0)
+ }
+ return r0
+}
+
+// MockClient_DeleteWorkspace_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeleteWorkspace'
+type MockClient_DeleteWorkspace_Call struct {
+ *mock.Call
+}
+
+// DeleteWorkspace is a helper method to define mock.On call
+// - ctx
+// - workspaceID
+func (_e *MockClient_Expecter) DeleteWorkspace(ctx interface{}, workspaceID interface{}) *MockClient_DeleteWorkspace_Call {
+ return &MockClient_DeleteWorkspace_Call{Call: _e.mock.On("DeleteWorkspace", ctx, workspaceID)}
+}
+
+func (_c *MockClient_DeleteWorkspace_Call) Run(run func(ctx context.Context, workspaceID int)) *MockClient_DeleteWorkspace_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].(int))
+ })
+ return _c
+}
+
+func (_c *MockClient_DeleteWorkspace_Call) Return(err error) *MockClient_DeleteWorkspace_Call {
+ _c.Call.Return(err)
+ return _c
+}
+
+func (_c *MockClient_DeleteWorkspace_Call) RunAndReturn(run func(ctx context.Context, workspaceID int) error) *MockClient_DeleteWorkspace_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// ExecuteCommand provides a mock function for the type MockClient
+func (_mock *MockClient) ExecuteCommand(ctx context.Context, workspaceID int, command string) error {
+ ret := _mock.Called(ctx, workspaceID, command)
+
+ if len(ret) == 0 {
+ panic("no return value specified for ExecuteCommand")
+ }
+
+ var r0 error
+ if returnFunc, ok := ret.Get(0).(func(context.Context, int, string) error); ok {
+ r0 = returnFunc(ctx, workspaceID, command)
+ } else {
+ r0 = ret.Error(0)
+ }
+ return r0
+}
+
+// MockClient_ExecuteCommand_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ExecuteCommand'
+type MockClient_ExecuteCommand_Call struct {
+ *mock.Call
+}
+
+// ExecuteCommand is a helper method to define mock.On call
+// - ctx
+// - workspaceID
+// - command
+func (_e *MockClient_Expecter) ExecuteCommand(ctx interface{}, workspaceID interface{}, command interface{}) *MockClient_ExecuteCommand_Call {
+ return &MockClient_ExecuteCommand_Call{Call: _e.mock.On("ExecuteCommand", ctx, workspaceID, command)}
+}
+
+func (_c *MockClient_ExecuteCommand_Call) Run(run func(ctx context.Context, workspaceID int, command string)) *MockClient_ExecuteCommand_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].(int), args[2].(string))
+ })
+ return _c
+}
+
+func (_c *MockClient_ExecuteCommand_Call) Return(err error) *MockClient_ExecuteCommand_Call {
+ _c.Call.Return(err)
+ return _c
+}
+
+func (_c *MockClient_ExecuteCommand_Call) RunAndReturn(run func(ctx context.Context, workspaceID int, command string) error) *MockClient_ExecuteCommand_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SetEnvVar provides a mock function for the type MockClient
+func (_mock *MockClient) SetEnvVar(ctx context.Context, workspaceID int, key string, value string) error {
+ ret := _mock.Called(ctx, workspaceID, key, value)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SetEnvVar")
+ }
+
+ var r0 error
+ if returnFunc, ok := ret.Get(0).(func(context.Context, int, string, string) error); ok {
+ r0 = returnFunc(ctx, workspaceID, key, value)
+ } else {
+ r0 = ret.Error(0)
+ }
+ return r0
+}
+
+// MockClient_SetEnvVar_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetEnvVar'
+type MockClient_SetEnvVar_Call struct {
+ *mock.Call
+}
+
+// SetEnvVar is a helper method to define mock.On call
+// - ctx
+// - workspaceID
+// - key
+// - value
+func (_e *MockClient_Expecter) SetEnvVar(ctx interface{}, workspaceID interface{}, key interface{}, value interface{}) *MockClient_SetEnvVar_Call {
+ return &MockClient_SetEnvVar_Call{Call: _e.mock.On("SetEnvVar", ctx, workspaceID, key, value)}
+}
+
+func (_c *MockClient_SetEnvVar_Call) Run(run func(ctx context.Context, workspaceID int, key string, value string)) *MockClient_SetEnvVar_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].(int), args[2].(string), args[3].(string))
+ })
+ return _c
+}
+
+func (_c *MockClient_SetEnvVar_Call) Return(err error) *MockClient_SetEnvVar_Call {
+ _c.Call.Return(err)
+ return _c
+}
+
+func (_c *MockClient_SetEnvVar_Call) RunAndReturn(run func(ctx context.Context, workspaceID int, key string, value string) error) *MockClient_SetEnvVar_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// StartPipeline provides a mock function for the type MockClient
+func (_mock *MockClient) StartPipeline(ctx context.Context, workspaceID int, profile string, stage string) error {
+ ret := _mock.Called(ctx, workspaceID, profile, stage)
+
+ if len(ret) == 0 {
+ panic("no return value specified for StartPipeline")
+ }
+
+ var r0 error
+ if returnFunc, ok := ret.Get(0).(func(context.Context, int, string, string) error); ok {
+ r0 = returnFunc(ctx, workspaceID, profile, stage)
+ } else {
+ r0 = ret.Error(0)
+ }
+ return r0
+}
+
+// MockClient_StartPipeline_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'StartPipeline'
+type MockClient_StartPipeline_Call struct {
+ *mock.Call
+}
+
+// StartPipeline is a helper method to define mock.On call
+// - ctx
+// - workspaceID
+// - profile
+// - stage
+func (_e *MockClient_Expecter) StartPipeline(ctx interface{}, workspaceID interface{}, profile interface{}, stage interface{}) *MockClient_StartPipeline_Call {
+ return &MockClient_StartPipeline_Call{Call: _e.mock.On("StartPipeline", ctx, workspaceID, profile, stage)}
+}
+
+func (_c *MockClient_StartPipeline_Call) Run(run func(ctx context.Context, workspaceID int, profile string, stage string)) *MockClient_StartPipeline_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].(int), args[2].(string), args[3].(string))
+ })
+ return _c
+}
+
+func (_c *MockClient_StartPipeline_Call) Return(err error) *MockClient_StartPipeline_Call {
+ _c.Call.Return(err)
+ return _c
+}
+
+func (_c *MockClient_StartPipeline_Call) RunAndReturn(run func(ctx context.Context, workspaceID int, profile string, stage string) error) *MockClient_StartPipeline_Call {
+ _c.Call.Return(run)
+ return _c
+}
+
+// SyncLandscape provides a mock function for the type MockClient
+func (_mock *MockClient) SyncLandscape(ctx context.Context, workspaceID int, profile string) error {
+ ret := _mock.Called(ctx, workspaceID, profile)
+
+ if len(ret) == 0 {
+ panic("no return value specified for SyncLandscape")
+ }
+
+ var r0 error
+ if returnFunc, ok := ret.Get(0).(func(context.Context, int, string) error); ok {
+ r0 = returnFunc(ctx, workspaceID, profile)
+ } else {
+ r0 = ret.Error(0)
+ }
+ return r0
+}
+
+// MockClient_SyncLandscape_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SyncLandscape'
+type MockClient_SyncLandscape_Call struct {
+ *mock.Call
+}
+
+// SyncLandscape is a helper method to define mock.On call
+// - ctx
+// - workspaceID
+// - profile
+func (_e *MockClient_Expecter) SyncLandscape(ctx interface{}, workspaceID interface{}, profile interface{}) *MockClient_SyncLandscape_Call {
+ return &MockClient_SyncLandscape_Call{Call: _e.mock.On("SyncLandscape", ctx, workspaceID, profile)}
+}
+
+func (_c *MockClient_SyncLandscape_Call) Run(run func(ctx context.Context, workspaceID int, profile string)) *MockClient_SyncLandscape_Call {
+ _c.Call.Run(func(args mock.Arguments) {
+ run(args[0].(context.Context), args[1].(int), args[2].(string))
+ })
+ return _c
+}
+
+func (_c *MockClient_SyncLandscape_Call) Return(err error) *MockClient_SyncLandscape_Call {
+ _c.Call.Return(err)
+ return _c
+}
+
+func (_c *MockClient_SyncLandscape_Call) RunAndReturn(run func(ctx context.Context, workspaceID int, profile string) error) *MockClient_SyncLandscape_Call {
+ _c.Call.Return(run)
+ return _c
+}