From f784eedeae3efb9fee96f24bd0e996ba7224e537 Mon Sep 17 00:00:00 2001 From: Vistaar Juneja Date: Tue, 15 Aug 2023 15:33:46 +0100 Subject: [PATCH] working executions flow --- cmd/gitness/wire_gen.go | 5 +- .../api/controller/execution/controller.go | 3 + internal/api/controller/execution/find.go | 17 +- internal/api/controller/execution/wire.go | 4 +- internal/store/database.go | 6 +- internal/store/database/encode.go | 15 ++ internal/store/database/execution.go | 39 +++ .../database/migrate/ci/ci_migrations.sql | 224 ++++++++++++++---- internal/store/database/stage.go | 70 +++++- internal/store/database/stage_scan.go | 162 +++++++++++++ internal/store/database/step.go | 25 +- internal/store/database/step_scan.go | 54 +++++ mocks/mock_client.go | 3 +- mocks/mock_store.go | 3 +- types/execution.go | 73 +++--- types/step.go | 2 - 16 files changed, 603 insertions(+), 102 deletions(-) create mode 100644 internal/store/database/encode.go create mode 100644 internal/store/database/stage_scan.go create mode 100644 internal/store/database/step_scan.go diff --git a/cmd/gitness/wire_gen.go b/cmd/gitness/wire_gen.go index abae4b558..85a6b70c8 100644 --- a/cmd/gitness/wire_gen.go +++ b/cmd/gitness/wire_gen.go @@ -8,7 +8,6 @@ package main import ( "context" - "github.com/harness/gitness/cli/server" "github.com/harness/gitness/encrypt" "github.com/harness/gitness/events" @@ -94,9 +93,9 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro } repoController := repo.ProvideController(config, db, provider, pathUID, authorizer, pathStore, repoStore, spaceStore, principalStore, gitrpcInterface) executionStore := database.ProvideExecutionStore(db) - pipelineStore := database.ProvidePipelineStore(db) - executionController := execution.ProvideController(db, authorizer, executionStore, pipelineStore, spaceStore) stageStore := database.ProvideStageStore(db) + pipelineStore := database.ProvidePipelineStore(db) + executionController := execution.ProvideController(db, authorizer, executionStore, stageStore, pipelineStore, spaceStore) stepStore := database.ProvideStepStore(db) logStore := logs.ProvideLogStore(db, config) logStream := livelog.ProvideLogStream(config) diff --git a/internal/api/controller/execution/controller.go b/internal/api/controller/execution/controller.go index abfa572eb..a6801f361 100644 --- a/internal/api/controller/execution/controller.go +++ b/internal/api/controller/execution/controller.go @@ -15,6 +15,7 @@ type Controller struct { db *sqlx.DB authorizer authz.Authorizer executionStore store.ExecutionStore + stageStore store.StageStore pipelineStore store.PipelineStore spaceStore store.SpaceStore } @@ -23,6 +24,7 @@ func NewController( db *sqlx.DB, authorizer authz.Authorizer, executionStore store.ExecutionStore, + stageStore store.StageStore, pipelineStore store.PipelineStore, spaceStore store.SpaceStore, ) *Controller { @@ -30,6 +32,7 @@ func NewController( db: db, authorizer: authorizer, executionStore: executionStore, + stageStore: stageStore, pipelineStore: pipelineStore, spaceStore: spaceStore, } diff --git a/internal/api/controller/execution/find.go b/internal/api/controller/execution/find.go index d597488fd..93e9bb436 100644 --- a/internal/api/controller/execution/find.go +++ b/internal/api/controller/execution/find.go @@ -36,5 +36,20 @@ func (c *Controller) Find( return nil, fmt.Errorf("could not authorize: %w", err) } - return c.executionStore.Find(ctx, pipeline.ID, executionNum) + execution, err := c.executionStore.Find(ctx, pipeline.ID, executionNum) + if err != nil { + return nil, fmt.Errorf("could not find execution: %w", err) + } + + stages, err := c.stageStore.ListSteps(ctx, execution.ID) + if err != nil { + return nil, fmt.Errorf("could not query stage information: %w", err) + } + + fmt.Printf("stages: %+v", stages) + + // Add stages information to the execution + execution.Stages = stages + + return execution, nil } diff --git a/internal/api/controller/execution/wire.go b/internal/api/controller/execution/wire.go index c559831f9..c85fd0ee2 100644 --- a/internal/api/controller/execution/wire.go +++ b/internal/api/controller/execution/wire.go @@ -20,8 +20,10 @@ var WireSet = wire.NewSet( func ProvideController(db *sqlx.DB, authorizer authz.Authorizer, executionStore store.ExecutionStore, + stageStore store.StageStore, pipelineStore store.PipelineStore, spaceStore store.SpaceStore, ) *Controller { - return NewController(db, authorizer, executionStore, pipelineStore, spaceStore) + return NewController(db, authorizer, executionStore, stageStore, + pipelineStore, spaceStore) } diff --git a/internal/store/database.go b/internal/store/database.go index f1e2dd3fd..a86187e78 100644 --- a/internal/store/database.go +++ b/internal/store/database.go @@ -534,9 +534,9 @@ type ( // // where the stage is incomplete (pending or running). // ListIncomplete(ctx context.Context) ([]*types.Stage, error) - // // ListSteps returns a build stage list from the datastore, - // // with the individual steps included. - // ListSteps(context.Context, int64) ([]*types.Stage, error) + // ListSteps returns a stage list from the datastore corresponding to an execution, + // with the individual steps included. + ListSteps(ctx context.Context, executionID int64) ([]*types.Stage, error) // // ListState returns a build stage list from the database // // across all repositories. diff --git a/internal/store/database/encode.go b/internal/store/database/encode.go new file mode 100644 index 000000000..25331a574 --- /dev/null +++ b/internal/store/database/encode.go @@ -0,0 +1,15 @@ +package database + +import ( + "encoding/json" + + sqlx "github.com/jmoiron/sqlx/types" +) + +// EncodeToJSON accepts a generic parameter and returns +// a sqlx.JSONText object which is used to store arbitrary +// data in the DB. +func EncodeToJSON(v any) sqlx.JSONText { + raw, _ := json.Marshal(v) + return sqlx.JSONText(raw) +} diff --git a/internal/store/database/execution.go b/internal/store/database/execution.go index 187d33805..ca8153d42 100644 --- a/internal/store/database/execution.go +++ b/internal/store/database/execution.go @@ -32,6 +32,45 @@ type executionStore struct { db *sqlx.DB } +// exection represents an execution object stored in the database +type execution struct { + ID int64 `db:"execution_id"` + PipelineID int64 `db:"execution_pipeline_id"` + RepoID int64 `db:"execution_repo_id"` + Trigger string `db:"execution_trigger"` + Number int64 `db:"execution_number"` + Parent int64 `db:"execution_parent"` + Status string `db:"execution_status"` + Error string `db:"execution_error"` + Event string `db:"execution_event"` + Action string `db:"execution_action"` + Link string `db:"execution_link"` + Timestamp int64 `db:"execution_timestamp"` + Title string `db:"execution_title"` + Message string `db:"execution_message"` + Before string `db:"execution_before"` + After string `db:"execution_after"` + Ref string `db:"execution_ref"` + Fork string `db:"execution_source_repo"` + Source string `db:"execution_source"` + Target string `db:"execution_target"` + Author string `db:"execution_author"` + AuthorName string `db:"execution_author_name"` + AuthorEmail string `db:"execution_author_email"` + AuthorAvatar string `db:"execution_author_avatar"` + Sender string `db:"execution_sender"` + Params string `db:"execution_params"` + Cron string `db:"execution_cron"` + Deploy string `db:"execution_deploy"` + DeployID int64 `db:"execution_deploy_id"` + Debug bool `db:"execution_debug"` + Started int64 `db:"execution_started"` + Finished int64 `db:"execution_finished"` + Created int64 `db:"execution_created"` + Updated int64 `db:"execution_updated"` + Version int64 `db:"execution_version"` +} + const ( executionColumns = ` execution_id diff --git a/internal/store/database/migrate/ci/ci_migrations.sql b/internal/store/database/migrate/ci/ci_migrations.sql index c9ec7b7e1..228a609c9 100644 --- a/internal/store/database/migrate/ci/ci_migrations.sql +++ b/internal/store/database/migrate/ci/ci_migrations.sql @@ -111,30 +111,30 @@ CREATE TABLE IF NOT EXISTS secrets ( CREATE TABLE IF NOT EXISTS stages ( stage_id INTEGER PRIMARY KEY AUTOINCREMENT - ,stage_execution_id INTEGER - ,stage_number INTEGER - ,stage_kind TEXT - ,stage_type TEXT - ,stage_name TEXT - ,stage_status TEXT - ,stage_error TEXT - ,stage_errignore BOOLEAN - ,stage_exit_code INTEGER - ,stage_limit INTEGER - ,stage_os TEXT - ,stage_arch TEXT - ,stage_variant TEXT - ,stage_kernel TEXT - ,stage_machine TEXT - ,stage_started INTEGER - ,stage_stopped INTEGER - ,stage_created INTEGER - ,stage_updated INTEGER - ,stage_version INTEGER - ,stage_on_success BOOLEAN - ,stage_on_failure BOOLEAN - ,stage_depends_on TEXT - ,stage_labels TEXT + ,stage_execution_id INTEGER NOT NULL + ,stage_number INTEGER NOT NULL + ,stage_kind TEXT NOT NULL + ,stage_type TEXT NOT NULL + ,stage_name TEXT NOT NULL + ,stage_status TEXT NOT NULL + ,stage_error TEXT NOT NULL + ,stage_errignore BOOLEAN NOT NULL + ,stage_exit_code INTEGER NOT NULL + ,stage_limit INTEGER NOT NULL + ,stage_os TEXT NOT NULL + ,stage_arch TEXT NOT NULL + ,stage_variant TEXT NOT NULL + ,stage_kernel TEXT NOT NULL + ,stage_machine TEXT NOT NULL + ,stage_started INTEGER NOT NULL + ,stage_stopped INTEGER NOT NULL + ,stage_created INTEGER NOT NULL + ,stage_updated INTEGER NOT NULL + ,stage_version INTEGER NOT NULL + ,stage_on_success BOOLEAN NOT NULL + ,stage_on_failure BOOLEAN NOT NULL + ,stage_depends_on TEXT NOT NULL + ,stage_labels TEXT NOT NULL ,stage_limit_repo INTEGER NOT NULL DEFAULT 0 -- Ensure unique combination of stage execution ID and stage number @@ -159,20 +159,20 @@ WHERE stage_status IN ('pending', 'running'); CREATE TABLE IF NOT EXISTS steps ( step_id INTEGER PRIMARY KEY AUTOINCREMENT - ,step_stage_id INTEGER - ,step_number INTEGER - ,step_name VARCHAR(100) - ,step_status VARCHAR(50) - ,step_error VARCHAR(500) - ,step_errignore BOOLEAN - ,step_exit_code INTEGER - ,step_started INTEGER - ,step_stopped INTEGER - ,step_version INTEGER - ,step_depends_on TEXT - ,step_image TEXT - ,step_detached BOOLEAN - ,step_schema TEXT + ,step_stage_id INTEGER NOT NULL + ,step_number INTEGER NOT NULL + ,step_name VARCHAR(100) NOT NULL + ,step_status VARCHAR(50) NOT NULL + ,step_error VARCHAR(500) NOT NULL + ,step_errignore BOOLEAN NOT NULL + ,step_exit_code INTEGER NOT NULL + ,step_started INTEGER NOT NULL + ,step_stopped INTEGER NOT NULL + ,step_version INTEGER NOT NULL + ,step_depends_on TEXT NOT NULL + ,step_image TEXT NOT NULL + ,step_detached BOOLEAN NOT NULL + ,step_schema TEXT NOT NULL -- Ensure unique comination of stage ID and step number ,UNIQUE(step_stage_id, step_number) @@ -201,7 +201,7 @@ CREATE TABLE IF NOT EXISTS connectors ( -- Ensure unique combination of space ID and connector UID ,UNIQUE (connector_space_id, connector_uid) -) +); CREATE TABLE IF NOT EXISTS logs ( @@ -213,4 +213,148 @@ CREATE TABLE IF NOT EXISTS logs ( REFERENCES steps (step_id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE CASCADE -); \ No newline at end of file +); + +-- Sample 1 +INSERT INTO stages (stage_execution_id, stage_number, stage_kind, stage_type, stage_name, stage_status, stage_error, stage_errignore, stage_exit_code, stage_limit, stage_os, stage_arch, stage_variant, stage_kernel, stage_machine, stage_started, stage_stopped, stage_created, stage_updated, stage_version, stage_on_success, stage_on_failure, stage_depends_on, stage_labels, stage_limit_repo) +VALUES ( + 3, -- stage_execution_id + 1, -- stage_number + 'build', -- stage_kind + 'docker', -- stage_type + 'Build Stage', -- stage_name + 'Pending', -- stage_status + '', -- stage_error + 0, -- stage_errignore + 0, -- stage_exit_code + 2, -- stage_limit + 'linux', -- stage_os + 'x86_64', -- stage_arch + 'default', -- stage_variant + '4.18.0-305.7.1.el8_4.x86_64', -- stage_kernel + 'x86_64', -- stage_machine + 0, -- stage_started + 0, -- stage_stopped + 1679089460, -- stage_created + 1679089500, -- stage_updated + 1, -- stage_version + 1, -- stage_on_success + 0, -- stage_on_failure + '', -- stage_depends_on + 'label1,label2', -- stage_labels + 1 -- stage_limit_repo +); + +-- Sample 2 +INSERT INTO stages (stage_execution_id, stage_number, stage_kind, stage_type, stage_name, stage_status, stage_error, stage_errignore, stage_exit_code, stage_limit, stage_os, stage_arch, stage_variant, stage_kernel, stage_machine, stage_started, stage_stopped, stage_created, stage_updated, stage_version, stage_on_success, stage_on_failure, stage_depends_on, stage_labels, stage_limit_repo) +VALUES ( + 3, -- stage_execution_id + 2, -- stage_number + 'test', -- stage_kind + 'pytest', -- stage_type + 'Test Stage', -- stage_name + 'Pending', -- stage_status + '', -- stage_error + 0, -- stage_errignore + 0, -- stage_exit_code + 1, -- stage_limit + 'linux', -- stage_os + 'x86_64', -- stage_arch + 'default', -- stage_variant + '4.18.0-305.7.1.el8_4.x86_64', -- stage_kernel + 'x86_64', -- stage_machine + 0, -- stage_started + 0, -- stage_stopped + 1679089560, -- stage_created + 1679089600, -- stage_updated + 1, -- stage_version + 1, -- stage_on_success + 1, -- stage_on_failure + '1', -- stage_depends_on (referring to the first stage) + 'label3,label4', -- stage_labels + 0 -- stage_limit_repo (using default value) +); + +INSERT INTO steps (step_stage_id, step_number, step_name, step_status, step_error, step_errignore, step_exit_code, step_started, step_stopped, step_version, step_depends_on, step_image, step_detached, step_schema) +VALUES ( + 1, -- step_stage_id + 1, -- step_number + 'stage1step1', -- step_name + 'Pending', -- step_status + '', -- step_error + 0, -- step_errignore + 0, -- step_exit_code + 0, -- step_started + 0, -- step_stopped + 1, -- step_version + '', -- step_depends_on + 'sample_image', -- step_image + 0, -- step_detached + 'sample_schema' -- step_schema +); + +INSERT INTO steps (step_stage_id, step_number, step_name, step_status, step_error, step_errignore, step_exit_code, step_started, step_stopped, step_version, step_depends_on, step_image, step_detached, step_schema) +VALUES ( + 1, -- step_stage_id + 2, -- step_number + 'stage1step2', -- step_name + 'Success', -- step_status + '', -- step_error + 0, -- step_errignore + 0, -- step_exit_code + 0, -- step_started + 0, -- step_stopped + 1, -- step_version + '', -- step_depends_on + 'sample_image', -- step_image + 0, -- step_detached + 'sample_schema' -- step_schema +); + +INSERT INTO steps (step_stage_id, step_number, step_name, step_status, step_error, step_errignore, step_exit_code, step_started, step_stopped, step_version, step_depends_on, step_image, step_detached, step_schema) +VALUES ( + 2, -- step_stage_id + 1, -- step_number + 'stage2step1', -- step_name + 'Success', -- step_status + '', -- step_error + 0, -- step_errignore + 0, -- step_exit_code + 0, -- step_started + 0, -- step_stopped + 1, -- step_version + '', -- step_depends_on + 'sample_image', -- step_image + 0, -- step_detached + 'sample_schema' -- step_schema +); + +INSERT INTO steps (step_stage_id, step_number, step_name, step_status, step_error, step_errignore, step_exit_code, step_started, step_stopped, step_version, step_depends_on, step_image, step_detached, step_schema) +VALUES ( + 2, -- step_stage_id + 1, -- step_number + 'stage2step2', -- step_name + 'Success', -- step_status + '', -- step_error + 0, -- step_errignore + 0, -- step_exit_code + 0, -- step_started + 0, -- step_stopped + 1, -- step_version + '', -- step_depends_on + 'sample_image', -- step_image + 0, -- step_detached + 'sample_schema' -- step_schema +); + + +INSERT INTO steps (step_stage_id, step_number, step_name) VALUES (1, 1, "step1"); +INSERT INTO steps (step_stage_id, step_number, step_name) VALUES (1, 2, "step2"); + +INSERT INTO steps (step_stage_id, step_number, step_name) VALUES (2, 1, "step1"); +INSERT INTO steps (step_stage_id, step_number, step_name) VALUES (2, 2, "step2"); + +INSERT INTO logs (log_id, log_data) VALUES (1, "stage1 step1 logs"); +INSERT INTO logs (log_id, log_data) VALUES (2, "stage1 step2 logs"); +INSERT INTO logs (log_id, log_data) VALUES (3, "stage2 step1 logs"); +INSERT INTO logs (log_id, log_data) VALUES (4, "stage2 step2 logs"); \ No newline at end of file diff --git a/internal/store/database/stage.go b/internal/store/database/stage.go index b4e229e04..e30850d07 100644 --- a/internal/store/database/stage.go +++ b/internal/store/database/stage.go @@ -6,6 +6,7 @@ package database import ( "context" + "fmt" "github.com/harness/gitness/internal/store" "github.com/harness/gitness/store/database" @@ -13,16 +14,12 @@ import ( "github.com/harness/gitness/types" "github.com/jmoiron/sqlx" + sqlxtypes "github.com/jmoiron/sqlx/types" ) var _ store.StageStore = (*stageStore)(nil) const ( - stageQueryBase = ` - SELECT` + - stageColumns + ` - FROM stages` - stageColumns = ` stage_id ,stage_execution_id @@ -53,6 +50,35 @@ const ( ` ) +type stage struct { + ID int64 `db:"stage_id"` + ExecutionID int64 `db:"stage_execution_id"` + Number int `db:"stage_number"` + Name string `db:"stage_name"` + Kind string `db:"stage_kind"` + Type string `db:"stage_type"` + Status string `db:"stage_status"` + Error string `db:"stage_error"` + ErrIgnore bool `db:"stage_errignore"` + ExitCode int `db:"stage_exit_code"` + Machine string `db:"stage_machine"` + OS string `db:"stage_os"` + Arch string `db:"stage_arch"` + Variant string `db:"stage_variant"` + Kernel string `db:"stage_kernel"` + Limit int `db:"stage_limit"` + LimitRepo int `db:"stage_limit_repo"` + Started int64 `db:"stage_started"` + Stopped int64 `db:"stage_stopped"` + Created int64 `db:"stage_created"` + Updated int64 `db:"stage_updated"` + Version int64 `db:"stage_version"` + OnSuccess bool `db:"stage_on_success"` + OnFailure bool `db:"stage_on_failure"` + DependsOn sqlxtypes.JSONText `db:"stage_depends_on"` + Labels sqlxtypes.JSONText `db:"stage_labels"` +} + // NewStageStore returns a new StageStore. func NewStageStore(db *sqlx.DB) *stageStore { return &stageStore{ @@ -72,9 +98,39 @@ func (s *stageStore) FindNumber(ctx context.Context, executionID int64, stageNum WHERE stage_execution_id = $1 AND stage_number = $2` db := dbtx.GetAccessor(ctx, s.db) - dst := new(types.Stage) + dst := new(stage) if err := db.GetContext(ctx, dst, findQueryStmt, executionID, stageNum); err != nil { return nil, database.ProcessSQLErrorf(err, "Failed to find stage") } - return dst, nil + return mapInternalToStage(dst) +} + +// ListSteps returns a stage with information about all its containing steps +func (s *stageStore) ListSteps(ctx context.Context, executionID int64) ([]*types.Stage, error) { + const queryNumberWithSteps = ` + SELECT` + stageColumns + "," + stepColumns + ` + FROM stages + LEFT JOIN steps + ON stages.stage_id=steps.step_stage_id + WHERE stages.stage_execution_id = $1 + ORDER BY + stage_id ASC + ,step_id ASC + ` + fmt.Println(queryNumberWithSteps) + db := dbtx.GetAccessor(ctx, s.db) + + dst := []*types.Stage{} + rows, err := db.QueryContext(ctx, queryNumberWithSteps, executionID) + if err != nil { + return nil, database.ProcessSQLErrorf(err, "Failed to query stages and steps") + } + stages, err := scanRowsWithSteps(rows) + if err != nil { + return nil, database.ProcessSQLErrorf(err, "Failed to find stage") + } + for _, k := range dst { + fmt.Printf("stage is: %+v", k) + } + return stages, nil } diff --git a/internal/store/database/stage_scan.go b/internal/store/database/stage_scan.go new file mode 100644 index 000000000..f8e1596c2 --- /dev/null +++ b/internal/store/database/stage_scan.go @@ -0,0 +1,162 @@ +// Copyright 2022 Harness Inc. All rights reserved. +// Use of this source code is governed by the Polyform Free Trial License +// that can be found in the LICENSE.md file for this repository. + +package database + +import ( + "database/sql" + "encoding/json" + "fmt" + + "github.com/harness/gitness/types" + sqlxtypes "github.com/jmoiron/sqlx/types" +) + +func mapInternalToStage(in *stage) (*types.Stage, error) { + var dependsOn []string + fmt.Println("in.DependsOn: ", in.DependsOn) + json.Unmarshal(in.DependsOn, &dependsOn) + var labels map[string]string + json.Unmarshal(in.Labels, &labels) + return &types.Stage{ + ID: in.ID, + ExecutionID: in.ExecutionID, + Number: in.Number, + Name: in.Name, + Kind: in.Kind, + Type: in.Type, + Status: in.Status, + Error: in.Error, + ErrIgnore: in.ErrIgnore, + ExitCode: in.ExitCode, + Machine: in.Machine, + OS: in.OS, + Arch: in.Arch, + Variant: in.Variant, + Kernel: in.Kernel, + Limit: in.Limit, + LimitRepo: in.LimitRepo, + Started: in.Started, + Stopped: in.Stopped, + Created: in.Created, + Updated: in.Updated, + Version: in.Version, + OnSuccess: in.OnSuccess, + OnFailure: in.OnFailure, + DependsOn: dependsOn, + Labels: labels, + }, nil +} + +func mapStageToInternal(in *types.Stage) *stage { + return &stage{ + ID: in.ID, + ExecutionID: in.ExecutionID, + Number: in.Number, + Name: in.Name, + Kind: in.Kind, + Type: in.Type, + Status: in.Status, + Error: in.Error, + ErrIgnore: in.ErrIgnore, + ExitCode: in.ExitCode, + Machine: in.Machine, + OS: in.OS, + Arch: in.Arch, + Variant: in.Variant, + Kernel: in.Kernel, + Limit: in.Limit, + LimitRepo: in.LimitRepo, + Started: in.Started, + Stopped: in.Stopped, + Created: in.Created, + Updated: in.Updated, + Version: in.Version, + OnSuccess: in.OnSuccess, + OnFailure: in.OnFailure, + DependsOn: EncodeToJSON(in.DependsOn), + Labels: EncodeToJSON(in.Labels), + } +} + +// helper function scans the sql.Row and copies the column +// values to the destination object. +// TODO: Use a nullstep instead to make sure values are not null +func scanRowsWithSteps(rows *sql.Rows) ([]*types.Stage, error) { + defer rows.Close() + + stages := []*types.Stage{} + var curr *types.Stage + for rows.Next() { + stage := new(types.Stage) + step := new(types.Step) + err := scanRowStep(rows, stage, step) + if err != nil { + return nil, err + } + if curr == nil || curr.ID != stage.ID { + curr = stage + stages = append(stages, curr) + } + if step.ID != 0 { + curr.Steps = append(curr.Steps, step) + } + } + return stages, nil +} + +// helper function scans the sql.Row and copies the column +// values to the destination object. +func scanRowStep(rows *sql.Rows, stage *types.Stage, step *types.Step) error { + depJSON := sqlxtypes.JSONText{} + labJSON := sqlxtypes.JSONText{} + stepDepJSON := sqlxtypes.JSONText{} + err := rows.Scan( + &stage.ID, + &stage.ExecutionID, + &stage.Number, + &stage.Name, + &stage.Kind, + &stage.Type, + &stage.Status, + &stage.Error, + &stage.ErrIgnore, + &stage.ExitCode, + &stage.Machine, + &stage.OS, + &stage.Arch, + &stage.Variant, + &stage.Kernel, + &stage.Limit, + &stage.LimitRepo, + &stage.Started, + &stage.Stopped, + &stage.Created, + &stage.Updated, + &stage.Version, + &stage.OnSuccess, + &stage.OnFailure, + &depJSON, + &labJSON, + &step.ID, + &step.StageID, + &step.Number, + &step.Name, + &step.Status, + &step.Error, + &step.ErrIgnore, + &step.ExitCode, + &step.Started, + &step.Stopped, + &step.Version, + &stepDepJSON, + &step.Image, + &step.Detached, + &step.Schema, + ) + json.Unmarshal(depJSON, &stage.DependsOn) + json.Unmarshal(labJSON, &stage.Labels) + json.Unmarshal(stepDepJSON, &step.DependsOn) + return err +} diff --git a/internal/store/database/step.go b/internal/store/database/step.go index 586aecbb0..94d76942f 100644 --- a/internal/store/database/step.go +++ b/internal/store/database/step.go @@ -13,6 +13,7 @@ import ( "github.com/harness/gitness/types" "github.com/jmoiron/sqlx" + sqlxtypes "github.com/jmoiron/sqlx/types" ) var _ store.StepStore = (*stepStore)(nil) @@ -34,8 +35,6 @@ const ( ,step_exit_code ,step_started ,step_stopped - ,step_created - ,step_updated ,step_version ,step_depends_on ,step_image @@ -44,6 +43,24 @@ const ( ` ) +type step struct { + ID int64 `db:"step_id"` + StageID int64 `db:"step_stage_id"` + Number int `db:"step_number"` + Name string `db:"step_name"` + Status string `db:"step_status"` + Error string `db:"step_error"` + ErrIgnore bool `db:"step_errignore"` + ExitCode int `db:"step_exit_code"` + Started int64 `db:"step_started"` + Stopped int64 `db:"step_stopped"` + Version int64 `db:"step_version"` + DependsOn sqlxtypes.JSONText `db:"step_depends_on"` + Image string `db:"step_image"` + Detached bool `db:"step_detached"` + Schema string `db:"step_schema"` +} + // NewStepStore returns a new StepStore. func NewStepStore(db *sqlx.DB) *stepStore { return &stepStore{ @@ -63,9 +80,9 @@ func (s *stepStore) FindNumber(ctx context.Context, stageID int64, stepNum int) WHERE step_stage_id = $1 AND step_number = $2` db := dbtx.GetAccessor(ctx, s.db) - dst := new(types.Step) + dst := new(step) if err := db.GetContext(ctx, dst, findQueryStmt, stageID, stepNum); err != nil { return nil, database.ProcessSQLErrorf(err, "Failed to find step") } - return dst, nil + return mapInternalToStep(dst) } diff --git a/internal/store/database/step_scan.go b/internal/store/database/step_scan.go new file mode 100644 index 000000000..3f666a0f7 --- /dev/null +++ b/internal/store/database/step_scan.go @@ -0,0 +1,54 @@ +// Copyright 2022 Harness Inc. All rights reserved. +// Use of this source code is governed by the Polyform Free Trial License +// that can be found in the LICENSE.md file for this repository. + +package database + +import ( + "github.com/harness/gitness/types" +) + +func mapInternalToStep(in *step) (*types.Step, error) { + var dependsOn []string + in.DependsOn.Unmarshal(&dependsOn) + // if err != nil { + // return nil, fmt.Errorf("could not unmarshal stage.DependsOn: %w", err) + // } + return &types.Step{ + ID: in.ID, + StageID: in.StageID, + Number: in.Number, + Name: in.Name, + Status: in.Status, + Error: in.Error, + ErrIgnore: in.ErrIgnore, + ExitCode: in.ExitCode, + Started: in.Started, + Stopped: in.Stopped, + Version: in.Version, + DependsOn: dependsOn, + Image: in.Image, + Detached: in.Detached, + Schema: in.Schema, + }, nil +} + +func mapStepToInternal(in *types.Step) *step { + return &step{ + ID: in.ID, + StageID: in.StageID, + Number: in.Number, + Name: in.Name, + Status: in.Status, + Error: in.Error, + ErrIgnore: in.ErrIgnore, + ExitCode: in.ExitCode, + Started: in.Started, + Stopped: in.Stopped, + Version: in.Version, + DependsOn: EncodeToJSON(in.DependsOn), + Image: in.Image, + Detached: in.Detached, + Schema: in.Schema, + } +} diff --git a/mocks/mock_client.go b/mocks/mock_client.go index 3cb746055..b16a6490e 100644 --- a/mocks/mock_client.go +++ b/mocks/mock_client.go @@ -8,10 +8,9 @@ import ( context "context" reflect "reflect" + gomock "github.com/golang/mock/gomock" user "github.com/harness/gitness/internal/api/controller/user" types "github.com/harness/gitness/types" - - gomock "github.com/golang/mock/gomock" ) // MockClient is a mock of Client interface. diff --git a/mocks/mock_store.go b/mocks/mock_store.go index 9310f3729..0af0bbc34 100644 --- a/mocks/mock_store.go +++ b/mocks/mock_store.go @@ -8,10 +8,9 @@ import ( context "context" reflect "reflect" + gomock "github.com/golang/mock/gomock" types "github.com/harness/gitness/types" enum "github.com/harness/gitness/types/enum" - - gomock "github.com/golang/mock/gomock" ) // MockPrincipalStore is a mock of PrincipalStore interface. diff --git a/types/execution.go b/types/execution.go index a66ff6680..ddb340c67 100644 --- a/types/execution.go +++ b/types/execution.go @@ -6,41 +6,40 @@ package types // Execution represents an instance of a pipeline execution. type Execution struct { - ID int64 `db:"execution_id" json:"id"` - PipelineID int64 `db:"execution_pipeline_id" json:"pipeline_id"` - RepoID int64 `db:"execution_repo_id" json:"repo_id"` - Trigger string `db:"execution_trigger" json:"trigger"` - Number int64 `db:"execution_number" json:"number"` - Parent int64 `db:"execution_parent" json:"parent,omitempty"` - Status string `db:"execution_status" json:"status"` - Error string `db:"execution_error" json:"error,omitempty"` - Event string `db:"execution_event" json:"event"` - Action string `db:"execution_action" json:"action"` - Link string `db:"execution_link" json:"link"` - Timestamp int64 `db:"execution_timestamp" json:"timestamp"` - Title string `db:"execution_title" json:"title,omitempty"` - Message string `db:"execution_message" json:"message"` - Before string `db:"execution_before" json:"before"` - After string `db:"execution_after" json:"after"` - Ref string `db:"execution_ref" json:"ref"` - Fork string `db:"execution_source_repo" json:"source_repo"` - Source string `db:"execution_source" json:"source"` - Target string `db:"execution_target" json:"target"` - Author string `db:"execution_author" json:"author_login"` - AuthorName string `db:"execution_author_name" json:"author_name"` - AuthorEmail string `db:"execution_author_email" json:"author_email"` - AuthorAvatar string `db:"execution_author_avatar" json:"author_avatar"` - Sender string `db:"execution_sender" json:"sender"` - Params string `db:"execution_params" json:"params,omitempty"` - Cron string `db:"execution_cron" json:"cron,omitempty"` - Deploy string `db:"execution_deploy" json:"deploy_to,omitempty"` - DeployID int64 `db:"execution_deploy_id" json:"deploy_id,omitempty"` - Debug bool `db:"execution_debug" json:"debug,omitempty"` - Started int64 `db:"execution_started" json:"started"` - Finished int64 `db:"execution_finished" json:"finished"` - Created int64 `db:"execution_created" json:"created"` - Updated int64 `db:"execution_updated" json:"updated"` - Version int64 `db:"execution_version" json:"version"` - // TODO: (Vistaar) Add stages - // Stages []*Stage `db:"-" json:"stages,omitempty"` + ID int64 `db:"execution_id" json:"id"` + PipelineID int64 `db:"execution_pipeline_id" json:"pipeline_id"` + RepoID int64 `db:"execution_repo_id" json:"repo_id"` + Trigger string `db:"execution_trigger" json:"trigger"` + Number int64 `db:"execution_number" json:"number"` + Parent int64 `db:"execution_parent" json:"parent,omitempty"` + Status string `db:"execution_status" json:"status"` + Error string `db:"execution_error" json:"error,omitempty"` + Event string `db:"execution_event" json:"event"` + Action string `db:"execution_action" json:"action"` + Link string `db:"execution_link" json:"link"` + Timestamp int64 `db:"execution_timestamp" json:"timestamp"` + Title string `db:"execution_title" json:"title,omitempty"` + Message string `db:"execution_message" json:"message"` + Before string `db:"execution_before" json:"before"` + After string `db:"execution_after" json:"after"` + Ref string `db:"execution_ref" json:"ref"` + Fork string `db:"execution_source_repo" json:"source_repo"` + Source string `db:"execution_source" json:"source"` + Target string `db:"execution_target" json:"target"` + Author string `db:"execution_author" json:"author_login"` + AuthorName string `db:"execution_author_name" json:"author_name"` + AuthorEmail string `db:"execution_author_email" json:"author_email"` + AuthorAvatar string `db:"execution_author_avatar" json:"author_avatar"` + Sender string `db:"execution_sender" json:"sender"` + Params string `db:"execution_params" json:"params,omitempty"` + Cron string `db:"execution_cron" json:"cron,omitempty"` + Deploy string `db:"execution_deploy" json:"deploy_to,omitempty"` + DeployID int64 `db:"execution_deploy_id" json:"deploy_id,omitempty"` + Debug bool `db:"execution_debug" json:"debug,omitempty"` + Started int64 `db:"execution_started" json:"started"` + Finished int64 `db:"execution_finished" json:"finished"` + Created int64 `db:"execution_created" json:"created"` + Updated int64 `db:"execution_updated" json:"updated"` + Version int64 `db:"execution_version" json:"version"` + Stages []*Stage `db:"-" json:"stages,omitempty"` } diff --git a/types/step.go b/types/step.go index c78d3d2ed..526972b6b 100644 --- a/types/step.go +++ b/types/step.go @@ -15,8 +15,6 @@ type Step struct { ExitCode int `json:"exit_code" db:"step_exit_code"` Started int64 `json:"started,omitempty" db:"step_started"` Stopped int64 `json:"stopped,omitempty" db:"step_stopped"` - Created int64 `json:"created" db:"step_created"` - Updated int64 `json:"updated" db:"step_updated"` Version int64 `json:"version" db:"step_version"` DependsOn []string `json:"depends_on,omitempty" db:"step_depends_on"` Image string `json:"image,omitempty" db:"step_image"`