mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2025-02-16 19:35:14 +00:00
Cleanup state reporting (#3850)
This commit is contained in:
parent
daeab8d3c7
commit
2fa9432ef8
18 changed files with 590 additions and 514 deletions
|
@ -36,7 +36,7 @@ func (r *Runner) createLogger(_logger zerolog.Logger, uploads *sync.WaitGroup, w
|
||||||
return func(step *backend.Step, rc io.Reader) error {
|
return func(step *backend.Step, rc io.Reader) error {
|
||||||
logger := _logger.With().
|
logger := _logger.With().
|
||||||
Str("image", step.Image).
|
Str("image", step.Image).
|
||||||
Str("workflowID", workflow.ID).
|
Str("workflow_id", workflow.ID).
|
||||||
Logger()
|
Logger()
|
||||||
|
|
||||||
uploads.Add(1)
|
uploads.Add(1)
|
||||||
|
|
|
@ -161,17 +161,14 @@ func (c *client) Wait(ctx context.Context, id string) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init signals the workflow is initialized.
|
// Init signals the workflow is initialized.
|
||||||
func (c *client) Init(ctx context.Context, id string, state rpc.State) (err error) {
|
func (c *client) Init(ctx context.Context, workflowID string, state rpc.WorkflowState) (err error) {
|
||||||
retry := c.newBackOff()
|
retry := c.newBackOff()
|
||||||
req := new(proto.InitRequest)
|
req := new(proto.InitRequest)
|
||||||
req.Id = id
|
req.Id = workflowID
|
||||||
req.State = new(proto.State)
|
req.State = new(proto.WorkflowState)
|
||||||
req.State.Error = state.Error
|
|
||||||
req.State.ExitCode = int32(state.ExitCode)
|
|
||||||
req.State.Exited = state.Exited
|
|
||||||
req.State.Finished = state.Finished
|
|
||||||
req.State.Started = state.Started
|
req.State.Started = state.Started
|
||||||
req.State.StepUuid = state.StepUUID
|
req.State.Finished = state.Finished
|
||||||
|
req.State.Error = state.Error
|
||||||
for {
|
for {
|
||||||
_, err = c.client.Init(ctx, req)
|
_, err = c.client.Init(ctx, req)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -201,18 +198,15 @@ func (c *client) Init(ctx context.Context, id string, state rpc.State) (err erro
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Done signals the work is complete.
|
// Done signals the workflow is complete.
|
||||||
func (c *client) Done(ctx context.Context, id string, state rpc.State) (err error) {
|
func (c *client) Done(ctx context.Context, workflowID string, state rpc.WorkflowState) (err error) {
|
||||||
retry := c.newBackOff()
|
retry := c.newBackOff()
|
||||||
req := new(proto.DoneRequest)
|
req := new(proto.DoneRequest)
|
||||||
req.Id = id
|
req.Id = workflowID
|
||||||
req.State = new(proto.State)
|
req.State = new(proto.WorkflowState)
|
||||||
req.State.Error = state.Error
|
|
||||||
req.State.ExitCode = int32(state.ExitCode)
|
|
||||||
req.State.Exited = state.Exited
|
|
||||||
req.State.Finished = state.Finished
|
|
||||||
req.State.Started = state.Started
|
req.State.Started = state.Started
|
||||||
req.State.StepUuid = state.StepUUID
|
req.State.Finished = state.Finished
|
||||||
|
req.State.Error = state.Error
|
||||||
for {
|
for {
|
||||||
_, err = c.client.Done(ctx, req)
|
_, err = c.client.Done(ctx, req)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -277,17 +271,17 @@ func (c *client) Extend(ctx context.Context, id string) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update updates the workflow state.
|
// Update updates the workflow state.
|
||||||
func (c *client) Update(ctx context.Context, id string, state rpc.State) (err error) {
|
func (c *client) Update(ctx context.Context, id string, state rpc.StepState) (err error) {
|
||||||
retry := c.newBackOff()
|
retry := c.newBackOff()
|
||||||
req := new(proto.UpdateRequest)
|
req := new(proto.UpdateRequest)
|
||||||
req.Id = id
|
req.Id = id
|
||||||
req.State = new(proto.State)
|
req.State = new(proto.StepState)
|
||||||
req.State.Error = state.Error
|
|
||||||
req.State.ExitCode = int32(state.ExitCode)
|
|
||||||
req.State.Exited = state.Exited
|
|
||||||
req.State.Finished = state.Finished
|
|
||||||
req.State.Started = state.Started
|
|
||||||
req.State.StepUuid = state.StepUUID
|
req.State.StepUuid = state.StepUUID
|
||||||
|
req.State.Started = state.Started
|
||||||
|
req.State.Finished = state.Finished
|
||||||
|
req.State.Exited = state.Exited
|
||||||
|
req.State.ExitCode = int32(state.ExitCode)
|
||||||
|
req.State.Error = state.Error
|
||||||
for {
|
for {
|
||||||
_, err = c.client.Update(ctx, req)
|
_, err = c.client.Update(ctx, req)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|
|
@ -23,7 +23,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/tevino/abool/v2"
|
|
||||||
"google.golang.org/grpc/metadata"
|
"google.golang.org/grpc/metadata"
|
||||||
|
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/pipeline"
|
"go.woodpecker-ci.org/woodpecker/v2/pipeline"
|
||||||
|
@ -57,34 +56,34 @@ func (r *Runner) Run(runnerCtx context.Context) error { //nolint:contextcheck
|
||||||
ctxMeta := metadata.NewOutgoingContext(context.Background(), meta)
|
ctxMeta := metadata.NewOutgoingContext(context.Background(), meta)
|
||||||
|
|
||||||
// get the next workflow from the queue
|
// get the next workflow from the queue
|
||||||
work, err := r.client.Next(runnerCtx, r.filter)
|
workflow, err := r.client.Next(runnerCtx, r.filter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if work == nil {
|
if workflow == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
timeout := time.Hour
|
timeout := time.Hour
|
||||||
if minutes := work.Timeout; minutes != 0 {
|
if minutes := workflow.Timeout; minutes != 0 {
|
||||||
timeout = time.Duration(minutes) * time.Minute
|
timeout = time.Duration(minutes) * time.Minute
|
||||||
}
|
}
|
||||||
|
|
||||||
repoName := extractRepositoryName(work.Config) // hack
|
repoName := extractRepositoryName(workflow.Config) // hack
|
||||||
pipelineNumber := extractPipelineNumber(work.Config) // hack
|
pipelineNumber := extractPipelineNumber(workflow.Config) // hack
|
||||||
|
|
||||||
r.counter.Add(
|
r.counter.Add(
|
||||||
work.ID,
|
workflow.ID,
|
||||||
timeout,
|
timeout,
|
||||||
repoName,
|
repoName,
|
||||||
pipelineNumber,
|
pipelineNumber,
|
||||||
)
|
)
|
||||||
defer r.counter.Done(work.ID)
|
defer r.counter.Done(workflow.ID)
|
||||||
|
|
||||||
logger := log.With().
|
logger := log.With().
|
||||||
Str("repo", repoName).
|
Str("repo", repoName).
|
||||||
Str("pipeline", pipelineNumber).
|
Str("pipeline", pipelineNumber).
|
||||||
Str("id", work.ID).
|
Str("workflow_id", workflow.ID).
|
||||||
Logger()
|
Logger()
|
||||||
|
|
||||||
logger.Debug().Msg("received execution")
|
logger.Debug().Msg("received execution")
|
||||||
|
@ -99,17 +98,17 @@ func (r *Runner) Run(runnerCtx context.Context) error { //nolint:contextcheck
|
||||||
logger.Error().Msg("Received sigterm termination signal")
|
logger.Error().Msg("Received sigterm termination signal")
|
||||||
})
|
})
|
||||||
|
|
||||||
canceled := abool.New()
|
canceled := false
|
||||||
go func() {
|
go func() {
|
||||||
logger.Debug().Msg("listen for cancel signal")
|
logger.Debug().Msg("listen for cancel signal")
|
||||||
|
|
||||||
if err := r.client.Wait(workflowCtx, work.ID); err != nil {
|
if err := r.client.Wait(workflowCtx, workflow.ID); err != nil {
|
||||||
canceled.SetTo(true)
|
canceled = true
|
||||||
logger.Warn().Err(err).Msg("cancel signal received")
|
logger.Warn().Err(err).Msg("cancel signal received")
|
||||||
|
|
||||||
cancel()
|
cancel()
|
||||||
} else {
|
} else {
|
||||||
logger.Debug().Msg("stop listening for cancel signal")
|
logger.Debug().Msg("done listening for cancel signal")
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -123,76 +122,66 @@ func (r *Runner) Run(runnerCtx context.Context) error { //nolint:contextcheck
|
||||||
case <-time.After(time.Minute):
|
case <-time.After(time.Minute):
|
||||||
logger.Debug().Msg("pipeline lease renewed")
|
logger.Debug().Msg("pipeline lease renewed")
|
||||||
|
|
||||||
if err := r.client.Extend(workflowCtx, work.ID); err != nil {
|
if err := r.client.Extend(workflowCtx, workflow.ID); err != nil {
|
||||||
log.Error().Err(err).Msg("extending pipeline deadline failed")
|
log.Error().Err(err).Msg("extending pipeline deadline failed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
state := rpc.State{}
|
state := rpc.WorkflowState{}
|
||||||
state.Started = time.Now().Unix()
|
state.Started = time.Now().Unix()
|
||||||
|
|
||||||
err = r.client.Init(runnerCtx, work.ID, state)
|
err = r.client.Init(runnerCtx, workflow.ID, state)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error().Err(err).Msg("pipeline initialization failed")
|
logger.Error().Err(err).Msg("workflow initialization failed")
|
||||||
|
// TODO: should we return here?
|
||||||
}
|
}
|
||||||
|
|
||||||
var uploads sync.WaitGroup
|
var uploads sync.WaitGroup
|
||||||
//nolint:contextcheck
|
//nolint:contextcheck
|
||||||
err = pipeline.New(work.Config,
|
err = pipeline.New(workflow.Config,
|
||||||
pipeline.WithContext(workflowCtx),
|
pipeline.WithContext(workflowCtx),
|
||||||
pipeline.WithTaskUUID(fmt.Sprint(work.ID)),
|
pipeline.WithTaskUUID(fmt.Sprint(workflow.ID)),
|
||||||
pipeline.WithLogger(r.createLogger(logger, &uploads, work)),
|
pipeline.WithLogger(r.createLogger(logger, &uploads, workflow)),
|
||||||
pipeline.WithTracer(r.createTracer(ctxMeta, logger, work)),
|
pipeline.WithTracer(r.createTracer(ctxMeta, logger, workflow)),
|
||||||
pipeline.WithBackend(*r.backend),
|
pipeline.WithBackend(*r.backend),
|
||||||
pipeline.WithDescription(map[string]string{
|
pipeline.WithDescription(map[string]string{
|
||||||
"ID": work.ID,
|
"workflow_id": workflow.ID,
|
||||||
"Repo": repoName,
|
"repo": repoName,
|
||||||
"Pipeline": pipelineNumber,
|
"pipeline_number": pipelineNumber,
|
||||||
}),
|
}),
|
||||||
).Run(runnerCtx)
|
).Run(runnerCtx)
|
||||||
|
|
||||||
state.Finished = time.Now().Unix()
|
state.Finished = time.Now().Unix()
|
||||||
state.Exited = true
|
|
||||||
|
|
||||||
if canceled.IsSet() {
|
if errors.Is(err, pipeline.ErrCancel) {
|
||||||
state.Error = ""
|
canceled = true
|
||||||
state.ExitCode = pipeline.ExitCodeKilled
|
} else if canceled {
|
||||||
} else if err != nil {
|
err = errors.Join(err, pipeline.ErrCancel)
|
||||||
pExitError := &pipeline.ExitError{}
|
}
|
||||||
switch {
|
|
||||||
case errors.As(err, &pExitError):
|
if err != nil {
|
||||||
state.ExitCode = pExitError.Code
|
|
||||||
case errors.Is(err, pipeline.ErrCancel):
|
|
||||||
state.Error = ""
|
|
||||||
state.ExitCode = pipeline.ExitCodeKilled
|
|
||||||
canceled.SetTo(true)
|
|
||||||
default:
|
|
||||||
state.ExitCode = 1
|
|
||||||
state.Error = err.Error()
|
state.Error = err.Error()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
logger.Debug().
|
logger.Debug().
|
||||||
Str("error", state.Error).
|
Str("error", state.Error).
|
||||||
Int("exit_code", state.ExitCode).
|
Bool("canceled", canceled).
|
||||||
Bool("canceled", canceled.IsSet()).
|
Msg("workflow finished")
|
||||||
Msg("pipeline complete")
|
|
||||||
|
|
||||||
logger.Debug().Msg("uploading logs")
|
logger.Debug().Msg("uploading logs ...")
|
||||||
uploads.Wait()
|
uploads.Wait()
|
||||||
logger.Debug().Msg("uploading logs complete")
|
logger.Debug().Msg("uploaded logs")
|
||||||
|
|
||||||
logger.Debug().
|
logger.Debug().
|
||||||
Str("error", state.Error).
|
Str("error", state.Error).
|
||||||
Int("exit_code", state.ExitCode).
|
Msg("updating workflow status")
|
||||||
Msg("updating pipeline status")
|
|
||||||
|
|
||||||
if err := r.client.Done(runnerCtx, work.ID, state); err != nil {
|
if err := r.client.Done(runnerCtx, workflow.ID, state); err != nil {
|
||||||
logger.Error().Err(err).Msg("updating pipeline status failed")
|
logger.Error().Err(err).Msg("updating workflow status failed")
|
||||||
} else {
|
} else {
|
||||||
logger.Debug().Msg("updating pipeline status complete")
|
logger.Debug().Msg("updating workflow status complete")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -36,7 +36,7 @@ func (r *Runner) createTracer(ctxMeta context.Context, logger zerolog.Logger, wo
|
||||||
Bool("exited", state.Process.Exited).
|
Bool("exited", state.Process.Exited).
|
||||||
Logger()
|
Logger()
|
||||||
|
|
||||||
stepState := rpc.State{
|
stepState := rpc.StepState{
|
||||||
StepUUID: state.Pipeline.Step.UUID,
|
StepUUID: state.Pipeline.Step.UUID,
|
||||||
Exited: state.Process.Exited,
|
Exited: state.Process.Exited,
|
||||||
ExitCode: state.Process.ExitCode,
|
ExitCode: state.Process.ExitCode,
|
||||||
|
@ -69,11 +69,11 @@ func (r *Runner) createTracer(ctxMeta context.Context, logger zerolog.Logger, wo
|
||||||
state.Pipeline.Step.Environment["CI_MACHINE"] = r.hostname
|
state.Pipeline.Step.Environment["CI_MACHINE"] = r.hostname
|
||||||
|
|
||||||
state.Pipeline.Step.Environment["CI_PIPELINE_STATUS"] = "success"
|
state.Pipeline.Step.Environment["CI_PIPELINE_STATUS"] = "success"
|
||||||
state.Pipeline.Step.Environment["CI_PIPELINE_STARTED"] = strconv.FormatInt(state.Pipeline.Time, 10)
|
state.Pipeline.Step.Environment["CI_PIPELINE_STARTED"] = strconv.FormatInt(state.Pipeline.Started, 10)
|
||||||
state.Pipeline.Step.Environment["CI_PIPELINE_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
|
state.Pipeline.Step.Environment["CI_PIPELINE_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
|
||||||
|
|
||||||
state.Pipeline.Step.Environment["CI_STEP_STATUS"] = "success"
|
state.Pipeline.Step.Environment["CI_STEP_STATUS"] = "success"
|
||||||
state.Pipeline.Step.Environment["CI_STEP_STARTED"] = strconv.FormatInt(state.Pipeline.Time, 10)
|
state.Pipeline.Step.Environment["CI_STEP_STARTED"] = strconv.FormatInt(state.Pipeline.Started, 10)
|
||||||
state.Pipeline.Step.Environment["CI_STEP_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
|
state.Pipeline.Step.Environment["CI_STEP_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
|
||||||
|
|
||||||
state.Pipeline.Step.Environment["CI_SYSTEM_PLATFORM"] = runtime.GOOS + "/" + runtime.GOARCH
|
state.Pipeline.Step.Environment["CI_SYSTEM_PLATFORM"] = runtime.GOOS + "/" + runtime.GOARCH
|
||||||
|
|
|
@ -38,7 +38,7 @@ type (
|
||||||
// Global state of the pipeline.
|
// Global state of the pipeline.
|
||||||
Pipeline struct {
|
Pipeline struct {
|
||||||
// Pipeline time started
|
// Pipeline time started
|
||||||
Time int64 `json:"time"`
|
Started int64 `json:"time"`
|
||||||
// Current pipeline step
|
// Current pipeline step
|
||||||
Step *backend.Step `json:"step"`
|
Step *backend.Step `json:"step"`
|
||||||
// Current pipeline error state
|
// Current pipeline error state
|
||||||
|
@ -147,7 +147,7 @@ func (r *Runtime) traceStep(processState *backend.State, err error, step *backen
|
||||||
}
|
}
|
||||||
|
|
||||||
state := new(State)
|
state := new(State)
|
||||||
state.Pipeline.Time = r.started
|
state.Pipeline.Started = r.started
|
||||||
state.Pipeline.Step = step
|
state.Pipeline.Step = step
|
||||||
state.Process = processState // empty
|
state.Process = processState // empty
|
||||||
state.Pipeline.Error = r.err
|
state.Pipeline.Error = r.err
|
||||||
|
|
|
@ -17,17 +17,17 @@ type Peer struct {
|
||||||
mock.Mock
|
mock.Mock
|
||||||
}
|
}
|
||||||
|
|
||||||
// Done provides a mock function with given fields: c, id, state
|
// Done provides a mock function with given fields: c, workflowID, state
|
||||||
func (_m *Peer) Done(c context.Context, id string, state rpc.State) error {
|
func (_m *Peer) Done(c context.Context, workflowID string, state rpc.WorkflowState) error {
|
||||||
ret := _m.Called(c, id, state)
|
ret := _m.Called(c, workflowID, state)
|
||||||
|
|
||||||
if len(ret) == 0 {
|
if len(ret) == 0 {
|
||||||
panic("no return value specified for Done")
|
panic("no return value specified for Done")
|
||||||
}
|
}
|
||||||
|
|
||||||
var r0 error
|
var r0 error
|
||||||
if rf, ok := ret.Get(0).(func(context.Context, string, rpc.State) error); ok {
|
if rf, ok := ret.Get(0).(func(context.Context, string, rpc.WorkflowState) error); ok {
|
||||||
r0 = rf(c, id, state)
|
r0 = rf(c, workflowID, state)
|
||||||
} else {
|
} else {
|
||||||
r0 = ret.Error(0)
|
r0 = ret.Error(0)
|
||||||
}
|
}
|
||||||
|
@ -35,9 +35,9 @@ func (_m *Peer) Done(c context.Context, id string, state rpc.State) error {
|
||||||
return r0
|
return r0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extend provides a mock function with given fields: c, id
|
// Extend provides a mock function with given fields: c, workflowID
|
||||||
func (_m *Peer) Extend(c context.Context, id string) error {
|
func (_m *Peer) Extend(c context.Context, workflowID string) error {
|
||||||
ret := _m.Called(c, id)
|
ret := _m.Called(c, workflowID)
|
||||||
|
|
||||||
if len(ret) == 0 {
|
if len(ret) == 0 {
|
||||||
panic("no return value specified for Extend")
|
panic("no return value specified for Extend")
|
||||||
|
@ -45,7 +45,7 @@ func (_m *Peer) Extend(c context.Context, id string) error {
|
||||||
|
|
||||||
var r0 error
|
var r0 error
|
||||||
if rf, ok := ret.Get(0).(func(context.Context, string) error); ok {
|
if rf, ok := ret.Get(0).(func(context.Context, string) error); ok {
|
||||||
r0 = rf(c, id)
|
r0 = rf(c, workflowID)
|
||||||
} else {
|
} else {
|
||||||
r0 = ret.Error(0)
|
r0 = ret.Error(0)
|
||||||
}
|
}
|
||||||
|
@ -53,17 +53,17 @@ func (_m *Peer) Extend(c context.Context, id string) error {
|
||||||
return r0
|
return r0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init provides a mock function with given fields: c, id, state
|
// Init provides a mock function with given fields: c, workflowID, state
|
||||||
func (_m *Peer) Init(c context.Context, id string, state rpc.State) error {
|
func (_m *Peer) Init(c context.Context, workflowID string, state rpc.WorkflowState) error {
|
||||||
ret := _m.Called(c, id, state)
|
ret := _m.Called(c, workflowID, state)
|
||||||
|
|
||||||
if len(ret) == 0 {
|
if len(ret) == 0 {
|
||||||
panic("no return value specified for Init")
|
panic("no return value specified for Init")
|
||||||
}
|
}
|
||||||
|
|
||||||
var r0 error
|
var r0 error
|
||||||
if rf, ok := ret.Get(0).(func(context.Context, string, rpc.State) error); ok {
|
if rf, ok := ret.Get(0).(func(context.Context, string, rpc.WorkflowState) error); ok {
|
||||||
r0 = rf(c, id, state)
|
r0 = rf(c, workflowID, state)
|
||||||
} else {
|
} else {
|
||||||
r0 = ret.Error(0)
|
r0 = ret.Error(0)
|
||||||
}
|
}
|
||||||
|
@ -183,17 +183,17 @@ func (_m *Peer) UnregisterAgent(ctx context.Context) error {
|
||||||
return r0
|
return r0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update provides a mock function with given fields: c, id, state
|
// Update provides a mock function with given fields: c, workflowID, state
|
||||||
func (_m *Peer) Update(c context.Context, id string, state rpc.State) error {
|
func (_m *Peer) Update(c context.Context, workflowID string, state rpc.StepState) error {
|
||||||
ret := _m.Called(c, id, state)
|
ret := _m.Called(c, workflowID, state)
|
||||||
|
|
||||||
if len(ret) == 0 {
|
if len(ret) == 0 {
|
||||||
panic("no return value specified for Update")
|
panic("no return value specified for Update")
|
||||||
}
|
}
|
||||||
|
|
||||||
var r0 error
|
var r0 error
|
||||||
if rf, ok := ret.Get(0).(func(context.Context, string, rpc.State) error); ok {
|
if rf, ok := ret.Get(0).(func(context.Context, string, rpc.StepState) error); ok {
|
||||||
r0 = rf(c, id, state)
|
r0 = rf(c, workflowID, state)
|
||||||
} else {
|
} else {
|
||||||
r0 = ret.Error(0)
|
r0 = ret.Error(0)
|
||||||
}
|
}
|
||||||
|
@ -231,9 +231,9 @@ func (_m *Peer) Version(c context.Context) (*rpc.Version, error) {
|
||||||
return r0, r1
|
return r0, r1
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait provides a mock function with given fields: c, id
|
// Wait provides a mock function with given fields: c, workflowID
|
||||||
func (_m *Peer) Wait(c context.Context, id string) error {
|
func (_m *Peer) Wait(c context.Context, workflowID string) error {
|
||||||
ret := _m.Called(c, id)
|
ret := _m.Called(c, workflowID)
|
||||||
|
|
||||||
if len(ret) == 0 {
|
if len(ret) == 0 {
|
||||||
panic("no return value specified for Wait")
|
panic("no return value specified for Wait")
|
||||||
|
@ -241,7 +241,7 @@ func (_m *Peer) Wait(c context.Context, id string) error {
|
||||||
|
|
||||||
var r0 error
|
var r0 error
|
||||||
if rf, ok := ret.Get(0).(func(context.Context, string) error); ok {
|
if rf, ok := ret.Get(0).(func(context.Context, string) error); ok {
|
||||||
r0 = rf(c, id)
|
r0 = rf(c, workflowID)
|
||||||
} else {
|
} else {
|
||||||
r0 = ret.Error(0)
|
r0 = ret.Error(0)
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,11 +27,18 @@ type (
|
||||||
Labels map[string]string `json:"labels"`
|
Labels map[string]string `json:"labels"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// State defines the step state.
|
// StepState defines the step state.
|
||||||
State struct {
|
StepState struct {
|
||||||
StepUUID string `json:"step_uuid"`
|
StepUUID string `json:"step_uuid"`
|
||||||
|
Started int64 `json:"started"`
|
||||||
|
Finished int64 `json:"finished"`
|
||||||
Exited bool `json:"exited"`
|
Exited bool `json:"exited"`
|
||||||
ExitCode int `json:"exit_code"`
|
ExitCode int `json:"exit_code"`
|
||||||
|
Error string `json:"error"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// WorkflowState defines the workflow state.
|
||||||
|
WorkflowState struct {
|
||||||
Started int64 `json:"started"`
|
Started int64 `json:"started"`
|
||||||
Finished int64 `json:"finished"`
|
Finished int64 `json:"finished"`
|
||||||
Error string `json:"error"`
|
Error string `json:"error"`
|
||||||
|
@ -61,21 +68,21 @@ type Peer interface {
|
||||||
Next(c context.Context, f Filter) (*Workflow, error)
|
Next(c context.Context, f Filter) (*Workflow, error)
|
||||||
|
|
||||||
// Wait blocks until the workflow is complete
|
// Wait blocks until the workflow is complete
|
||||||
Wait(c context.Context, id string) error
|
Wait(c context.Context, workflowID string) error
|
||||||
|
|
||||||
// Init signals the step is initialized
|
// Init signals the workflow is initialized
|
||||||
Init(c context.Context, id string, state State) error
|
Init(c context.Context, workflowID string, state WorkflowState) error
|
||||||
|
|
||||||
// Done signals the step is complete
|
// Done signals the workflow is complete
|
||||||
Done(c context.Context, id string, state State) error
|
Done(c context.Context, workflowID string, state WorkflowState) error
|
||||||
|
|
||||||
// Extend extends the workflow deadline
|
// Extend extends the workflow deadline
|
||||||
Extend(c context.Context, id string) error
|
Extend(c context.Context, workflowID string) error
|
||||||
|
|
||||||
// Update updates the step state
|
// Update updates the step state
|
||||||
Update(c context.Context, id string, state State) error
|
Update(c context.Context, workflowID string, state StepState) error
|
||||||
|
|
||||||
// Log writes the workflow log entry
|
// Log writes the step log entry
|
||||||
Log(c context.Context, logEntry *LogEntry) error
|
Log(c context.Context, logEntry *LogEntry) error
|
||||||
|
|
||||||
// RegisterAgent register our agent to the server
|
// RegisterAgent register our agent to the server
|
||||||
|
|
|
@ -16,4 +16,4 @@ package proto
|
||||||
|
|
||||||
// Version is the version of the woodpecker.proto file,
|
// Version is the version of the woodpecker.proto file,
|
||||||
// IMPORTANT: increased by 1 each time it get changed.
|
// IMPORTANT: increased by 1 each time it get changed.
|
||||||
const Version int32 = 8
|
const Version int32 = 9
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -41,10 +41,16 @@ service Woodpecker {
|
||||||
// Basic Types
|
// Basic Types
|
||||||
//
|
//
|
||||||
|
|
||||||
message State {
|
message StepState {
|
||||||
string step_uuid = 1;
|
string step_uuid = 1;
|
||||||
bool exited = 2;
|
int64 started = 2;
|
||||||
int32 exit_code = 3;
|
int64 finished = 3;
|
||||||
|
bool exited = 4;
|
||||||
|
int32 exit_code = 5;
|
||||||
|
string error = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
message WorkflowState {
|
||||||
int64 started = 4;
|
int64 started = 4;
|
||||||
int64 finished = 5;
|
int64 finished = 5;
|
||||||
string error = 6;
|
string error = 6;
|
||||||
|
@ -78,7 +84,7 @@ message NextRequest {
|
||||||
|
|
||||||
message InitRequest {
|
message InitRequest {
|
||||||
string id = 1;
|
string id = 1;
|
||||||
State state = 2;
|
WorkflowState state = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message WaitRequest {
|
message WaitRequest {
|
||||||
|
@ -87,7 +93,7 @@ message WaitRequest {
|
||||||
|
|
||||||
message DoneRequest {
|
message DoneRequest {
|
||||||
string id = 1;
|
string id = 1;
|
||||||
State state = 2;
|
WorkflowState state = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ExtendRequest {
|
message ExtendRequest {
|
||||||
|
@ -96,7 +102,7 @@ message ExtendRequest {
|
||||||
|
|
||||||
message UpdateRequest {
|
message UpdateRequest {
|
||||||
string id = 1;
|
string id = 1;
|
||||||
State state = 2;
|
StepState state = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message LogRequest {
|
message LogRequest {
|
||||||
|
|
|
@ -44,11 +44,11 @@ var DefaultTracer = TraceFunc(func(state *State) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
state.Pipeline.Step.Environment["CI_PIPELINE_STATUS"] = "success"
|
state.Pipeline.Step.Environment["CI_PIPELINE_STATUS"] = "success"
|
||||||
state.Pipeline.Step.Environment["CI_PIPELINE_STARTED"] = strconv.FormatInt(state.Pipeline.Time, 10)
|
state.Pipeline.Step.Environment["CI_PIPELINE_STARTED"] = strconv.FormatInt(state.Pipeline.Started, 10)
|
||||||
state.Pipeline.Step.Environment["CI_PIPELINE_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
|
state.Pipeline.Step.Environment["CI_PIPELINE_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
|
||||||
|
|
||||||
state.Pipeline.Step.Environment["CI_STEP_STATUS"] = "success"
|
state.Pipeline.Step.Environment["CI_STEP_STATUS"] = "success"
|
||||||
state.Pipeline.Step.Environment["CI_STEP_STARTED"] = strconv.FormatInt(state.Pipeline.Time, 10)
|
state.Pipeline.Step.Environment["CI_STEP_STARTED"] = strconv.FormatInt(state.Pipeline.Started, 10)
|
||||||
state.Pipeline.Step.Environment["CI_STEP_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
|
state.Pipeline.Step.Environment["CI_STEP_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
|
||||||
|
|
||||||
if state.Pipeline.Error != nil {
|
if state.Pipeline.Error != nil {
|
||||||
|
|
|
@ -48,7 +48,7 @@ type RPC struct {
|
||||||
pipelineCount *prometheus.CounterVec
|
pipelineCount *prometheus.CounterVec
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next implements the rpc.Next function.
|
// Next blocks until it provides the next workflow to execute.
|
||||||
func (s *RPC) Next(c context.Context, agentFilter rpc.Filter) (*rpc.Workflow, error) {
|
func (s *RPC) Next(c context.Context, agentFilter rpc.Filter) (*rpc.Workflow, error) {
|
||||||
if hostname, err := s.getHostnameFromContext(c); err == nil {
|
if hostname, err := s.getHostnameFromContext(c); err == nil {
|
||||||
log.Debug().Msgf("agent connected: %s: polling", hostname)
|
log.Debug().Msgf("agent connected: %s: polling", hostname)
|
||||||
|
@ -80,25 +80,25 @@ func (s *RPC) Next(c context.Context, agentFilter rpc.Filter) (*rpc.Workflow, er
|
||||||
}
|
}
|
||||||
|
|
||||||
// task should not run, so mark it as done
|
// task should not run, so mark it as done
|
||||||
if err := s.Done(c, task.ID, rpc.State{}); err != nil {
|
if err := s.Done(c, task.ID, rpc.WorkflowState{}); err != nil {
|
||||||
log.Error().Err(err).Msgf("mark task '%s' done failed", task.ID)
|
log.Error().Err(err).Msgf("marking workflow task '%s' as done failed", task.ID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait implements the rpc.Wait function.
|
// Wait blocks until the workflow with the given ID is done.
|
||||||
func (s *RPC) Wait(c context.Context, id string) error {
|
func (s *RPC) Wait(c context.Context, workflowID string) error {
|
||||||
return s.queue.Wait(c, id)
|
return s.queue.Wait(c, workflowID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extend implements the rpc.Extend function.
|
// Extend extends the lease for the workflow with the given ID.
|
||||||
func (s *RPC) Extend(c context.Context, id string) error {
|
func (s *RPC) Extend(c context.Context, workflowID string) error {
|
||||||
return s.queue.Extend(c, id)
|
return s.queue.Extend(c, workflowID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update implements the rpc.Update function.
|
// Update updates the state of a step.
|
||||||
func (s *RPC) Update(_ context.Context, id string, state rpc.State) error {
|
func (s *RPC) Update(_ context.Context, strWorkflowID string, state rpc.StepState) error {
|
||||||
workflowID, err := strconv.ParseInt(id, 10, 64)
|
workflowID, err := strconv.ParseInt(strWorkflowID, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -163,15 +163,15 @@ func (s *RPC) Update(_ context.Context, id string, state rpc.State) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init implements the rpc.Init function.
|
// Init implements the rpc.Init function.
|
||||||
func (s *RPC) Init(c context.Context, id string, state rpc.State) error {
|
func (s *RPC) Init(c context.Context, strWorkflowID string, state rpc.WorkflowState) error {
|
||||||
stepID, err := strconv.ParseInt(id, 10, 64)
|
workflowID, err := strconv.ParseInt(strWorkflowID, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
workflow, err := s.store.WorkflowLoad(stepID)
|
workflow, err := s.store.WorkflowLoad(workflowID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msgf("cannot find step with id %d", stepID)
|
log.Error().Err(err).Msgf("cannot find workflow with id %d", workflowID)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,7 +195,7 @@ func (s *RPC) Init(c context.Context, id string, state rpc.State) error {
|
||||||
|
|
||||||
if currentPipeline.Status == model.StatusPending {
|
if currentPipeline.Status == model.StatusPending {
|
||||||
if currentPipeline, err = pipeline.UpdateToStatusRunning(s.store, *currentPipeline, state.Started); err != nil {
|
if currentPipeline, err = pipeline.UpdateToStatusRunning(s.store, *currentPipeline, state.Started); err != nil {
|
||||||
log.Error().Err(err).Msgf("init: cannot update build_id %d state", currentPipeline.ID)
|
log.Error().Err(err).Msgf("init: cannot update pipeline %d state", currentPipeline.ID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,24 +220,25 @@ func (s *RPC) Init(c context.Context, id string, state rpc.State) error {
|
||||||
s.pubsub.Publish(message)
|
s.pubsub.Publish(message)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
workflow, err = pipeline.UpdateWorkflowToStatusStarted(s.store, *workflow, state)
|
workflow, err = pipeline.UpdateWorkflowStatusToRunning(s.store, *workflow, state)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
s.updateForgeStatus(c, repo, currentPipeline, workflow)
|
s.updateForgeStatus(c, repo, currentPipeline, workflow)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Done implements the rpc.Done function.
|
// Done marks the workflow with the given ID as done.
|
||||||
func (s *RPC) Done(c context.Context, id string, state rpc.State) error {
|
func (s *RPC) Done(c context.Context, strWorkflowID string, state rpc.WorkflowState) error {
|
||||||
workflowID, err := strconv.ParseInt(id, 10, 64)
|
workflowID, err := strconv.ParseInt(strWorkflowID, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
workflow, err := s.store.WorkflowLoad(workflowID)
|
workflow, err := s.store.WorkflowLoad(workflowID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msgf("cannot find step with id %d", workflowID)
|
log.Error().Err(err).Msgf("cannot find workflow with id %d", workflowID)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,19 +262,19 @@ func (s *RPC) Done(c context.Context, id string, state rpc.State) error {
|
||||||
logger := log.With().
|
logger := log.With().
|
||||||
Str("repo_id", fmt.Sprint(repo.ID)).
|
Str("repo_id", fmt.Sprint(repo.ID)).
|
||||||
Str("pipeline_id", fmt.Sprint(currentPipeline.ID)).
|
Str("pipeline_id", fmt.Sprint(currentPipeline.ID)).
|
||||||
Str("workflow_id", id).Logger()
|
Str("workflow_id", strWorkflowID).Logger()
|
||||||
|
|
||||||
logger.Trace().Msgf("gRPC Done with state: %#v", state)
|
logger.Trace().Msgf("gRPC Done with state: %#v", state)
|
||||||
|
|
||||||
if workflow, err = pipeline.UpdateWorkflowStatusToDone(s.store, *workflow, state); err != nil {
|
if workflow, err = pipeline.UpdateWorkflowStatusToDone(s.store, *workflow, state); err != nil {
|
||||||
logger.Error().Err(err).Msgf("pipeline.UpdateStepStatusToDone: cannot update workflow state: %s", err)
|
logger.Error().Err(err).Msgf("pipeline.UpdateWorkflowStatusToDone: cannot update workflow state: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var queueErr error
|
var queueErr error
|
||||||
if workflow.Failing() {
|
if workflow.Failing() {
|
||||||
queueErr = s.queue.Error(c, id, fmt.Errorf("step finished with exit code %d, %s", state.ExitCode, state.Error))
|
queueErr = s.queue.Error(c, strWorkflowID, fmt.Errorf("workflow finished with error %s", state.Error))
|
||||||
} else {
|
} else {
|
||||||
queueErr = s.queue.Done(c, id, workflow.State)
|
queueErr = s.queue.Done(c, strWorkflowID, workflow.State)
|
||||||
}
|
}
|
||||||
if queueErr != nil {
|
if queueErr != nil {
|
||||||
logger.Error().Err(queueErr).Msg("queue.Done: cannot ack workflow")
|
logger.Error().Err(queueErr).Msg("queue.Done: cannot ack workflow")
|
||||||
|
@ -286,8 +287,8 @@ func (s *RPC) Done(c context.Context, id string, state rpc.State) error {
|
||||||
s.completeChildrenIfParentCompleted(workflow)
|
s.completeChildrenIfParentCompleted(workflow)
|
||||||
|
|
||||||
if !model.IsThereRunningStage(currentPipeline.Workflows) {
|
if !model.IsThereRunningStage(currentPipeline.Workflows) {
|
||||||
if currentPipeline, err = pipeline.UpdateStatusToDone(s.store, *currentPipeline, model.PipelineStatus(currentPipeline.Workflows), workflow.Stopped); err != nil {
|
if currentPipeline, err = pipeline.UpdateStatusToDone(s.store, *currentPipeline, model.PipelineStatus(currentPipeline.Workflows), workflow.Finished); err != nil {
|
||||||
logger.Error().Err(err).Msgf("pipeline.UpdateStatusToDone: cannot update workflow final state")
|
logger.Error().Err(err).Msgf("pipeline.UpdateStatusToDone: cannot update workflows final state")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,25 +312,25 @@ func (s *RPC) Done(c context.Context, id string, state rpc.State) error {
|
||||||
s.pipelineTime.WithLabelValues(repo.FullName, currentPipeline.Branch, string(currentPipeline.Status), "total").Set(float64(currentPipeline.Finished - currentPipeline.Started))
|
s.pipelineTime.WithLabelValues(repo.FullName, currentPipeline.Branch, string(currentPipeline.Status), "total").Set(float64(currentPipeline.Finished - currentPipeline.Started))
|
||||||
}
|
}
|
||||||
if currentPipeline.IsMultiPipeline() {
|
if currentPipeline.IsMultiPipeline() {
|
||||||
s.pipelineTime.WithLabelValues(repo.FullName, currentPipeline.Branch, string(workflow.State), workflow.Name).Set(float64(workflow.Stopped - workflow.Started))
|
s.pipelineTime.WithLabelValues(repo.FullName, currentPipeline.Branch, string(workflow.State), workflow.Name).Set(float64(workflow.Finished - workflow.Started))
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log implements the rpc.Log function.
|
// Log writes a log entry to the database and publishes it to the pubsub.
|
||||||
func (s *RPC) Log(c context.Context, _logEntry *rpc.LogEntry) error {
|
func (s *RPC) Log(c context.Context, rpcLogEntry *rpc.LogEntry) error {
|
||||||
// convert rpc log_entry to model.log_entry
|
// convert rpc log_entry to model.log_entry
|
||||||
step, err := s.store.StepByUUID(_logEntry.StepUUID)
|
step, err := s.store.StepByUUID(rpcLogEntry.StepUUID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not find step with uuid %s in store: %w", _logEntry.StepUUID, err)
|
return fmt.Errorf("could not find step with uuid %s in store: %w", rpcLogEntry.StepUUID, err)
|
||||||
}
|
}
|
||||||
logEntry := &model.LogEntry{
|
logEntry := &model.LogEntry{
|
||||||
StepID: step.ID,
|
StepID: step.ID,
|
||||||
Time: _logEntry.Time,
|
Time: rpcLogEntry.Time,
|
||||||
Line: _logEntry.Line,
|
Line: rpcLogEntry.Line,
|
||||||
Data: _logEntry.Data,
|
Data: rpcLogEntry.Data,
|
||||||
Type: model.LogEntryType(_logEntry.Type),
|
Type: model.LogEntryType(rpcLogEntry.Type),
|
||||||
}
|
}
|
||||||
// make sure writes to pubsub are non blocking (https://github.com/woodpecker-ci/woodpecker/blob/c919f32e0b6432a95e1a6d3d0ad662f591adf73f/server/logging/log.go#L9)
|
// make sure writes to pubsub are non blocking (https://github.com/woodpecker-ci/woodpecker/blob/c919f32e0b6432a95e1a6d3d0ad662f591adf73f/server/logging/log.go#L9)
|
||||||
go func() {
|
go func() {
|
||||||
|
@ -366,13 +367,14 @@ func (s *RPC) RegisterAgent(ctx context.Context, platform, backend, version stri
|
||||||
return agent.ID, nil
|
return agent.ID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnregisterAgent removes the agent from the database.
|
||||||
func (s *RPC) UnregisterAgent(ctx context.Context) error {
|
func (s *RPC) UnregisterAgent(ctx context.Context) error {
|
||||||
agent, err := s.getAgentFromContext(ctx)
|
agent, err := s.getAgentFromContext(ctx)
|
||||||
if !agent.IsSystemAgent() {
|
if !agent.IsSystemAgent() {
|
||||||
// registered with individual agent token -> do not unregister
|
// registered with individual agent token -> do not unregister
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
log.Debug().Msgf("unregistering agent with ID %d", agent.ID)
|
log.Debug().Msgf("un-registering agent with ID %d", agent.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -401,7 +403,7 @@ func (s *RPC) ReportHealth(ctx context.Context, status string) error {
|
||||||
func (s *RPC) completeChildrenIfParentCompleted(completedWorkflow *model.Workflow) {
|
func (s *RPC) completeChildrenIfParentCompleted(completedWorkflow *model.Workflow) {
|
||||||
for _, c := range completedWorkflow.Children {
|
for _, c := range completedWorkflow.Children {
|
||||||
if c.Running() {
|
if c.Running() {
|
||||||
if _, err := pipeline.UpdateStepToStatusSkipped(s.store, *c, completedWorkflow.Stopped); err != nil {
|
if _, err := pipeline.UpdateStepToStatusSkipped(s.store, *c, completedWorkflow.Finished); err != nil {
|
||||||
log.Error().Err(err).Msgf("done: cannot update step_id %d child state", c.ID)
|
log.Error().Err(err).Msgf("done: cannot update step_id %d child state", c.ID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,13 +85,10 @@ func (s *WoodpeckerServer) Next(c context.Context, req *proto.NextRequest) (*pro
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *WoodpeckerServer) Init(c context.Context, req *proto.InitRequest) (*proto.Empty, error) {
|
func (s *WoodpeckerServer) Init(c context.Context, req *proto.InitRequest) (*proto.Empty, error) {
|
||||||
state := rpc.State{
|
state := rpc.WorkflowState{
|
||||||
Error: req.GetState().GetError(),
|
|
||||||
ExitCode: int(req.GetState().GetExitCode()),
|
|
||||||
Finished: req.GetState().GetFinished(),
|
|
||||||
Started: req.GetState().GetStarted(),
|
Started: req.GetState().GetStarted(),
|
||||||
StepUUID: req.GetState().GetStepUuid(),
|
Finished: req.GetState().GetFinished(),
|
||||||
Exited: req.GetState().GetExited(),
|
Error: req.GetState().GetError(),
|
||||||
}
|
}
|
||||||
res := new(proto.Empty)
|
res := new(proto.Empty)
|
||||||
err := s.peer.Init(c, req.GetId(), state)
|
err := s.peer.Init(c, req.GetId(), state)
|
||||||
|
@ -99,13 +96,13 @@ func (s *WoodpeckerServer) Init(c context.Context, req *proto.InitRequest) (*pro
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *WoodpeckerServer) Update(c context.Context, req *proto.UpdateRequest) (*proto.Empty, error) {
|
func (s *WoodpeckerServer) Update(c context.Context, req *proto.UpdateRequest) (*proto.Empty, error) {
|
||||||
state := rpc.State{
|
state := rpc.StepState{
|
||||||
|
StepUUID: req.GetState().GetStepUuid(),
|
||||||
|
Started: req.GetState().GetStarted(),
|
||||||
|
Finished: req.GetState().GetFinished(),
|
||||||
|
Exited: req.GetState().GetExited(),
|
||||||
Error: req.GetState().GetError(),
|
Error: req.GetState().GetError(),
|
||||||
ExitCode: int(req.GetState().GetExitCode()),
|
ExitCode: int(req.GetState().GetExitCode()),
|
||||||
Finished: req.GetState().GetFinished(),
|
|
||||||
Started: req.GetState().GetStarted(),
|
|
||||||
StepUUID: req.GetState().GetStepUuid(),
|
|
||||||
Exited: req.GetState().GetExited(),
|
|
||||||
}
|
}
|
||||||
res := new(proto.Empty)
|
res := new(proto.Empty)
|
||||||
err := s.peer.Update(c, req.GetId(), state)
|
err := s.peer.Update(c, req.GetId(), state)
|
||||||
|
@ -113,13 +110,10 @@ func (s *WoodpeckerServer) Update(c context.Context, req *proto.UpdateRequest) (
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *WoodpeckerServer) Done(c context.Context, req *proto.DoneRequest) (*proto.Empty, error) {
|
func (s *WoodpeckerServer) Done(c context.Context, req *proto.DoneRequest) (*proto.Empty, error) {
|
||||||
state := rpc.State{
|
state := rpc.WorkflowState{
|
||||||
Error: req.GetState().GetError(),
|
|
||||||
ExitCode: int(req.GetState().GetExitCode()),
|
|
||||||
Finished: req.GetState().GetFinished(),
|
|
||||||
Started: req.GetState().GetStarted(),
|
Started: req.GetState().GetStarted(),
|
||||||
StepUUID: req.GetState().GetStepUuid(),
|
Finished: req.GetState().GetFinished(),
|
||||||
Exited: req.GetState().GetExited(),
|
Error: req.GetState().GetError(),
|
||||||
}
|
}
|
||||||
res := new(proto.Empty)
|
res := new(proto.Empty)
|
||||||
err := s.peer.Done(c, req.GetId(), state)
|
err := s.peer.Done(c, req.GetId(), state)
|
||||||
|
|
|
@ -37,7 +37,7 @@ type Step struct {
|
||||||
Failure string `json:"-" xorm:"failure"`
|
Failure string `json:"-" xorm:"failure"`
|
||||||
ExitCode int `json:"exit_code" xorm:"exit_code"`
|
ExitCode int `json:"exit_code" xorm:"exit_code"`
|
||||||
Started int64 `json:"start_time,omitempty" xorm:"started"`
|
Started int64 `json:"start_time,omitempty" xorm:"started"`
|
||||||
Stopped int64 `json:"end_time,omitempty" xorm:"stopped"`
|
Finished int64 `json:"end_time,omitempty" xorm:"stopped"`
|
||||||
Type StepType `json:"type,omitempty" xorm:"type"`
|
Type StepType `json:"type,omitempty" xorm:"type"`
|
||||||
} // @name Step
|
} // @name Step
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ type Workflow struct {
|
||||||
State StatusValue `json:"state" xorm:"state"`
|
State StatusValue `json:"state" xorm:"state"`
|
||||||
Error string `json:"error,omitempty" xorm:"TEXT 'error'"`
|
Error string `json:"error,omitempty" xorm:"TEXT 'error'"`
|
||||||
Started int64 `json:"start_time,omitempty" xorm:"started"`
|
Started int64 `json:"start_time,omitempty" xorm:"started"`
|
||||||
Stopped int64 `json:"end_time,omitempty" xorm:"stopped"`
|
Finished int64 `json:"end_time,omitempty" xorm:"stopped"`
|
||||||
AgentID int64 `json:"agent_id,omitempty" xorm:"agent_id"`
|
AgentID int64 `json:"agent_id,omitempty" xorm:"agent_id"`
|
||||||
Platform string `json:"platform,omitempty" xorm:"platform"`
|
Platform string `json:"platform,omitempty" xorm:"platform"`
|
||||||
Environ map[string]string `json:"environ,omitempty" xorm:"json 'environ'"`
|
Environ map[string]string `json:"environ,omitempty" xorm:"json 'environ'"`
|
||||||
|
|
|
@ -24,9 +24,9 @@ import (
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/server/store"
|
"go.woodpecker-ci.org/woodpecker/v2/server/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
func UpdateStepStatus(store store.Store, step *model.Step, state rpc.State) error {
|
func UpdateStepStatus(store store.Store, step *model.Step, state rpc.StepState) error {
|
||||||
if state.Exited {
|
if state.Exited {
|
||||||
step.Stopped = state.Finished
|
step.Finished = state.Finished
|
||||||
step.ExitCode = state.ExitCode
|
step.ExitCode = state.ExitCode
|
||||||
step.Error = state.Error
|
step.Error = state.Error
|
||||||
step.State = model.StatusSuccess
|
step.State = model.StatusSuccess
|
||||||
|
@ -36,30 +36,30 @@ func UpdateStepStatus(store store.Store, step *model.Step, state rpc.State) erro
|
||||||
if state.ExitCode == pipeline.ExitCodeKilled {
|
if state.ExitCode == pipeline.ExitCodeKilled {
|
||||||
step.State = model.StatusKilled
|
step.State = model.StatusKilled
|
||||||
}
|
}
|
||||||
} else if step.Stopped == 0 {
|
} else if step.Finished == 0 {
|
||||||
step.Started = state.Started
|
step.Started = state.Started
|
||||||
step.State = model.StatusRunning
|
step.State = model.StatusRunning
|
||||||
}
|
}
|
||||||
return store.StepUpdate(step)
|
return store.StepUpdate(step)
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpdateStepToStatusStarted(store store.Store, step model.Step, state rpc.State) (*model.Step, error) {
|
func UpdateStepToStatusStarted(store store.Store, step model.Step, state rpc.StepState) (*model.Step, error) {
|
||||||
step.Started = state.Started
|
step.Started = state.Started
|
||||||
step.State = model.StatusRunning
|
step.State = model.StatusRunning
|
||||||
return &step, store.StepUpdate(&step)
|
return &step, store.StepUpdate(&step)
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpdateStepToStatusSkipped(store store.Store, step model.Step, stopped int64) (*model.Step, error) {
|
func UpdateStepToStatusSkipped(store store.Store, step model.Step, finished int64) (*model.Step, error) {
|
||||||
step.State = model.StatusSkipped
|
step.State = model.StatusSkipped
|
||||||
if step.Started != 0 {
|
if step.Started != 0 {
|
||||||
step.State = model.StatusSuccess // for daemons that are killed
|
step.State = model.StatusSuccess // for daemons that are killed
|
||||||
step.Stopped = stopped
|
step.Finished = finished
|
||||||
}
|
}
|
||||||
return &step, store.StepUpdate(&step)
|
return &step, store.StepUpdate(&step)
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpdateStepStatusToDone(store store.Store, step model.Step, state rpc.State) (*model.Step, error) {
|
func UpdateStepStatusToDone(store store.Store, step model.Step, state rpc.StepState) (*model.Step, error) {
|
||||||
step.Stopped = state.Finished
|
step.Finished = state.Finished
|
||||||
step.Error = state.Error
|
step.Error = state.Error
|
||||||
step.ExitCode = state.ExitCode
|
step.ExitCode = state.ExitCode
|
||||||
if state.Started == 0 {
|
if state.Started == 0 {
|
||||||
|
@ -75,9 +75,9 @@ func UpdateStepStatusToDone(store store.Store, step model.Step, state rpc.State)
|
||||||
|
|
||||||
func UpdateStepToStatusKilled(store store.Store, step model.Step) (*model.Step, error) {
|
func UpdateStepToStatusKilled(store store.Store, step model.Step) (*model.Step, error) {
|
||||||
step.State = model.StatusKilled
|
step.State = model.StatusKilled
|
||||||
step.Stopped = time.Now().Unix()
|
step.Finished = time.Now().Unix()
|
||||||
if step.Started == 0 {
|
if step.Started == 0 {
|
||||||
step.Started = step.Stopped
|
step.Started = step.Finished
|
||||||
}
|
}
|
||||||
step.ExitCode = pipeline.ExitCodeKilled
|
step.ExitCode = pipeline.ExitCodeKilled
|
||||||
return &step, store.StepUpdate(&step)
|
return &step, store.StepUpdate(&step)
|
||||||
|
|
|
@ -41,7 +41,7 @@ func TestUpdateStepStatusNotExited(t *testing.T) {
|
||||||
step := &model.Step{}
|
step := &model.Step{}
|
||||||
|
|
||||||
// advertised step status
|
// advertised step status
|
||||||
state := rpc.State{
|
state := rpc.StepState{
|
||||||
Started: int64(42),
|
Started: int64(42),
|
||||||
Exited: false,
|
Exited: false,
|
||||||
// Dummy data
|
// Dummy data
|
||||||
|
@ -54,7 +54,7 @@ func TestUpdateStepStatusNotExited(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, model.StatusRunning, step.State)
|
assert.EqualValues(t, model.StatusRunning, step.State)
|
||||||
assert.EqualValues(t, 42, step.Started)
|
assert.EqualValues(t, 42, step.Started)
|
||||||
assert.EqualValues(t, 0, step.Stopped)
|
assert.EqualValues(t, 0, step.Finished)
|
||||||
assert.EqualValues(t, 0, step.ExitCode)
|
assert.EqualValues(t, 0, step.ExitCode)
|
||||||
assert.EqualValues(t, "", step.Error)
|
assert.EqualValues(t, "", step.Error)
|
||||||
}
|
}
|
||||||
|
@ -63,10 +63,10 @@ func TestUpdateStepStatusNotExitedButStopped(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// step in db before update
|
// step in db before update
|
||||||
step := &model.Step{Started: 42, Stopped: 64, State: model.StatusKilled}
|
step := &model.Step{Started: 42, Finished: 64, State: model.StatusKilled}
|
||||||
|
|
||||||
// advertised step status
|
// advertised step status
|
||||||
state := rpc.State{
|
state := rpc.StepState{
|
||||||
Exited: false,
|
Exited: false,
|
||||||
// Dummy data
|
// Dummy data
|
||||||
Finished: int64(1),
|
Finished: int64(1),
|
||||||
|
@ -78,7 +78,7 @@ func TestUpdateStepStatusNotExitedButStopped(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, model.StatusKilled, step.State)
|
assert.EqualValues(t, model.StatusKilled, step.State)
|
||||||
assert.EqualValues(t, 42, step.Started)
|
assert.EqualValues(t, 42, step.Started)
|
||||||
assert.EqualValues(t, 64, step.Stopped)
|
assert.EqualValues(t, 64, step.Finished)
|
||||||
assert.EqualValues(t, 0, step.ExitCode)
|
assert.EqualValues(t, 0, step.ExitCode)
|
||||||
assert.EqualValues(t, "", step.Error)
|
assert.EqualValues(t, "", step.Error)
|
||||||
}
|
}
|
||||||
|
@ -90,7 +90,7 @@ func TestUpdateStepStatusExited(t *testing.T) {
|
||||||
step := &model.Step{Started: 42}
|
step := &model.Step{Started: 42}
|
||||||
|
|
||||||
// advertised step status
|
// advertised step status
|
||||||
state := rpc.State{
|
state := rpc.StepState{
|
||||||
Started: int64(42),
|
Started: int64(42),
|
||||||
Exited: true,
|
Exited: true,
|
||||||
Finished: int64(34),
|
Finished: int64(34),
|
||||||
|
@ -102,7 +102,7 @@ func TestUpdateStepStatusExited(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, model.StatusKilled, step.State)
|
assert.EqualValues(t, model.StatusKilled, step.State)
|
||||||
assert.EqualValues(t, 42, step.Started)
|
assert.EqualValues(t, 42, step.Started)
|
||||||
assert.EqualValues(t, 34, step.Stopped)
|
assert.EqualValues(t, 34, step.Finished)
|
||||||
assert.EqualValues(t, pipeline.ExitCodeKilled, step.ExitCode)
|
assert.EqualValues(t, pipeline.ExitCodeKilled, step.ExitCode)
|
||||||
assert.EqualValues(t, "an error", step.Error)
|
assert.EqualValues(t, "an error", step.Error)
|
||||||
}
|
}
|
||||||
|
@ -114,7 +114,7 @@ func TestUpdateStepStatusExitedButNot137(t *testing.T) {
|
||||||
step := &model.Step{Started: 42}
|
step := &model.Step{Started: 42}
|
||||||
|
|
||||||
// advertised step status
|
// advertised step status
|
||||||
state := rpc.State{
|
state := rpc.StepState{
|
||||||
Started: int64(42),
|
Started: int64(42),
|
||||||
Exited: true,
|
Exited: true,
|
||||||
Finished: int64(34),
|
Finished: int64(34),
|
||||||
|
@ -125,7 +125,7 @@ func TestUpdateStepStatusExitedButNot137(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, model.StatusFailure, step.State)
|
assert.EqualValues(t, model.StatusFailure, step.State)
|
||||||
assert.EqualValues(t, 42, step.Started)
|
assert.EqualValues(t, 42, step.Started)
|
||||||
assert.EqualValues(t, 34, step.Stopped)
|
assert.EqualValues(t, 34, step.Finished)
|
||||||
assert.EqualValues(t, 0, step.ExitCode)
|
assert.EqualValues(t, 0, step.ExitCode)
|
||||||
assert.EqualValues(t, "an error", step.Error)
|
assert.EqualValues(t, "an error", step.Error)
|
||||||
}
|
}
|
||||||
|
@ -134,7 +134,7 @@ func TestUpdateStepStatusExitedWithCode(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// advertised step status
|
// advertised step status
|
||||||
state := rpc.State{
|
state := rpc.StepState{
|
||||||
Started: int64(42),
|
Started: int64(42),
|
||||||
Exited: true,
|
Exited: true,
|
||||||
Finished: int64(34),
|
Finished: int64(34),
|
||||||
|
@ -149,10 +149,10 @@ func TestUpdateStepStatusExitedWithCode(t *testing.T) {
|
||||||
assert.Equal(t, 1, step.ExitCode)
|
assert.Equal(t, 1, step.ExitCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUpdateStepPToStatusStarted(t *testing.T) {
|
func TestUpdateStepToStatusStarted(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
state := rpc.State{Started: int64(42)}
|
state := rpc.StepState{Started: int64(42)}
|
||||||
step, _ := UpdateStepToStatusStarted(mockStoreStep(t), model.Step{}, state)
|
step, _ := UpdateStepToStatusStarted(mockStoreStep(t), model.Step{}, state)
|
||||||
|
|
||||||
assert.Equal(t, model.StatusRunning, step.State)
|
assert.Equal(t, model.StatusRunning, step.State)
|
||||||
|
@ -165,7 +165,7 @@ func TestUpdateStepToStatusSkipped(t *testing.T) {
|
||||||
step, _ := UpdateStepToStatusSkipped(mockStoreStep(t), model.Step{}, int64(1))
|
step, _ := UpdateStepToStatusSkipped(mockStoreStep(t), model.Step{}, int64(1))
|
||||||
|
|
||||||
assert.Equal(t, model.StatusSkipped, step.State)
|
assert.Equal(t, model.StatusSkipped, step.State)
|
||||||
assert.EqualValues(t, 0, step.Stopped)
|
assert.EqualValues(t, 0, step.Finished)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUpdateStepToStatusSkippedButStarted(t *testing.T) {
|
func TestUpdateStepToStatusSkippedButStarted(t *testing.T) {
|
||||||
|
@ -178,20 +178,20 @@ func TestUpdateStepToStatusSkippedButStarted(t *testing.T) {
|
||||||
step, _ = UpdateStepToStatusSkipped(mockStoreStep(t), *step, int64(1))
|
step, _ = UpdateStepToStatusSkipped(mockStoreStep(t), *step, int64(1))
|
||||||
|
|
||||||
assert.Equal(t, model.StatusSuccess, step.State)
|
assert.Equal(t, model.StatusSuccess, step.State)
|
||||||
assert.EqualValues(t, 1, step.Stopped)
|
assert.EqualValues(t, 1, step.Finished)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUpdateStepStatusToDoneSkipped(t *testing.T) {
|
func TestUpdateStepStatusToDoneSkipped(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
state := rpc.State{
|
state := rpc.StepState{
|
||||||
Finished: int64(34),
|
Finished: int64(34),
|
||||||
}
|
}
|
||||||
|
|
||||||
step, _ := UpdateStepStatusToDone(mockStoreStep(t), model.Step{}, state)
|
step, _ := UpdateStepStatusToDone(mockStoreStep(t), model.Step{}, state)
|
||||||
|
|
||||||
assert.Equal(t, model.StatusSkipped, step.State)
|
assert.Equal(t, model.StatusSkipped, step.State)
|
||||||
assert.EqualValues(t, 34, step.Stopped)
|
assert.EqualValues(t, 34, step.Finished)
|
||||||
assert.Empty(t, step.Error)
|
assert.Empty(t, step.Error)
|
||||||
assert.Equal(t, 0, step.ExitCode)
|
assert.Equal(t, 0, step.ExitCode)
|
||||||
}
|
}
|
||||||
|
@ -199,7 +199,7 @@ func TestUpdateStepStatusToDoneSkipped(t *testing.T) {
|
||||||
func TestUpdateStepStatusToDoneSuccess(t *testing.T) {
|
func TestUpdateStepStatusToDoneSuccess(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
state := rpc.State{
|
state := rpc.StepState{
|
||||||
Started: int64(42),
|
Started: int64(42),
|
||||||
Finished: int64(34),
|
Finished: int64(34),
|
||||||
}
|
}
|
||||||
|
@ -207,7 +207,7 @@ func TestUpdateStepStatusToDoneSuccess(t *testing.T) {
|
||||||
step, _ := UpdateStepStatusToDone(mockStoreStep(t), model.Step{}, state)
|
step, _ := UpdateStepStatusToDone(mockStoreStep(t), model.Step{}, state)
|
||||||
|
|
||||||
assert.Equal(t, model.StatusSuccess, step.State)
|
assert.Equal(t, model.StatusSuccess, step.State)
|
||||||
assert.EqualValues(t, 34, step.Stopped)
|
assert.EqualValues(t, 34, step.Finished)
|
||||||
assert.Empty(t, step.Error)
|
assert.Empty(t, step.Error)
|
||||||
assert.Equal(t, 0, step.ExitCode)
|
assert.Equal(t, 0, step.ExitCode)
|
||||||
}
|
}
|
||||||
|
@ -215,7 +215,7 @@ func TestUpdateStepStatusToDoneSuccess(t *testing.T) {
|
||||||
func TestUpdateStepStatusToDoneFailureWithError(t *testing.T) {
|
func TestUpdateStepStatusToDoneFailureWithError(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
state := rpc.State{Error: "an error"}
|
state := rpc.StepState{Error: "an error"}
|
||||||
|
|
||||||
step, _ := UpdateStepStatusToDone(mockStoreStep(t), model.Step{}, state)
|
step, _ := UpdateStepStatusToDone(mockStoreStep(t), model.Step{}, state)
|
||||||
|
|
||||||
|
@ -225,7 +225,7 @@ func TestUpdateStepStatusToDoneFailureWithError(t *testing.T) {
|
||||||
func TestUpdateStepStatusToDoneFailureWithExitCode(t *testing.T) {
|
func TestUpdateStepStatusToDoneFailureWithExitCode(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
state := rpc.State{ExitCode: 43}
|
state := rpc.StepState{ExitCode: 43}
|
||||||
|
|
||||||
step, _ := UpdateStepStatusToDone(mockStoreStep(t), model.Step{}, state)
|
step, _ := UpdateStepStatusToDone(mockStoreStep(t), model.Step{}, state)
|
||||||
|
|
||||||
|
@ -240,8 +240,8 @@ func TestUpdateStepToStatusKilledStarted(t *testing.T) {
|
||||||
step, _ := UpdateStepToStatusKilled(mockStoreStep(t), model.Step{})
|
step, _ := UpdateStepToStatusKilled(mockStoreStep(t), model.Step{})
|
||||||
|
|
||||||
assert.Equal(t, model.StatusKilled, step.State)
|
assert.Equal(t, model.StatusKilled, step.State)
|
||||||
assert.LessOrEqual(t, now, step.Stopped)
|
assert.LessOrEqual(t, now, step.Finished)
|
||||||
assert.Equal(t, step.Stopped, step.Started)
|
assert.Equal(t, step.Finished, step.Started)
|
||||||
assert.Equal(t, 137, step.ExitCode)
|
assert.Equal(t, 137, step.ExitCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ import (
|
||||||
"go.woodpecker-ci.org/woodpecker/v2/server/store"
|
"go.woodpecker-ci.org/woodpecker/v2/server/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
func UpdateWorkflowToStatusStarted(store store.Store, workflow model.Workflow, state rpc.State) (*model.Workflow, error) {
|
func UpdateWorkflowStatusToRunning(store store.Store, workflow model.Workflow, state rpc.WorkflowState) (*model.Workflow, error) {
|
||||||
workflow.Started = state.Started
|
workflow.Started = state.Started
|
||||||
workflow.State = model.StatusRunning
|
workflow.State = model.StatusRunning
|
||||||
return &workflow, store.WorkflowUpdate(&workflow)
|
return &workflow, store.WorkflowUpdate(&workflow)
|
||||||
|
@ -31,8 +31,8 @@ func UpdateWorkflowToStatusSkipped(store store.Store, workflow model.Workflow) (
|
||||||
return &workflow, store.WorkflowUpdate(&workflow)
|
return &workflow, store.WorkflowUpdate(&workflow)
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpdateWorkflowStatusToDone(store store.Store, workflow model.Workflow, state rpc.State) (*model.Workflow, error) {
|
func UpdateWorkflowStatusToDone(store store.Store, workflow model.Workflow, state rpc.WorkflowState) (*model.Workflow, error) {
|
||||||
workflow.Stopped = state.Finished
|
workflow.Finished = state.Finished
|
||||||
workflow.Error = state.Error
|
workflow.Error = state.Error
|
||||||
if state.Started == 0 {
|
if state.Started == 0 {
|
||||||
workflow.State = model.StatusSkipped
|
workflow.State = model.StatusSkipped
|
Loading…
Reference in a new issue