diff --git a/constants/limit.go b/constants/limit.go index c6f2532c..c1a4ac95 100644 --- a/constants/limit.go +++ b/constants/limit.go @@ -33,4 +33,7 @@ const ( // DeployBuildsMaxSize defines the maximum size in characters for deployment builds. DeployBuildsMaxSize = 500 + + // ReportStepStatusLimit defines the maximum number of steps in a pipeline that may report their status to the SCM. + ReportStepStatusLimit = 10 ) diff --git a/database/step.go b/database/step.go index 318407e1..34304168 100644 --- a/database/step.go +++ b/database/step.go @@ -49,6 +49,7 @@ type Step struct { Host sql.NullString `sql:"host"` Runtime sql.NullString `sql:"runtime"` Distribution sql.NullString `sql:"distribution"` + ReportAs sql.NullString `sql:"report_as"` } // Nullify ensures the valid flag for @@ -142,6 +143,11 @@ func (s *Step) Nullify() *Step { s.Distribution.Valid = false } + // check if the ReportAs field should be false + if len(s.ReportAs.String) == 0 { + s.ReportAs.Valid = false + } + return s } @@ -166,6 +172,7 @@ func (s *Step) ToLibrary() *library.Step { step.SetHost(s.Host.String) step.SetRuntime(s.Runtime.String) step.SetDistribution(s.Distribution.String) + step.SetReportAs(s.ReportAs.String) return step } @@ -209,6 +216,7 @@ func (s *Step) Validate() error { s.Host = sql.NullString{String: sanitize(s.Host.String), Valid: s.Host.Valid} s.Runtime = sql.NullString{String: sanitize(s.Runtime.String), Valid: s.Runtime.Valid} s.Distribution = sql.NullString{String: sanitize(s.Distribution.String), Valid: s.Distribution.Valid} + s.ReportAs = sql.NullString{String: sanitize(s.ReportAs.String), Valid: s.ReportAs.Valid} return nil } @@ -233,6 +241,7 @@ func StepFromLibrary(s *library.Step) *Step { Host: sql.NullString{String: s.GetHost(), Valid: true}, Runtime: sql.NullString{String: s.GetRuntime(), Valid: true}, Distribution: sql.NullString{String: s.GetDistribution(), Valid: true}, + ReportAs: sql.NullString{String: s.GetReportAs(), Valid: true}, } return step.Nullify() diff --git a/database/step_test.go b/database/step_test.go index 90d10a51..270f939b 100644 --- a/database/step_test.go +++ b/database/step_test.go @@ -31,6 +31,7 @@ func TestDatabase_Step_Nullify(t *testing.T) { Host: sql.NullString{String: "", Valid: false}, Runtime: sql.NullString{String: "", Valid: false}, Distribution: sql.NullString{String: "", Valid: false}, + ReportAs: sql.NullString{String: "", Valid: false}, } // setup tests @@ -82,6 +83,7 @@ func TestDatabase_Step_ToLibrary(t *testing.T) { want.SetHost("example.company.com") want.SetRuntime("docker") want.SetDistribution("linux") + want.SetReportAs("test") // run test got := testStep().ToLibrary() @@ -191,6 +193,7 @@ func TestDatabase_StepFromLibrary(t *testing.T) { s.SetHost("example.company.com") s.SetRuntime("docker") s.SetDistribution("linux") + s.SetReportAs("test") want := testStep() @@ -222,5 +225,6 @@ func testStep() *Step { Host: sql.NullString{String: "example.company.com", Valid: true}, Runtime: sql.NullString{String: "docker", Valid: true}, Distribution: sql.NullString{String: "linux", Valid: true}, + ReportAs: sql.NullString{String: "test", Valid: true}, } } diff --git a/library/step.go b/library/step.go index 5dfa8aee..bf33ae5c 100644 --- a/library/step.go +++ b/library/step.go @@ -31,6 +31,7 @@ type Step struct { Host *string `json:"host,omitempty"` Runtime *string `json:"runtime,omitempty"` Distribution *string `json:"distribution,omitempty"` + ReportAs *string `json:"report_as,omitempty"` } // Duration calculates and returns the total amount of @@ -78,6 +79,7 @@ func (s *Step) Environment() map[string]string { "VELA_STEP_STAGE": ToString(s.GetStage()), "VELA_STEP_STARTED": ToString(s.GetStarted()), "VELA_STEP_STATUS": ToString(s.GetStatus()), + "VELA_STEP_REPORT_AS": ToString(s.GetReportAs()), } } @@ -289,6 +291,19 @@ func (s *Step) GetDistribution() string { return *s.Distribution } +// GetReportAs returns the ReportAs field. +// +// When the provided Step type is nil, or the field within +// the type is nil, it returns the zero value for the field. +func (s *Step) GetReportAs() string { + // return zero value if Step type or ReportAs field is nil + if s == nil || s.ReportAs == nil { + return "" + } + + return *s.ReportAs +} + // SetID sets the ID field. // // When the provided Step type is nil, it @@ -484,7 +499,7 @@ func (s *Step) SetRuntime(v string) { s.Runtime = &v } -// SetDistribution sets the Runtime field. +// SetDistribution sets the Distribution field. // // When the provided Step type is nil, it // will set nothing and immediately return. @@ -497,6 +512,19 @@ func (s *Step) SetDistribution(v string) { s.Distribution = &v } +// SetReportAs sets the ReportAs field. +// +// When the provided Step type is nil, it +// will set nothing and immediately return. +func (s *Step) SetReportAs(v string) { + // return if Step type is nil + if s == nil { + return + } + + s.ReportAs = &v +} + // String implements the Stringer interface for the Step type. func (s *Step) String() string { return fmt.Sprintf(`{ @@ -512,6 +540,7 @@ func (s *Step) String() string { Name: %s, Number: %d, RepoID: %d, + ReportAs: %s, Runtime: %s, Stage: %s, Started: %d, @@ -529,6 +558,7 @@ func (s *Step) String() string { s.GetName(), s.GetNumber(), s.GetRepoID(), + s.GetReportAs(), s.GetRuntime(), s.GetStage(), s.GetStarted(), @@ -558,6 +588,7 @@ func StepFromBuildContainer(build *Build, ctn *pipeline.Container) *Step { s.SetName(ctn.Name) s.SetNumber(ctn.Number) s.SetImage(ctn.Image) + s.SetReportAs(ctn.ReportAs) // check if the VELA_STEP_STAGE environment variable exists value, ok := ctn.Environment["VELA_STEP_STAGE"] @@ -609,6 +640,13 @@ func StepFromContainerEnvironment(ctn *pipeline.Container) *Step { s.SetName(value) } + // check if the VELA_STEP_REPORT_AS environment variable exists + value, ok = ctn.Environment["VELA_STEP_REPORT_AS"] + if ok { + // set the ReportAs field to the value from environment variable + s.SetReportAs(value) + } + // check if the VELA_STEP_RUNTIME environment variable exists value, ok = ctn.Environment["VELA_STEP_RUNTIME"] if ok { diff --git a/library/step_test.go b/library/step_test.go index 60446d4e..ba73dc6e 100644 --- a/library/step_test.go +++ b/library/step_test.go @@ -55,6 +55,7 @@ func TestLibrary_Step_Environment(t *testing.T) { "VELA_STEP_IMAGE": "target/vela-git:v0.3.0", "VELA_STEP_NAME": "clone", "VELA_STEP_NUMBER": "1", + "VELA_STEP_REPORT_AS": "test", "VELA_STEP_RUNTIME": "docker", "VELA_STEP_STAGE": "", "VELA_STEP_STARTED": "1563474078", @@ -150,6 +151,10 @@ func TestLibrary_Step_Getters(t *testing.T) { if test.step.GetDistribution() != test.want.GetDistribution() { t.Errorf("GetDistribution is %v, want %v", test.step.GetDistribution(), test.want.GetDistribution()) } + + if test.step.GetReportAs() != test.want.GetReportAs() { + t.Errorf("GetReportAs is %v, want %v", test.step.GetReportAs(), test.want.GetReportAs()) + } } } @@ -190,6 +195,7 @@ func TestLibrary_Step_Setters(t *testing.T) { test.step.SetHost(test.want.GetHost()) test.step.SetRuntime(test.want.GetRuntime()) test.step.SetDistribution(test.want.GetDistribution()) + test.step.SetReportAs(test.want.GetReportAs()) if test.step.GetID() != test.want.GetID() { t.Errorf("SetID is %v, want %v", test.step.GetID(), test.want.GetID()) @@ -254,6 +260,10 @@ func TestLibrary_Step_Setters(t *testing.T) { if test.step.GetDistribution() != test.want.GetDistribution() { t.Errorf("SetDistribution is %v, want %v", test.step.GetDistribution(), test.want.GetDistribution()) } + + if test.step.GetReportAs() != test.want.GetReportAs() { + t.Errorf("SetReportAs is %v, want %v", test.step.GetReportAs(), test.want.GetReportAs()) + } } } @@ -274,6 +284,7 @@ func TestLibrary_Step_String(t *testing.T) { Name: %s, Number: %d, RepoID: %d, + ReportAs: %s, Runtime: %s, Stage: %s, Started: %d, @@ -291,6 +302,7 @@ func TestLibrary_Step_String(t *testing.T) { s.GetName(), s.GetNumber(), s.GetRepoID(), + s.GetReportAs(), s.GetRuntime(), s.GetStage(), s.GetStarted(), @@ -363,9 +375,10 @@ func TestLibrary_StepFromBuildContainer(t *testing.T) { { name: "container with build", container: &pipeline.Container{ - Name: s.GetName(), - Number: s.GetNumber(), - Image: s.GetImage(), + Name: s.GetName(), + Number: s.GetNumber(), + Image: s.GetImage(), + ReportAs: s.GetReportAs(), Environment: map[string]string{ "VELA_STEP_STAGE": "clone", }, @@ -423,6 +436,7 @@ func TestLibrary_StepFromContainerEnvironment(t *testing.T) { "VELA_STEP_IMAGE": "target/vela-git:v0.3.0", "VELA_STEP_NAME": "clone", "VELA_STEP_NUMBER": "1", + "VELA_STEP_REPORT_AS": "test", "VELA_STEP_RUNTIME": "docker", "VELA_STEP_STAGE": "clone", "VELA_STEP_STARTED": "1563474078", @@ -462,6 +476,7 @@ func testStep() *Step { s.SetHost("example.company.com") s.SetRuntime("docker") s.SetDistribution("linux") + s.SetReportAs("test") return s } diff --git a/pipeline/container.go b/pipeline/container.go index 3ada27a0..fcd12080 100644 --- a/pipeline/container.go +++ b/pipeline/container.go @@ -51,6 +51,7 @@ type ( Ulimits UlimitSlice `json:"ulimits,omitempty" yaml:"ulimits,omitempty"` Volumes VolumeSlice `json:"volumes,omitempty" yaml:"volumes,omitempty"` User string `json:"user,omitempty" yaml:"user,omitempty"` + ReportAs string `json:"report_as,omitempty" yaml:"report_as,omitempty"` } ) @@ -133,7 +134,8 @@ func (c *Container) Empty() bool { len(c.Secrets) == 0 && len(c.Ulimits) == 0 && len(c.Volumes) == 0 && - len(c.User) == 0 { + len(c.User) == 0 && + len(c.ReportAs) == 0 { return true } diff --git a/pipeline/container_test.go b/pipeline/container_test.go index 2f814ba7..ba08cd2b 100644 --- a/pipeline/container_test.go +++ b/pipeline/container_test.go @@ -917,6 +917,7 @@ func testContainers() *ContainerSlice { Name: "echo", Number: 3, Pull: "always", + ReportAs: "echo-step", Ruleset: Ruleset{ If: Rules{Event: []string{"push"}}, Operator: "and", diff --git a/yaml/step.go b/yaml/step.go index 82232143..396a3b74 100644 --- a/yaml/step.go +++ b/yaml/step.go @@ -34,6 +34,7 @@ type ( Detach bool `yaml:"detach,omitempty" json:"detach,omitempty" jsonschema:"description=Run the container in a detached (headless) state.\nReference: https://go-vela.github.io/docs/reference/yaml/steps/#the-detach-tag"` Privileged bool `yaml:"privileged,omitempty" json:"privileged,omitempty" jsonschema:"description=Run the container with extra privileges.\nReference: https://go-vela.github.io/docs/reference/yaml/steps/#the-privileged-tag"` User string `yaml:"user,omitempty" json:"user,omitempty" jsonschema:"description=Set the user for the container.\nReference: https://go-vela.github.io/docs/reference/yaml/steps/#the-user-tag"` + ReportAs string `yaml:"report_as,omitempty" json:"report_as,omitempty" jsonschema:"description=Set the name of the step to report as.\nReference: https://go-vela.github.io/docs/reference/yaml/steps/#the-report_as-tag"` } ) @@ -60,6 +61,7 @@ func (s *StepSlice) ToPipeline() *pipeline.ContainerSlice { Ulimits: *step.Ulimits.ToPipeline(), Volumes: *step.Volumes.ToPipeline(), User: step.User, + ReportAs: step.ReportAs, }) } diff --git a/yaml/step_test.go b/yaml/step_test.go index e1cead4c..2d0b6034 100644 --- a/yaml/step_test.go +++ b/yaml/step_test.go @@ -30,6 +30,7 @@ func TestYaml_StepSlice_ToPipeline(t *testing.T) { Name: "echo", Privileged: false, Pull: "not_present", + ReportAs: "my-step", Ruleset: Ruleset{ If: Rules{ Branch: []string{"main"}, @@ -86,6 +87,7 @@ func TestYaml_StepSlice_ToPipeline(t *testing.T) { Name: "echo", Privileged: false, Pull: "not_present", + ReportAs: "my-step", Ruleset: pipeline.Ruleset{ If: pipeline.Rules{ Branch: []string{"main"}, @@ -187,9 +189,10 @@ func TestYaml_StepSlice_UnmarshalYAML(t *testing.T) { Pull: "always", }, { - Name: "docker_build", - Image: "plugins/docker:18.09", - Pull: "always", + Name: "docker_build", + Image: "plugins/docker:18.09", + Pull: "always", + ReportAs: "docker", Parameters: map[string]interface{}{ "registry": "index.docker.io", "repo": "github/octocat", diff --git a/yaml/testdata/step.yml b/yaml/testdata/step.yml index 5dd49e3e..1d6d9cc9 100644 --- a/yaml/testdata/step.yml +++ b/yaml/testdata/step.yml @@ -28,6 +28,7 @@ - name: docker_build image: plugins/docker:18.09 + report_as: docker parameters: registry: index.docker.io repo: github/octocat