diff --git a/internal/interactor/config.go b/internal/interactor/config.go deleted file mode 100644 index 68517b29..00000000 --- a/internal/interactor/config.go +++ /dev/null @@ -1,22 +0,0 @@ -package interactor - -import ( - "context" - - "github.com/gitploy-io/gitploy/ent" - "github.com/gitploy-io/gitploy/pkg/e" - "github.com/gitploy-io/gitploy/vo" -) - -func (i *Interactor) GetEnv(ctx context.Context, u *ent.User, r *ent.Repo, env string) (*vo.Env, error) { - config, err := i.SCM.GetConfig(ctx, u, r) - if err != nil { - return nil, err - } - - if !config.HasEnv(env) { - return nil, e.NewError(e.ErrorCodeConfigUndefinedEnv, nil) - } - - return config.GetEnv(env), nil -} diff --git a/internal/interactor/config_test.go b/internal/interactor/config_test.go deleted file mode 100644 index 47f63629..00000000 --- a/internal/interactor/config_test.go +++ /dev/null @@ -1,57 +0,0 @@ -package interactor - -import ( - "context" - "testing" - - "github.com/golang/mock/gomock" - - "github.com/gitploy-io/gitploy/ent" - "github.com/gitploy-io/gitploy/internal/interactor/mock" - "github.com/gitploy-io/gitploy/pkg/e" - "github.com/gitploy-io/gitploy/vo" -) - -func TestInteractor_GetEnv(t *testing.T) { - t.Run("Return an error when the environment is not defined.", func(t *testing.T) { - ctrl := gomock.NewController(t) - scm := mock.NewMockSCM(ctrl) - - scm. - EXPECT(). - GetConfig(gomock.Any(), gomock.AssignableToTypeOf(&ent.User{}), gomock.AssignableToTypeOf(&ent.Repo{})). - Return(&vo.Config{ - Envs: []*vo.Env{}, - }, nil) - - i := &Interactor{SCM: scm} - - _, err := i.GetEnv(context.Background(), &ent.User{}, &ent.Repo{}, "production") - if !e.HasErrorCode(err, e.ErrorCodeConfigUndefinedEnv) { - t.Fatalf("GetEnv error = %v, wanted ErrorCodeConfigUndefinedEnv", err) - } - }) - - t.Run("Return the environment.", func(t *testing.T) { - ctrl := gomock.NewController(t) - scm := mock.NewMockSCM(ctrl) - - scm. - EXPECT(). - GetConfig(gomock.Any(), gomock.AssignableToTypeOf(&ent.User{}), gomock.AssignableToTypeOf(&ent.Repo{})). - Return(&vo.Config{ - Envs: []*vo.Env{ - { - Name: "production", - }, - }, - }, nil) - - i := &Interactor{SCM: scm} - - _, err := i.GetEnv(context.Background(), &ent.User{}, &ent.Repo{}, "production") - if err != nil { - t.Fatalf("GetEnv returns an error: %v", err) - } - }) -} diff --git a/internal/interactor/deployment.go b/internal/interactor/deployment.go index 343f9efc..6515f9ed 100644 --- a/internal/interactor/deployment.go +++ b/internal/interactor/deployment.go @@ -37,10 +37,6 @@ func (i *Interactor) Deploy(ctx context.Context, u *ent.User, r *ent.Repo, d *en return nil, err } - if err := env.Eval(&vo.EvalValues{IsRollback: d.IsRollback}); err != nil { - return nil, err - } - number, err := i.Store.GetNextDeploymentNumberOfRepo(ctx, r) if err != nil { return nil, e.NewError( @@ -139,10 +135,6 @@ func (i *Interactor) DeployToRemote(ctx context.Context, u *ent.User, r *ent.Rep ) } - if err := env.Eval(&vo.EvalValues{IsRollback: d.IsRollback}); err != nil { - return nil, err - } - rd, err := i.createRemoteDeployment(ctx, u, r, d, env) if err != nil { return nil, err diff --git a/internal/interactor/deployment_test.go b/internal/interactor/deployment_test.go index fca2d386..2de6d565 100644 --- a/internal/interactor/deployment_test.go +++ b/internal/interactor/deployment_test.go @@ -289,7 +289,7 @@ func TestInteractor_DeployToRemote(t *testing.T) { } }) - t.Run("create a new remote deployment and update the deployment.", func(t *testing.T) { + t.Run("Create a new remote deployment and update the deployment.", func(t *testing.T) { input := struct { d *ent.Deployment e *vo.Env diff --git a/internal/server/api/v1/repos/deployment.go b/internal/server/api/v1/repos/deployment.go index 354aaf67..0aa854f0 100644 --- a/internal/server/api/v1/repos/deployment.go +++ b/internal/server/api/v1/repos/deployment.go @@ -85,15 +85,23 @@ func (r *Repo) CreateDeployment(c *gin.Context) { vr, _ := c.Get(KeyRepo) re := vr.(*ent.Repo) - env, err := r.i.GetEnv(ctx, u, re, p.Env) + config, err := r.i.GetConfig(ctx, u, re) if e.HasErrorCode(err, e.ErrorCodeEntityNotFound) { - r.log.Check(gb.GetZapLogLevel(err), "The configuration file is not found.").Write(zap.Error(err)) - // To override the HTTP status 422. + r.log.Check(gb.GetZapLogLevel(err), "Failed to get the configuration.").Write(zap.Error(err)) gb.ResponseWithStatusAndError(c, http.StatusUnprocessableEntity, err) return - } else if err != nil { - r.log.Check(gb.GetZapLogLevel(err), "It has failed to get the configuration.").Write(zap.Error(err)) - gb.ResponseWithError(c, err) + } + + if err := config.Eval(&vo.EvalValues{}); err != nil { + r.log.Check(gb.GetZapLogLevel(err), "Failed to evaluate the configuration.").Write(zap.Error(err)) + gb.ResponseWithStatusAndError(c, http.StatusUnprocessableEntity, err) + return + } + + var env *vo.Env + if env = config.GetEnv(p.Env); env == nil { + r.log.Warn("The environment is not found.", zap.String("env", p.Env)) + gb.ResponseWithStatusAndError(c, http.StatusUnprocessableEntity, e.NewError(e.ErrorCodeConfigUndefinedEnv, nil)) return } @@ -110,7 +118,6 @@ func (r *Repo) CreateDeployment(c *gin.Context) { return } - // TODO: Migrate the event logic into the interactor. if _, err := r.i.CreateEvent(ctx, &ent.Event{ Kind: event.KindDeployment, Type: event.TypeCreated, @@ -124,6 +131,7 @@ func (r *Repo) CreateDeployment(c *gin.Context) { d = de } + r.log.Info("Start to deploy.", zap.String("repo", re.GetFullName()), zap.String("env", p.Env)) gb.Response(c, http.StatusCreated, d) } @@ -149,15 +157,23 @@ func (r *Repo) UpdateDeployment(c *gin.Context) { return } - env, err := r.i.GetEnv(ctx, u, re, d.Env) + config, err := r.i.GetConfig(ctx, u, re) if e.HasErrorCode(err, e.ErrorCodeEntityNotFound) { - r.log.Check(gb.GetZapLogLevel(err), "The configuration file is not found.").Write(zap.Error(err)) - // To override the HTTP status 422. + r.log.Check(gb.GetZapLogLevel(err), "Failed to get the configuration.").Write(zap.Error(err)) gb.ResponseWithStatusAndError(c, http.StatusUnprocessableEntity, err) return - } else if err != nil { - r.log.Check(gb.GetZapLogLevel(err), "It has failed to get the configuration.").Write(zap.Error(err)) - gb.ResponseWithError(c, err) + } + + if err := config.Eval(&vo.EvalValues{IsRollback: d.IsRollback}); err != nil { + r.log.Check(gb.GetZapLogLevel(err), "Failed to evaludate the configuration.").Write(zap.Error(err)) + gb.ResponseWithStatusAndError(c, http.StatusUnprocessableEntity, err) + return + } + + var env *vo.Env + if env = config.GetEnv(d.Env); env == nil { + r.log.Warn("The environment is not found.", zap.String("env", d.Env)) + gb.ResponseWithStatusAndError(c, http.StatusUnprocessableEntity, e.NewError(e.ErrorCodeConfigUndefinedEnv, nil)) return } @@ -180,6 +196,7 @@ func (r *Repo) UpdateDeployment(c *gin.Context) { d = de } + r.log.Info("Start to deploy.", zap.String("repo", re.GetFullName()), zap.Int("number", d.Number)) gb.Response(c, http.StatusOK, d) } @@ -203,15 +220,23 @@ func (r *Repo) RollbackDeployment(c *gin.Context) { return } - env, err := r.i.GetEnv(ctx, u, re, d.Env) + config, err := r.i.GetConfig(ctx, u, re) if e.HasErrorCode(err, e.ErrorCodeEntityNotFound) { - r.log.Check(gb.GetZapLogLevel(err), "The configuration file is not found.").Write(zap.Error(err)) - // To override the HTTP status 422. + r.log.Check(gb.GetZapLogLevel(err), "Failed to get the configuration.").Write(zap.Error(err)) gb.ResponseWithStatusAndError(c, http.StatusUnprocessableEntity, err) return - } else if err != nil { - r.log.Check(gb.GetZapLogLevel(err), "It has failed to get the configuration.").Write(zap.Error(err)) - gb.ResponseWithError(c, err) + } + + if err := config.Eval(&vo.EvalValues{IsRollback: true}); err != nil { + r.log.Check(gb.GetZapLogLevel(err), "Failed to evaludate the configuration.").Write(zap.Error(err)) + gb.ResponseWithStatusAndError(c, http.StatusUnprocessableEntity, err) + return + } + + var env *vo.Env + if env = config.GetEnv(d.Env); env == nil { + r.log.Warn("The environment is not found.", zap.String("env", d.Env)) + gb.ResponseWithStatusAndError(c, http.StatusUnprocessableEntity, e.NewError(e.ErrorCodeConfigUndefinedEnv, nil)) return } @@ -242,6 +267,7 @@ func (r *Repo) RollbackDeployment(c *gin.Context) { d = de } + r.log.Info("Start to rollback.", zap.String("repo", re.GetFullName()), zap.Int("number", d.Number)) gb.Response(c, http.StatusCreated, d) } diff --git a/internal/server/api/v1/repos/deployment_test.go b/internal/server/api/v1/repos/deployment_test.go index 4ef33b70..8ccd7f4b 100644 --- a/internal/server/api/v1/repos/deployment_test.go +++ b/internal/server/api/v1/repos/deployment_test.go @@ -120,13 +120,15 @@ func TestRepo_CreateDeployment(t *testing.T) { ctrl := gomock.NewController(t) m := mock.NewMockInteractor(ctrl) - t.Log("Read the config file.") m. EXPECT(). - GetEnv(gomock.Any(), gomock.AssignableToTypeOf(&ent.User{}), gomock.AssignableToTypeOf(&ent.Repo{}), gomock.Any()). - Return(&vo.Env{ - Name: "prod", - }, nil) + GetConfig(gomock.Any(), gomock.AssignableToTypeOf(&ent.User{}), gomock.AssignableToTypeOf(&ent.Repo{})). + Return(&vo.Config{ + Envs: []*vo.Env{ + { + Name: "prod", + }, + }}, nil) t.Log("Deploy with the payload successfully.") m. diff --git a/internal/server/api/v1/repos/interface.go b/internal/server/api/v1/repos/interface.go index d690ccff..c1d281a5 100644 --- a/internal/server/api/v1/repos/interface.go +++ b/internal/server/api/v1/repos/interface.go @@ -31,7 +31,6 @@ type ( Deploy(ctx context.Context, u *ent.User, re *ent.Repo, d *ent.Deployment, env *vo.Env) (*ent.Deployment, error) DeployToRemote(ctx context.Context, u *ent.User, r *ent.Repo, d *ent.Deployment, env *vo.Env) (*ent.Deployment, error) GetConfig(ctx context.Context, u *ent.User, r *ent.Repo) (*vo.Config, error) - GetEnv(ctx context.Context, u *ent.User, r *ent.Repo, env string) (*vo.Env, error) ListReviews(ctx context.Context, d *ent.Deployment) ([]*ent.Review, error) FindReviewOfUser(ctx context.Context, u *ent.User, d *ent.Deployment) (*ent.Review, error) diff --git a/internal/server/api/v1/repos/lock.go b/internal/server/api/v1/repos/lock.go index fb1002d1..755d1230 100644 --- a/internal/server/api/v1/repos/lock.go +++ b/internal/server/api/v1/repos/lock.go @@ -20,6 +20,7 @@ import ( "github.com/gitploy-io/gitploy/internal/server/global" gb "github.com/gitploy-io/gitploy/internal/server/global" "github.com/gitploy-io/gitploy/pkg/e" + "github.com/gitploy-io/gitploy/vo" ) type ( @@ -84,15 +85,17 @@ func (r *Repo) CreateLock(c *gin.Context) { vu, _ := c.Get(global.KeyUser) u := vu.(*ent.User) - env, err := r.i.GetEnv(ctx, u, re, p.Env) + config, err := r.i.GetConfig(ctx, u, re) if e.HasErrorCode(err, e.ErrorCodeEntityNotFound) { - r.log.Check(gb.GetZapLogLevel(err), "The configuration file is not found.").Write(zap.Error(err)) - // To override the HTTP status 422. + r.log.Check(gb.GetZapLogLevel(err), "Failed to get the configuration.").Write(zap.Error(err)) gb.ResponseWithStatusAndError(c, http.StatusUnprocessableEntity, err) return - } else if err != nil { - r.log.Check(gb.GetZapLogLevel(err), "It has failed to get the configuration.").Write(zap.Error(err)) - gb.ResponseWithError(c, err) + } + + var env *vo.Env + if env = config.GetEnv(p.Env); env == nil { + r.log.Warn("The environment is not found.", zap.String("env", p.Env)) + gb.ResponseWithStatusAndError(c, http.StatusUnprocessableEntity, e.NewError(e.ErrorCodeConfigUndefinedEnv, nil)) return } diff --git a/internal/server/api/v1/repos/lock_test.go b/internal/server/api/v1/repos/lock_test.go index 3ce07ca3..23a2547e 100644 --- a/internal/server/api/v1/repos/lock_test.go +++ b/internal/server/api/v1/repos/lock_test.go @@ -17,7 +17,6 @@ import ( "github.com/gitploy-io/gitploy/ent" "github.com/gitploy-io/gitploy/internal/server/api/v1/repos/mock" "github.com/gitploy-io/gitploy/internal/server/global" - "github.com/gitploy-io/gitploy/pkg/e" "github.com/gitploy-io/gitploy/vo" ) @@ -34,11 +33,15 @@ func TestRepo_CreateLock(t *testing.T) { ctrl := gomock.NewController(t) m := mock.NewMockInteractor(ctrl) - t.Log("Read deploy.yml and check the env.") m. EXPECT(). - GetEnv(gomock.Any(), gomock.AssignableToTypeOf(&ent.User{}), gomock.AssignableToTypeOf(&ent.Repo{}), gomock.Any()). - Return(nil, e.NewError(e.ErrorCodeConfigUndefinedEnv, nil)) + GetConfig(gomock.Any(), gomock.AssignableToTypeOf(&ent.User{}), gomock.AssignableToTypeOf(&ent.Repo{})). + Return(&vo.Config{ + Envs: []*vo.Env{ + { + Name: "dev", + }, + }}, nil) r := NewRepo(RepoConfig{}, m) @@ -72,13 +75,15 @@ func TestRepo_CreateLock(t *testing.T) { ctrl := gomock.NewController(t) m := mock.NewMockInteractor(ctrl) - t.Log("Read deploy.yml and check the env.") m. EXPECT(). - GetEnv(gomock.Any(), gomock.AssignableToTypeOf(&ent.User{}), gomock.AssignableToTypeOf(&ent.Repo{}), gomock.Any()). - Return(&vo.Env{ - Name: "production", - }, nil) + GetConfig(gomock.Any(), gomock.AssignableToTypeOf(&ent.User{}), gomock.AssignableToTypeOf(&ent.Repo{})). + Return(&vo.Config{ + Envs: []*vo.Env{ + { + Name: "production", + }, + }}, nil) t.Log("Lock the env.") m. diff --git a/internal/server/api/v1/repos/mock/interactor.go b/internal/server/api/v1/repos/mock/interactor.go index c2696428..9bc3df33 100644 --- a/internal/server/api/v1/repos/mock/interactor.go +++ b/internal/server/api/v1/repos/mock/interactor.go @@ -336,21 +336,6 @@ func (mr *MockInteractorMockRecorder) GetConfig(ctx, u, r interface{}) *gomock.C return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetConfig", reflect.TypeOf((*MockInteractor)(nil).GetConfig), ctx, u, r) } -// GetEnv mocks base method. -func (m *MockInteractor) GetEnv(ctx context.Context, u *ent.User, r *ent.Repo, env string) (*vo.Env, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetEnv", ctx, u, r, env) - ret0, _ := ret[0].(*vo.Env) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetEnv indicates an expected call of GetEnv. -func (mr *MockInteractorMockRecorder) GetEnv(ctx, u, r, env interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEnv", reflect.TypeOf((*MockInteractor)(nil).GetEnv), ctx, u, r, env) -} - // GetTag mocks base method. func (m *MockInteractor) GetTag(ctx context.Context, u *ent.User, r *ent.Repo, tag string) (*vo.Tag, error) { m.ctrl.T.Helper() diff --git a/internal/server/slack/deploy.go b/internal/server/slack/deploy.go index 685e2432..28509955 100644 --- a/internal/server/slack/deploy.go +++ b/internal/server/slack/deploy.go @@ -273,15 +273,21 @@ func (s *Slack) interactDeploy(c *gin.Context) { return } - cfg, err := s.i.GetConfig(ctx, cu.Edges.User, cb.Edges.Repo) + config, err := s.i.GetConfig(ctx, cu.Edges.User, cb.Edges.Repo) if err != nil { postMessageWithError(cu, err) c.Status(http.StatusOK) return } + if err := config.Eval(&vo.EvalValues{}); err != nil { + postMessageWithError(cu, err) + c.Status(http.StatusOK) + return + } + var env *vo.Env - if env = cfg.GetEnv(sm.Env); env == nil { + if env = config.GetEnv(sm.Env); env == nil { postBotMessage(cu, "The env is not defined in the config.") c.Status(http.StatusOK) return diff --git a/internal/server/slack/rollback.go b/internal/server/slack/rollback.go index ef378823..7327e181 100644 --- a/internal/server/slack/rollback.go +++ b/internal/server/slack/rollback.go @@ -212,15 +212,21 @@ func (s *Slack) interactRollback(c *gin.Context) { return } - cfg, err := s.i.GetConfig(ctx, cu.Edges.User, cb.Edges.Repo) + config, err := s.i.GetConfig(ctx, cu.Edges.User, cb.Edges.Repo) if err != nil { postMessageWithError(cu, err) c.Status(http.StatusOK) return } + if err := config.Eval(&vo.EvalValues{}); err != nil { + postMessageWithError(cu, err) + c.Status(http.StatusOK) + return + } + var env *vo.Env - if env = cfg.GetEnv(d.Env); env == nil { + if env = config.GetEnv(d.Env); env == nil { postBotMessage(cu, "The env is not defined in the config.") c.Status(http.StatusOK) return diff --git a/vo/config.go b/vo/config.go index f2d0d055..ec1bd590 100644 --- a/vo/config.go +++ b/vo/config.go @@ -1,7 +1,6 @@ package vo import ( - "encoding/json" "regexp" "strconv" @@ -14,6 +13,10 @@ import ( type ( Config struct { Envs []*Env `json:"envs" yaml:"envs"` + + // save the content of the configuration file + // when it is unmarshalled. + source []byte } Env struct { @@ -48,21 +51,61 @@ type ( ) const ( - varnameDeployTask = "GITPLOY_DEPLOY_TASK" - varnameRollbackTask = "GITPLOY_ROLLBACK_TASK" - varnameIsRollback = "GITPLOY_IS_ROLLBACK" + VarnameDeployTask = "GITPLOY_DEPLOY_TASK" + VarnameRollbackTask = "GITPLOY_ROLLBACK_TASK" + VarnameIsRollback = "GITPLOY_IS_ROLLBACK" ) const ( - // defaultDeployTask is the value of the 'GITPLOY_DEPLOY_TASK' variable. - defaultDeployTask = "deploy" - // defaultRollbackTask is the value of the 'GITPLOY_ROLLBACK_TASK' variable. - defaultRollbackTask = "rollback" + // DefaultDeployTask is the value of the 'GITPLOY_DEPLOY_TASK' variable. + DefaultDeployTask = "deploy" + // DefaultRollbackTask is the value of the 'GITPLOY_ROLLBACK_TASK' variable. + DefaultRollbackTask = "rollback" ) func UnmarshalYAML(content []byte, c *Config) error { if err := yaml.Unmarshal([]byte(content), c); err != nil { - return err + return eutil.NewError(eutil.ErrorCodeConfigParseError, err) + } + + c.source = content + + return nil +} + +func (c *Config) Eval(v *EvalValues) error { + // Evaluates variables + mapper := func(vn string) string { + if vn == VarnameDeployTask { + if !v.IsRollback { + return DefaultDeployTask + } else { + return "" + } + } + + if vn == VarnameRollbackTask { + if v.IsRollback { + return DefaultRollbackTask + } else { + return "" + } + } + + if vn == VarnameIsRollback { + return strconv.FormatBool(v.IsRollback) + } + + return "ERR_NOT_IMPLEMENTED" + } + + evalued, err := envsubst.Eval(string(c.source), mapper) + if err != nil { + return eutil.NewError(eutil.ErrorCodeConfigParseError, err) + } + + if err := yaml.Unmarshal([]byte(evalued), c); err != nil { + return eutil.NewError(eutil.ErrorCodeConfigParseError, err) } return nil @@ -125,46 +168,3 @@ func (e *Env) IsAutoDeployOn(ref string) (bool, error) { func (e *Env) HasReview() bool { return e.Review != nil && e.Review.Enabled } - -func (e *Env) Eval(v *EvalValues) error { - byts, err := json.Marshal(e) - if err != nil { - return eutil.NewError(eutil.ErrorCodeConfigParseError, err) - } - - // Evaluates variables - mapper := func(vn string) string { - if vn == varnameDeployTask { - if !v.IsRollback { - return defaultDeployTask - } else { - return "" - } - } - - if vn == varnameRollbackTask { - if v.IsRollback { - return defaultRollbackTask - } else { - return "" - } - } - - if vn == varnameIsRollback { - return strconv.FormatBool(v.IsRollback) - } - - return "ERR_NOT_IMPLEMENTED" - } - - evalued, err := envsubst.Eval(string(byts), mapper) - if err != nil { - return eutil.NewError(eutil.ErrorCodeConfigParseError, err) - } - - if err := json.Unmarshal([]byte(evalued), e); err != nil { - return eutil.NewError(eutil.ErrorCodeConfigParseError, err) - } - - return nil -} diff --git a/vo/config_test.go b/vo/config_test.go index cd8a6cf6..5ec69884 100644 --- a/vo/config_test.go +++ b/vo/config_test.go @@ -1,7 +1,6 @@ package vo import ( - "fmt" "reflect" "testing" @@ -31,6 +30,7 @@ envs: RequiredContexts: &[]string{"github-action"}, }, }, + source: []byte(s), } if !reflect.DeepEqual(c, e) { tt.Errorf("Config = %s, expected %s", spew.Sdump(c), spew.Sdump(e)) @@ -57,6 +57,7 @@ envs: AutoMerge: pointer.ToBool(false), }, }, + source: []byte(s), } if !reflect.DeepEqual(c, e) { tt.Errorf("Config = %s, expected %s", spew.Sdump(c), spew.Sdump(e)) @@ -72,8 +73,7 @@ envs: err := UnmarshalYAML([]byte(s), c) if err != nil { - tt.Errorf("failed to parse: %s", err) - tt.FailNow() + tt.Fatalf("failed to parse: %s", err) } e := &Config{ @@ -83,6 +83,7 @@ envs: AutoMerge: pointer.ToBool(true), }, }, + source: []byte(s), } if !reflect.DeepEqual(c, e) { tt.Errorf("Config = %s, expected %s", spew.Sdump(c), spew.Sdump(e)) @@ -90,6 +91,70 @@ envs: }) } +func TestConfig_Eval(t *testing.T) { + t.Run("Evaluate the configuration.", func(t *testing.T) { + s := ` +envs: + - name: dev + task: ${GITPLOY_DEPLOY_TASK}:kubernetes` + + c := &Config{} + if err := UnmarshalYAML([]byte(s), c); err != nil { + t.Fatalf("Failed to parse the configuration file: %v", err) + } + + err := c.Eval(&EvalValues{}) + if err != nil { + t.Fatalf("Eval returns an error: %v", err) + } + + e := &Config{ + Envs: []*Env{ + { + Name: "dev", + Task: pointer.ToString("deploy:kubernetes"), + }, + }, + source: []byte(s), + } + if !reflect.DeepEqual(c, e) { + t.Errorf("Config = %v expected %v", spew.Sdump(c), spew.Sdump(e)) + } + }) + + t.Run("Evaluate the configuration with the regexp.", func(t *testing.T) { + s := ` +envs: + - name: dev + task: ${GITPLOY_DEPLOY_TASK}:kubernetes + deployable_ref: 'v.*\..*\..*'` + + c := &Config{} + if err := UnmarshalYAML([]byte(s), c); err != nil { + t.Fatalf("Failed to parse the configuration file: %v", err) + } + + err := c.Eval(&EvalValues{}) + if err != nil { + t.Fatalf("Eval returns an error: %v", err) + } + + e := &Config{ + Envs: []*Env{ + { + Name: "dev", + Task: pointer.ToString("deploy:kubernetes"), + DeployableRef: pointer.ToString(`v.*\..*\..*`), + }, + }, + source: []byte(s), + } + if !reflect.DeepEqual(c, e) { + t.Errorf("Config = %v expected %v", spew.Sdump(c), spew.Sdump(e)) + } + }) +} + func TestEnv_IsProductionEnvironment(t *testing.T) { t.Run("Reutrn false when the production environment is nil", func(t *testing.T) { e := &Env{} @@ -159,79 +224,3 @@ func TestEnv_IsDeployableRef(t *testing.T) { } }) } - -func TestEnv_Eval(t *testing.T) { - t.Run("eval the task.", func(t *testing.T) { - cs := []struct { - env *Env - want *Env - }{ - { - env: &Env{ - Task: pointer.ToString("${GITPLOY_DEPLOY_TASK}"), - }, - want: &Env{ - Task: pointer.ToString(defaultDeployTask), - }, - }, - { - env: &Env{ - Task: pointer.ToString("${GITPLOY_DEPLOY_TASK}:kubernetes"), - }, - want: &Env{ - Task: pointer.ToString(fmt.Sprintf("%s:kubernetes", defaultDeployTask)), - }, - }, - { - env: &Env{ - Task: pointer.ToString("${GITPLOY_DEPLOY_TASK}${GITPLOY_ROLLBACK_TASK}"), - }, - want: &Env{ - Task: pointer.ToString(defaultDeployTask), - }, - }, - } - - for _, c := range cs { - err := c.env.Eval(&EvalValues{}) - if err != nil { - t.Fatalf("Eval returns an error: %s", err) - } - if !reflect.DeepEqual(c.env, c.want) { - t.Fatalf("Eval = %v, wanted %v", *c.env.Task, *c.want.Task) - } - } - }) - - t.Run("eval the is_rollback.", func(t *testing.T) { - const ( - isRollback = true - ) - - cs := []struct { - env *Env - want *Env - }{ - { - env: &Env{ - Payload: pointer.ToString("{\"is_rollback\": ${GITPLOY_IS_ROLLBACK}}"), - }, - want: &Env{ - Payload: pointer.ToString("{\"is_rollback\": true}"), - }, - }, - } - - for _, c := range cs { - err := c.env.Eval(&EvalValues{ - IsRollback: isRollback, - }) - if err != nil { - t.Fatalf("Eval returns an error: %s", err) - } - if !reflect.DeepEqual(c.env, c.want) { - t.Fatalf("Eval = %v, wanted %v", c.env, c.want) - } - } - }) -}