| |
| |
| |
| |
| @@ -656,11 +656,8 @@ func (b *Build) executeStage(ctx context.Context, buildStage BuildStage, executo |
| // rather than the returned error because gRPC wraps deadline |
| // exceeded as a status error that does not unwrap to |
| // context.DeadlineExceeded. |
| - if err != nil && errors.Is(ctx.Err(), context.DeadlineExceeded) { |
| - b.logger.Warningln( |
| - string(buildStage) + " could not run to completion because the timeout was exceeded. " + |
| - "For more control over job and script timeouts see: " + |
| - "https://docs.gitlab.com/ci/runners/configure_runners/#set-script-and-after_script-timeouts") |
| + if err != nil { |
| + b.warnTimeoutExceeded(ctx, string(buildStage)) |
| } |
| return err |
| } |
| @@ -676,14 +673,7 @@ func (b *Build) executeStage(ctx context.Context, buildStage BuildStage, executo |
| b.setCurrentStage(buildStage) |
| b.Log().WithField("build_stage", buildStage).Debug("Executing build stage") |
| |
| - defer func() { |
| - if errors.Is(ctx.Err(), context.DeadlineExceeded) { |
| - b.logger.Warningln( |
| - string(buildStage) + " could not run to completion because the timeout was exceeded. " + |
| - "For more control over job and script timeouts see: " + |
| - "https://docs.gitlab.com/ci/runners/configure_runners/#set-script-and-after_script-timeouts") |
| - } |
| - }() |
| + defer b.warnTimeoutExceeded(ctx, string(buildStage)) |
| |
| shell := executor.Shell() |
| if shell == nil { |
| @@ -828,6 +818,12 @@ func (b *Build) executeScript(ctx context.Context, trace JobTrace, executor Exec |
| //nolint:errcheck |
| err = b.executeStepStage(ctx, executor.(steps.Connector), "concrete", concreteSteps, trace.SetCancelFunc) |
| |
| + // Whole-job dispatch: stage breakdown isn't visible to the user, so |
| + // attribute the timeout to "Job" rather than a build stage. |
| + if err != nil { |
| + b.warnTimeoutExceeded(ctx, "Job") |
| + } |
| + |
| b.executeUploadReferees(ctx, startTime, time.Now()) |
| |
| return err |
| @@ -1092,6 +1088,16 @@ func (b *Build) attemptExecuteStage( |
| return err |
| } |
| |
| +func (b *Build) warnTimeoutExceeded(ctx context.Context, subject string) { |
| + if !errors.Is(ctx.Err(), context.DeadlineExceeded) { |
| + return |
| + } |
| + b.logger.Warningln( |
| + subject + " could not run to completion because the timeout was exceeded. " + |
| + "For more control over job and script timeouts see: " + |
| + "https://docs.gitlab.com/ci/runners/configure_runners/#set-script-and-after_script-timeouts") |
| +} |
| + |
| func (b *Build) GetBuildTimeout() time.Duration { |
| buildTimeout := b.RunnerInfo.Timeout |
| if buildTimeout <= 0 { |
| |
| |
| |
| |
| @@ -353,7 +353,6 @@ func (b *builder) buildSteps() []stages.Step { |
| }) |
| |
| if step.Name == spec.StepNameAfterScript { |
| - s.AllowFailure = true |
| s.OnSuccess = true |
| s.OnFailure = true |
| afterScript = append(afterScript, s) |
| |
| |
| |
| |
| @@ -224,17 +224,21 @@ func (r *Runner) runScriptSteps(jobCtx context.Context, steps []stages.Step) err |
| r.setCancel(cancel) |
| |
| var firstErr error |
| + timeoutStage := "step_script" |
| for _, step := range steps { |
| r.loadGitlabEnv() |
| |
| - if err := r.section(scriptCtx, "step_"+step.Step, step.Run); err != nil { |
| + sectionName := "step_" + step.Step |
| + if err := r.section(scriptCtx, sectionName, step.Run); err != nil { |
| if firstErr == nil { |
| firstErr = err |
| } |
| + timeoutStage = sectionName |
| break |
| } |
| } |
| |
| + r.warnStageTimeout(jobCtx, scriptCtx, timeoutStage) |
| return r.classifyScriptContextError(jobCtx, scriptCtx, firstErr) |
| } |
| |
| @@ -277,6 +281,7 @@ func (r *Runner) runAfterScriptSteps(jobCtx context.Context, steps []stages.Step |
| return nil |
| }) |
| |
| + r.warnStageTimeout(jobCtx, afterCtx, "after_script") |
| return err |
| } |
| |
| @@ -386,6 +391,21 @@ func (r *Runner) logWarningf(format string, args ...interface{}) { |
| fmt.Fprintf(r.env.Stderr, " %s\033[0m\n", msg) |
| } |
| |
| +// warnStageTimeout fires only on a stage-only deadline; the job-level |
| +// case is owned by the outer runner. |
| +func (r *Runner) warnStageTimeout(jobCtx, stageCtx context.Context, stageName string) { |
| + if !errors.Is(stageCtx.Err(), context.DeadlineExceeded) { |
| + return |
| + } |
| + if errors.Is(jobCtx.Err(), context.DeadlineExceeded) { |
| + return |
| + } |
| + r.logWarningf("%s could not run to completion because the timeout was exceeded. "+ |
| + "For more control over job and script timeouts see: "+ |
| + "https://docs.gitlab.com/ci/runners/configure_runners/#set-script-and-after_script-timeouts", |
| + stageName) |
| +} |
| + |
| // setupGitlabEnv creates the GITLAB_ENV file so user scripts can append |
| // KEY=VALUE lines to define dynamic variables for subsequent steps. |
| func (r *Runner) setupGitlabEnv() error { |
|
|