pipeline runtime: move setting step environment variables into own func and add CI_PIPELINE_STATUS back (#6516)

This commit is contained in:
6543
2026-05-01 15:40:52 +02:00
committed by GitHub
parent 63fccbed96
commit 7cef7a8a15
4 changed files with 41 additions and 31 deletions

View File

@@ -82,6 +82,7 @@ This is the reference list of all environment variables available to your pipeli
| | **Current pipeline** | |
| `CI_PIPELINE_NUMBER` | pipeline number | `8` |
| `CI_PIPELINE_PARENT` | number of parent pipeline | `0` |
| `CI_PIPELINE_STATUS` | state of the workflow right before the step was started | `success`, `failure` |
| `CI_PIPELINE_EVENT` | pipeline event (see [`event`](../20-usage/20-workflow-syntax.md#event)) | `push`, `pull_request`, `pull_request_closed`, `pull_request_metadata`, `tag`, `release`, `manual`, `cron` |
| `CI_PIPELINE_EVENT_REASON` | exact reason why `pull_request_metadata` event was send. it is forge instance specific and can change | `label_updated`, `milestoned`, `demilestoned`, `assigned`, `edited`, ... |
| `CI_PIPELINE_URL` | link to the web UI for the pipeline | `https://ci.example.com/repos/7/pipeline/8` |

View File

@@ -43,9 +43,8 @@ type Runtime struct {
// Cleanup operations should use the runnerCtx passed to Run().
ctx context.Context
tracer tracing.Tracer
tracerLock sync.Mutex
logger logging.Logger
tracer tracing.Tracer
logger logging.Logger
uploadWait sync.WaitGroup
@@ -63,7 +62,6 @@ func New(spec *backend_types.Config, backend backend_types.Backend, opts ...Opti
r.ctx = context.Background()
r.taskUUID = ulid.Make().String()
r.tracer = tracing.NoOpTracer
r.tracerLock = sync.Mutex{}
for _, opt := range opts {
opt(r)
}

View File

@@ -271,18 +271,20 @@ func TestWorkflowWithServiceStep(t *testing.T) {
assert.Greater(t, testExit.Workflow.Started, int64(0))
// Strip runtime-injected env for a structural comparison of the step itself.
delete(testExit.CurrStep.Environment, "CI_PIPELINE_STARTED")
delete(testExit.CurrStep.Environment, "CI_STEP_STARTED")
delete(testExit.CurrStep.Environment, dummy.EnvKeyStepSleep)
assert.EqualValues(t, state.State{
Workflow: state.Workflow{Started: testExit.Workflow.Started},
CurrStep: &backend_types.Step{
Name: "test",
UUID: "test-uuid",
Type: "commands",
OnSuccess: true,
Environment: map[string]string{},
Commands: []string{"echo test"},
Name: "test",
UUID: "test-uuid",
Type: "commands",
OnSuccess: true,
Environment: map[string]string{
"CI_PIPELINE_STARTED": fmt.Sprintf("%d", r.started),
"CI_PIPELINE_STATUS": "success",
},
Commands: []string{"echo test"},
},
CurrStepState: backend_types.State{
Started: testExit.CurrStepState.Started,
@@ -478,6 +480,7 @@ func TestWorkflowPluginStep(t *testing.T) {
delete(lastPluginTrace.CurrStep.Environment, "CI_STEP_STARTED")
assert.EqualValues(t, map[string]string{
"CI_PIPELINE_STATUS": "success",
"DRONE_BUILD_STATUS": "success",
"DRONE_REPO_SCM": "git",
"EXPECT_TYPE": "plugin",

View File

@@ -17,6 +17,7 @@ package runtime
import (
"context"
"errors"
"fmt"
"strconv"
"sync"
"time"
@@ -45,9 +46,9 @@ func (r *Runtime) executeStep(runnerCtx context.Context, step *backend_types.Ste
return err
}
// Add compatibility environment variables for drone-ci plugins.
if step.Type == backend_types.StepTypePlugin {
metadata.SetDroneEnviron(step.Environment)
// Set runtime specific step environment
if err := r.setStepEnv(step); err != nil {
return err
}
logger.Debug().Str("step", step.Name).Msg("executing")
@@ -83,6 +84,29 @@ func (r *Runtime) shouldSkipStep(step *backend_types.Step) bool {
return false
}
// setStepEnv sets runtime specific step environment variables.
// It also adds the drone plugin compatibility layer.
func (r *Runtime) setStepEnv(step *backend_types.Step) error {
if step.Environment == nil {
return fmt.Errorf("step %q (%q) has no environment variables initialized", step.Name, step.UUID)
}
// Add compatibility environment variables for drone-ci plugins.
if step.Type == backend_types.StepTypePlugin {
metadata.SetDroneEnviron(step.Environment)
}
if r.err.Get() != nil {
step.Environment["CI_PIPELINE_STATUS"] = "failure"
} else {
step.Environment["CI_PIPELINE_STATUS"] = "success"
}
step.Environment["CI_PIPELINE_STARTED"] = strconv.FormatInt(r.started, 10)
step.Environment["CI_STEP_STARTED"] = strconv.FormatInt(time.Now().Unix(), 10)
return nil
}
// startStep starts the step container and spawns a goroutine to stream its logs.
// It returns:
// - waitForLogs: must be called before WaitStep — it blocks until the log stream
@@ -220,7 +244,7 @@ func (r *Runtime) runDetachedStep(runnerCtx context.Context, step *backend_types
err = pipeline_errors.ErrCancel
}
if err != nil {
logger.Error().Err(err).Str("step", step.Name).Msg("detached step failed after while running")
logger.Error().Err(err).Str("step", step.Name).Msg("detached step failed while running")
}
if traceErr := r.traceStep(processState, err, step); traceErr != nil {
@@ -257,22 +281,6 @@ func (r *Runtime) traceStep(processState *backend_types.State, err error, step *
// processState == nil && err == nil: step just started, leave s.CurrStepState zero-valued.
}
// The traceStep should just trace changes, but it currently also updates step env vars.
{
r.tracerLock.Lock()
defer r.tracerLock.Unlock()
if s.CurrStepState.Exited {
if s.CurrStep.Environment == nil {
s.CurrStep.Environment = map[string]string{}
}
// TODO: find better way to insert runtime step environment variables.
s.CurrStep.Environment["CI_PIPELINE_STARTED"] = strconv.FormatInt(s.Workflow.Started, 10)
s.CurrStep.Environment["CI_STEP_STARTED"] = strconv.FormatInt(s.Workflow.Started, 10)
}
}
if traceErr := r.tracer.Trace(s); traceErr != nil {
logger := r.makeLogger()
logger.Error().Err(traceErr).Msg("could not trace step state change")