Renamed procs/jobs to steps in code (#1331)

Renamed `procs` to `steps` in code for the issue #1288

Co-authored-by: Harikesh Prajapati <harikesh.prajapati@druva.com>
Co-authored-by: qwerty287 <ndev@web.de>
Co-authored-by: qwerty287 <80460567+qwerty287@users.noreply.github.com>
Co-authored-by: 6543 <6543@obermui.de>
This commit is contained in:
Harikesh00 2022-10-28 21:08:53 +05:30 committed by GitHub
parent b44e895017
commit 36e42914fa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
109 changed files with 1474 additions and 1364 deletions

View file

@ -23,7 +23,7 @@ tasks:
env:
WOODPECKER_SERVER: localhost:9000
WOODPECKER_SECRET: "1234"
WOODPECKER_MAX_PROCS: 1
WOODPECKER_MAX_WORKFLOWS: 1
WOODPECKER_HEALTHCHECK: false
command: |
gp sync-await woodpecker-server

View file

@ -67,7 +67,7 @@ func (r *Runner) Run(ctx context.Context) error {
meta, _ := metadata.FromOutgoingContext(ctx)
ctxmeta := metadata.NewOutgoingContext(context.Background(), meta)
// get the next job from the queue
// get the next workflow from the queue
work, err := r.client.Next(ctx, r.filter)
if err != nil {
return err
@ -150,10 +150,10 @@ func (r *Runner) Run(ctx context.Context) error {
}
var uploads sync.WaitGroup
defaultLogger := pipeline.LogFunc(func(proc *backend.Step, rc multipart.Reader) error {
defaultLogger := pipeline.LogFunc(func(step *backend.Step, rc multipart.Reader) error {
loglogger := logger.With().
Str("image", proc.Image).
Str("stage", proc.Alias).
Str("image", step.Image).
Str("stage", step.Alias).
Logger()
part, rerr := rc.NextPart()
@ -172,7 +172,7 @@ func (r *Runner) Run(ctx context.Context) error {
loglogger.Debug().Msg("log stream opened")
limitedPart := io.LimitReader(part, maxLogsUpload)
logStream := rpc.NewLineWriter(r.client, work.ID, proc.Alias, secrets...)
logStream := rpc.NewLineWriter(r.client, work.ID, step.Alias, secrets...)
if _, err := io.Copy(logStream, limitedPart); err != nil {
log.Error().Err(err).Msg("copy limited logStream part")
}
@ -186,7 +186,7 @@ func (r *Runner) Run(ctx context.Context) error {
file := &rpc.File{
Mime: "application/json+logs",
Proc: proc.Alias,
Step: step.Alias,
Name: "logs.json",
Data: data,
Size: len(data),
@ -218,7 +218,7 @@ func (r *Runner) Run(ctx context.Context) error {
file = &rpc.File{
Mime: part.Header().Get("Content-Type"),
Proc: proc.Alias,
Step: step.Alias,
Name: part.FileName(),
Data: data,
Size: len(data),
@ -250,7 +250,7 @@ func (r *Runner) Run(ctx context.Context) error {
})
defaultTracer := pipeline.TraceFunc(func(state *pipeline.State) error {
proclogger := logger.With().
steplogger := logger.With().
Str("image", state.Pipeline.Step.Image).
Str("stage", state.Pipeline.Step.Alias).
Err(state.Process.Error).
@ -258,27 +258,27 @@ func (r *Runner) Run(ctx context.Context) error {
Bool("exited", state.Process.Exited).
Logger()
procState := rpc.State{
Proc: state.Pipeline.Step.Alias,
stepState := rpc.State{
Step: state.Pipeline.Step.Alias,
Exited: state.Process.Exited,
ExitCode: state.Process.ExitCode,
Started: time.Now().Unix(), // TODO do not do this
Finished: time.Now().Unix(),
}
if state.Process.Error != nil {
procState.Error = state.Process.Error.Error()
stepState.Error = state.Process.Error.Error()
}
defer func() {
proclogger.Debug().Msg("update step status")
steplogger.Debug().Msg("update step status")
if uerr := r.client.Update(ctxmeta, work.ID, procState); uerr != nil {
proclogger.Debug().
if uerr := r.client.Update(ctxmeta, work.ID, stepState); uerr != nil {
steplogger.Debug().
Err(uerr).
Msg("update step status error")
}
proclogger.Debug().Msg("update step status complete")
steplogger.Debug().Msg("update step status complete")
}()
if state.Process.Exited {
return nil
@ -289,22 +289,29 @@ func (r *Runner) Run(ctx context.Context) error {
// TODO: find better way to update this state and move it to pipeline to have the same env in cli-exec
state.Pipeline.Step.Environment["CI_MACHINE"] = r.hostname
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_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
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_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
state.Pipeline.Step.Environment["CI_SYSTEM_ARCH"] = runtime.GOOS + "/" + runtime.GOARCH
// DEPRECATED
state.Pipeline.Step.Environment["CI_BUILD_STATUS"] = "success"
state.Pipeline.Step.Environment["CI_BUILD_STARTED"] = strconv.FormatInt(state.Pipeline.Time, 10)
state.Pipeline.Step.Environment["CI_BUILD_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
state.Pipeline.Step.Environment["CI_JOB_STATUS"] = "success"
state.Pipeline.Step.Environment["CI_JOB_STARTED"] = strconv.FormatInt(state.Pipeline.Time, 10)
state.Pipeline.Step.Environment["CI_JOB_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
state.Pipeline.Step.Environment["CI_SYSTEM_ARCH"] = runtime.GOOS + "/" + runtime.GOARCH
if state.Pipeline.Error != nil {
state.Pipeline.Step.Environment["CI_PIPELINE_STATUS"] = "failure"
state.Pipeline.Step.Environment["CI_STEP_STATUS"] = "failure"
// DEPRECATED
state.Pipeline.Step.Environment["CI_BUILD_STATUS"] = "failure"
state.Pipeline.Step.Environment["CI_JOB_STATUS"] = "failure"

View file

@ -53,7 +53,7 @@ var Command = &cli.Command{
&cli.StringSliceFlag{
Name: "param",
Aliases: []string{"p"},
Usage: "custom parameters to be injected into the job environment. Format: KEY=value",
Usage: "custom parameters to be injected into the step environment. Format: KEY=value",
},
),
}

View file

@ -112,7 +112,7 @@ func execWithAxis(c *cli.Context, file, repoPath string, axis matrix.Axis) error
metadata := metadataFromContext(c, axis)
environ := metadata.Environ()
var secrets []compiler.Secret
for key, val := range metadata.Job.Matrix {
for key, val := range metadata.Step.Matrix {
environ[key] = val
secrets = append(secrets, compiler.Secret{
Name: key,
@ -289,8 +289,8 @@ func metadataFromContext(c *cli.Context, axis matrix.Axis) frontend.Metadata {
},
},
},
Job: frontend.Job{
Number: c.Int("job-number"),
Step: frontend.Step{
Number: c.Int("step-number"),
Matrix: axis,
},
Sys: frontend.System{
@ -312,13 +312,13 @@ func convertPathForWindows(path string) string {
return filepath.ToSlash(path)
}
var defaultLogger = pipeline.LogFunc(func(proc *backendTypes.Step, rc multipart.Reader) error {
var defaultLogger = pipeline.LogFunc(func(step *backendTypes.Step, rc multipart.Reader) error {
part, err := rc.NextPart()
if err != nil {
return err
}
logStream := NewLineWriter(proc.Alias)
logStream := NewLineWriter(step.Alias)
_, err = io.Copy(logStream, part)
return err
})

View file

@ -260,8 +260,8 @@ var flags = []cli.Flag{
Name: "prev-commit-author-email",
},
&cli.IntFlag{
EnvVars: []string{"CI_JOB_NUMBER"},
Name: "job-number",
EnvVars: []string{"CI_STEP_NUMBER", "CI_JOB_NUMBER"},
Name: "step-number",
},
&cli.StringSliceFlag{
EnvVars: []string{"CI_ENV"},

View file

@ -32,7 +32,7 @@ const (
// Line is a line of console output.
type Line struct {
Proc string `json:"proc,omitempty"`
Step string `json:"step,omitempty"`
Time int64 `json:"time,omitempty"`
Type int `json:"type,omitempty"`
Pos int `json:"pos,omitempty"`
@ -66,7 +66,7 @@ func (w *LineWriter) Write(p []byte) (n int, err error) {
line := &Line{
Out: out,
Proc: w.name,
Step: w.name,
Pos: w.num,
Time: int64(time.Since(w.now).Seconds()),
Type: LineStdout,

View file

@ -27,7 +27,7 @@ import (
var pipelineLogsCmd = &cli.Command{
Name: "logs",
Usage: "show pipeline logs",
ArgsUsage: "<repo/name> [pipeline] [job]",
ArgsUsage: "<repo/name> [pipeline] [step]",
Action: pipelineLogs,
Flags: common.GlobalFlags,
}
@ -44,7 +44,7 @@ func pipelineLogs(c *cli.Context) error {
return err
}
job, err := strconv.Atoi(c.Args().Get(2))
step, err := strconv.Atoi(c.Args().Get(2))
if err != nil {
return err
}
@ -54,7 +54,7 @@ func pipelineLogs(c *cli.Context) error {
return err
}
logs, err := client.PipelineLogs(owner, name, number, job)
logs, err := client.PipelineLogs(owner, name, number, step)
if err != nil {
return err
}

View file

@ -76,8 +76,8 @@ func pipelinePs(c *cli.Context) error {
return err
}
for _, proc := range pipeline.Procs {
for _, child := range proc.Children {
for _, step := range pipeline.Steps {
for _, child := range step.Children {
if err := tmpl.Execute(os.Stdout, child); err != nil {
return err
}
@ -88,7 +88,7 @@ func pipelinePs(c *cli.Context) error {
}
// template for pipeline ps information
var tmplPipelinePs = "\x1b[33mProc #{{ .PID }} \x1b[0m" + `
var tmplPipelinePs = "\x1b[33mStep #{{ .PID }} \x1b[0m" + `
Step: {{ .Name }}
State: {{ .State }}
`

View file

@ -34,7 +34,7 @@ var pipelineStartCmd = &cli.Command{
&cli.StringSliceFlag{
Name: "param",
Aliases: []string{"p"},
Usage: "custom parameters to be injected into the job environment. Format: KEY=value",
Usage: "custom parameters to be injected into the step environment. Format: KEY=value",
},
),
}
@ -62,7 +62,7 @@ func pipelineStart(c *cli.Context) (err error) {
number = pipeline.Number
} else {
if len(pipelineArg) == 0 {
return errors.New("missing job number")
return errors.New("missing step number")
}
number, err = strconv.Atoi(pipelineArg)
if err != nil {

View file

@ -27,7 +27,7 @@ import (
var pipelineStopCmd = &cli.Command{
Name: "stop",
Usage: "stop a pipeline",
ArgsUsage: "<repo/name> [pipeline] [job]",
ArgsUsage: "<repo/name> [pipeline] [step]",
Flags: common.GlobalFlags,
Action: pipelineStop,
}
@ -42,9 +42,9 @@ func pipelineStop(c *cli.Context) (err error) {
if err != nil {
return err
}
job, _ := strconv.Atoi(c.Args().Get(2))
if job == 0 {
job = 1
step, _ := strconv.Atoi(c.Args().Get(2))
if step == 0 {
step = 1
}
client, err := internal.NewClient(c)
@ -52,11 +52,11 @@ func pipelineStop(c *cli.Context) (err error) {
return err
}
err = client.PipelineStop(owner, name, number, job)
err = client.PipelineStop(owner, name, number, step)
if err != nil {
return err
}
fmt.Printf("Stopping pipeline %s/%s#%d.%d\n", owner, name, number, job)
fmt.Printf("Stopping pipeline %s/%s#%d.%d\n", owner, name, number, step)
return nil
}

View file

@ -85,7 +85,7 @@ func loop(c *cli.Context) error {
log.Logger = log.With().Caller().Logger()
}
counter.Polling = c.Int("max-procs")
counter.Polling = c.Int("max-workflows")
counter.Running = 0
if c.Bool("healthcheck") {
@ -139,7 +139,7 @@ func loop(c *cli.Context) error {
backend.Init(context.WithValue(ctx, types.CliContext, c))
var wg sync.WaitGroup
parallel := c.Int("max-procs")
parallel := c.Int("max-workflows")
wg.Add(parallel)
// new engine
@ -169,7 +169,7 @@ func loop(c *cli.Context) error {
return
}
log.Debug().Msg("polling new jobs")
log.Debug().Msg("polling new steps")
if err := r.Run(ctx); err != nil {
log.Error().Err(err).Msg("pipeline done with error")
return

View file

@ -79,8 +79,8 @@ var flags = []cli.Flag{
Usage: "List of labels to filter tasks on. An agent must be assigned every tag listed in a task to be selected.",
},
&cli.IntFlag{
EnvVars: []string{"WOODPECKER_MAX_PROCS"},
Name: "max-procs",
EnvVars: []string{"WOODPECKER_MAX_WORKFLOWS", "WOODPECKER_MAX_PROCS"},
Name: "max-workflows",
Usage: "agent parallel workflows",
Value: 1,
},

View file

@ -304,20 +304,20 @@ func setupCoding(c *cli.Context) (remote.Remote, error) {
}
func setupMetrics(g *errgroup.Group, _store store.Store) {
pendingJobs := promauto.NewGauge(prometheus.GaugeOpts{
pendingSteps := promauto.NewGauge(prometheus.GaugeOpts{
Namespace: "woodpecker",
Name: "pending_jobs",
Help: "Total number of pending pipeline processes.",
Name: "pending_steps",
Help: "Total number of pending pipeline steps.",
})
waitingJobs := promauto.NewGauge(prometheus.GaugeOpts{
waitingSteps := promauto.NewGauge(prometheus.GaugeOpts{
Namespace: "woodpecker",
Name: "waiting_jobs",
Name: "waiting_steps",
Help: "Total number of pipeline waiting on deps.",
})
runningJobs := promauto.NewGauge(prometheus.GaugeOpts{
runningSteps := promauto.NewGauge(prometheus.GaugeOpts{
Namespace: "woodpecker",
Name: "running_jobs",
Help: "Total number of running pipeline processes.",
Name: "running_steps",
Help: "Total number of running pipeline steps.",
})
workers := promauto.NewGauge(prometheus.GaugeOpts{
Namespace: "woodpecker",
@ -343,9 +343,9 @@ func setupMetrics(g *errgroup.Group, _store store.Store) {
g.Go(func() error {
for {
stats := server.Config.Services.Queue.Info(context.TODO())
pendingJobs.Set(float64(stats.Stats.Pending))
waitingJobs.Set(float64(stats.Stats.WaitingOnDeps))
runningJobs.Set(float64(stats.Stats.Running))
pendingSteps.Set(float64(stats.Stats.Pending))
waitingSteps.Set(float64(stats.Stats.WaitingOnDeps))
runningSteps.Set(float64(stats.Stats.Running))
workers.Set(float64(stats.Stats.Workers))
time.Sleep(500 * time.Millisecond)
}

View file

@ -28,4 +28,4 @@ services:
environment:
- WOODPECKER_SERVER=woodpecker-server:9000
- WOODPECKER_AGENT_SECRET=${WOODPECKER_AGENT_SECRET}
- WOODPECKER_MAX_PROCS=2
- WOODPECKER_MAX_WORKFLOWS=2

View file

@ -75,7 +75,7 @@ This is the reference list of all environment variables available to your pipeli
| `CI_COMMIT_AUTHOR_AVATAR` | commit author avatar |
| | **Current pipeline** |
| `CI_PIPELINE_NUMBER` | pipeline number |
| `CI_PIPELINE_PARENT` | number of parent pipeline |
| `CI_PIPELINE_PARENT` | number of parent pipeline |
| `CI_PIPELINE_EVENT` | pipeline event (push, pull_request, tag, deployment) |
| `CI_PIPELINE_LINK` | pipeline link in CI |
| `CI_PIPELINE_DEPLOY_TARGET` | pipeline deploy target for `deployment` events (ie production) |
@ -83,11 +83,11 @@ This is the reference list of all environment variables available to your pipeli
| `CI_PIPELINE_CREATED` | pipeline created UNIX timestamp |
| `CI_PIPELINE_STARTED` | pipeline started UNIX timestamp |
| `CI_PIPELINE_FINISHED` | pipeline finished UNIX timestamp |
| | **Current job** |
| `CI_JOB_NUMBER` | job number |
| `CI_JOB_STATUS` | job status (success, failure) |
| `CI_JOB_STARTED` | job started UNIX timestamp |
| `CI_JOB_FINISHED` | job finished UNIX timestamp |
| | **Current step** |
| `CI_STEP_NUMBER` | step number |
| `CI_STEP_STATUS` | step status (success, failure) |
| `CI_STEP_STARTED` | step started UNIX timestamp |
| `CI_STEP_FINISHED` | step finished UNIX timestamp |
| | **Previous commit** |
| `CI_PREV_COMMIT_SHA` | previous commit SHA |
| `CI_PREV_COMMIT_REF` | previous commit ref |

View file

@ -9,7 +9,7 @@ A Woodpecker deployment consists of two parts:
>
> If you have 4 agents installed and connected to the Woodpecker server, your system will process 4 builds in parallel.
>
> You can add more agents to increase the number of parallel builds or set the agent's `WOODPECKER_MAX_PROCS=1` environment variable to increase the number of parallel builds for that agent.
> You can add more agents to increase the number of parallel steps or set the agent's `WOODPECKER_MAX_WORKFLOWS=1` environment variable to increase the number of parallel workflows for that agent.
## Installation

View file

@ -17,11 +17,11 @@ services:
The following are automatically set and can be overridden:
- WOODPECKER_HOSTNAME if not set, becomes the OS' hostname
- WOODPECKER_MAX_PROCS if not set, defaults to 1
- WOODPECKER_MAX_WORKFLOWS if not set, defaults to 1
## Processes per agent
By default the maximum processes that are run per agent is 1. If required you can add `WOODPECKER_MAX_PROCS` to increase your parallel processing on a per-agent basis.
By default the maximum processes that are run per agent is 1. If required you can add `WOODPECKER_MAX_WORKFLOWS` to increase your parallel processing on a per-agent basis.
```yaml
# docker-compose.yml
@ -33,7 +33,7 @@ services:
environment:
- WOODPECKER_SERVER=localhost:9000
- WOODPECKER_AGENT_SECRET="your-shared-secret-goes-here"
+ - WOODPECKER_MAX_PROCS=4
+ - WOODPECKER_MAX_WORKFLOWS=4
```
## All agent configuration options
@ -80,10 +80,10 @@ Disable colored debug output.
Configures the agent hostname.
### `WOODPECKER_MAX_PROCS`
### `WOODPECKER_MAX_WORKFLOWS`
> Default: `1`
Configures the number of parallel builds.
Configures the number of parallel workflows.
### `WOODPECKER_FILTER_LABELS`
> Default: empty

View file

@ -35,7 +35,7 @@ scrape_configs:
List of Prometheus metrics specific to Woodpecker:
```
# HELP woodpecker_pipeline_count Build count.
# HELP woodpecker_pipeline_count Pipeline count.
# TYPE woodpecker_pipeline_count counter
woodpecker_build_count{branch="master",pipeline="total",repo="woodpecker-ci/woodpecker",status="success"} 3
woodpecker_build_count{branch="mkdocs",pipeline="total",repo="woodpecker-ci/woodpecker",status="success"} 3
@ -46,21 +46,21 @@ woodpecker_build_time{branch="mkdocs",pipeline="total",repo="woodpecker-ci/woodp
# HELP woodpecker_pipeline_total_count Total number of builds.
# TYPE woodpecker_pipeline_total_count gauge
woodpecker_build_total_count 1025
# HELP woodpecker_pending_jobs Total number of pending build processes.
# TYPE woodpecker_pending_jobs gauge
woodpecker_pending_jobs 0
# HELP woodpecker_pending_steps Total number of pending pipeline steps.
# TYPE woodpecker_pending_steps gauge
woodpecker_pending_steps 0
# HELP woodpecker_repo_count Total number of repos.
# TYPE woodpecker_repo_count gauge
woodpecker_repo_count 9
# HELP woodpecker_running_jobs Total number of running build processes.
# TYPE woodpecker_running_jobs gauge
woodpecker_running_jobs 0
# HELP woodpecker_running_steps Total number of running pipeline steps.
# TYPE woodpecker_running_steps gauge
woodpecker_running_steps 0
# HELP woodpecker_user_count Total number of users.
# TYPE woodpecker_user_count gauge
woodpecker_user_count 1
# HELP woodpecker_waiting_jobs Total number of builds waiting on deps.
# TYPE woodpecker_waiting_jobs gauge
woodpecker_waiting_jobs 0
# HELP woodpecker_waiting_steps Total number of pipeline waiting on deps.
# TYPE woodpecker_waiting_steps gauge
woodpecker_waiting_steps 0
# HELP woodpecker_worker_count Total number of workers.
# TYPE woodpecker_worker_count gauge
woodpecker_worker_count 4

View file

@ -8,8 +8,11 @@ Some versions need some changes to the server configuration or the pipeline conf
- Refactored support of old agent filter labels and expression. Learn how to use the new [filter](./20-usage/20-pipeline-syntax.md#labels)
- Renamed step environment variable `CI_SYSTEM_ARCH` to `CI_SYSTEM_PLATFORM`. Same applies for the cli exec variable.
- Renamed environment variables `CI_BUILD_*` and `CI_PREV_BUILD_*` to `CI_PIPELINE_*` and `CI_PREV_PIPELINE_*`, old ones are still available but deprecated
- Renamed environment variables `CI_JOB_*` to `CI_STEP_*`, old ones are still available but deprecated
- Renamed API endpoints for pipelines (`<owner>/<repo>/builds/<buildId>` -> `<owner>/<repo>/pipelines/<pipelineId>`), old ones are still available but deprecated
- Updated Prometheus gauge `build_*` to `pipeline_*`
- Updated Prometheus gauge `*_job_*` to `*_step_*`
- Renamed config env `WOODPECKER_MAX_PROCS` to `WOODPECKER_MAX_WORKFLOWS` (still available as fallback)
## 0.15.0

View file

@ -22,7 +22,7 @@ If you have some missing resources, please feel free to [open a pull-request](ht
- [Convert Drone CI pipelines to Woodpecker CI](https://codeberg.org/lafriks/woodpecker-pipeline-transform)
- [Ansible NAS](https://github.com/davestephens/ansible-nas/) - a homelab Ansible playbook that can set up Woodpecker-CI and Gitea
- [picus](https://github.com/windsource/picus) - Picus connects to a Woodpecker CI server and creates an agent in the cloud when there are pending jobs.
- [picus](https://github.com/windsource/picus) - Picus connects to a Woodpecker CI server and creates an agent in the cloud when there are pending workflows.
## Templates

View file

@ -58,7 +58,7 @@ WOODPECKER_GITHUB_SECRET=<redacted>
# agent
WOODPECKER_SERVER=localhost:9000
WOODPECKER_SECRET=a-long-and-secure-password-used-for-the-local-development-system
WOODPECKER_MAX_PROCS=1
WOODPECKER_MAX_WORKFLOWS=1
# enable if you want to develop the UI
# WOODPECKER_DEV_WWW_PROXY=http://localhost:8010

View file

@ -12,73 +12,73 @@ import (
)
// returns a container configuration.
func toConfig(proc *types.Step) *container.Config {
func toConfig(step *types.Step) *container.Config {
config := &container.Config{
Image: proc.Image,
Labels: proc.Labels,
WorkingDir: proc.WorkingDir,
Image: step.Image,
Labels: step.Labels,
WorkingDir: step.WorkingDir,
AttachStdout: true,
AttachStderr: true,
}
if len(proc.Environment) != 0 {
config.Env = toEnv(proc.Environment)
if len(step.Environment) != 0 {
config.Env = toEnv(step.Environment)
}
if len(proc.Command) != 0 {
config.Cmd = proc.Command
if len(step.Command) != 0 {
config.Cmd = step.Command
}
if len(proc.Entrypoint) != 0 {
config.Entrypoint = proc.Entrypoint
if len(step.Entrypoint) != 0 {
config.Entrypoint = step.Entrypoint
}
if len(proc.Volumes) != 0 {
config.Volumes = toVol(proc.Volumes)
if len(step.Volumes) != 0 {
config.Volumes = toVol(step.Volumes)
}
return config
}
// returns a container host configuration.
func toHostConfig(proc *types.Step) *container.HostConfig {
func toHostConfig(step *types.Step) *container.HostConfig {
config := &container.HostConfig{
Resources: container.Resources{
CPUQuota: proc.CPUQuota,
CPUShares: proc.CPUShares,
CpusetCpus: proc.CPUSet,
Memory: proc.MemLimit,
MemorySwap: proc.MemSwapLimit,
CPUQuota: step.CPUQuota,
CPUShares: step.CPUShares,
CpusetCpus: step.CPUSet,
Memory: step.MemLimit,
MemorySwap: step.MemSwapLimit,
},
LogConfig: container.LogConfig{
Type: "json-file",
},
Privileged: proc.Privileged,
ShmSize: proc.ShmSize,
Sysctls: proc.Sysctls,
Privileged: step.Privileged,
ShmSize: step.ShmSize,
Sysctls: step.Sysctls,
}
// if len(proc.VolumesFrom) != 0 {
// config.VolumesFrom = proc.VolumesFrom
// if len(step.VolumesFrom) != 0 {
// config.VolumesFrom = step.VolumesFrom
// }
if len(proc.NetworkMode) != 0 {
config.NetworkMode = container.NetworkMode(proc.NetworkMode)
if len(step.NetworkMode) != 0 {
config.NetworkMode = container.NetworkMode(step.NetworkMode)
}
if len(proc.IpcMode) != 0 {
config.IpcMode = container.IpcMode(proc.IpcMode)
if len(step.IpcMode) != 0 {
config.IpcMode = container.IpcMode(step.IpcMode)
}
if len(proc.DNS) != 0 {
config.DNS = proc.DNS
if len(step.DNS) != 0 {
config.DNS = step.DNS
}
if len(proc.DNSSearch) != 0 {
config.DNSSearch = proc.DNSSearch
if len(step.DNSSearch) != 0 {
config.DNSSearch = step.DNSSearch
}
if len(proc.ExtraHosts) != 0 {
config.ExtraHosts = proc.ExtraHosts
if len(step.ExtraHosts) != 0 {
config.ExtraHosts = step.ExtraHosts
}
if len(proc.Devices) != 0 {
config.Devices = toDev(proc.Devices)
if len(step.Devices) != 0 {
config.Devices = toDev(step.Devices)
}
if len(proc.Volumes) != 0 {
config.Binds = proc.Volumes
if len(step.Volumes) != 0 {
config.Binds = step.Volumes
}
config.Tmpfs = map[string]string{}
for _, path := range proc.Tmpfs {
for _, path := range step.Tmpfs {
if !strings.Contains(path, ":") {
config.Tmpfs[path] = ""
continue

View file

@ -104,19 +104,19 @@ func (e *docker) Setup(_ context.Context, conf *backend.Config) error {
return nil
}
func (e *docker) Exec(ctx context.Context, proc *backend.Step) error {
config := toConfig(proc)
hostConfig := toHostConfig(proc)
func (e *docker) Exec(ctx context.Context, step *backend.Step) error {
config := toConfig(step)
hostConfig := toHostConfig(step)
// create pull options with encoded authorization credentials.
pullopts := types.ImagePullOptions{}
if proc.AuthConfig.Username != "" && proc.AuthConfig.Password != "" {
pullopts.RegistryAuth, _ = encodeAuthToBase64(proc.AuthConfig)
if step.AuthConfig.Username != "" && step.AuthConfig.Password != "" {
pullopts.RegistryAuth, _ = encodeAuthToBase64(step.AuthConfig)
}
// automatically pull the latest version of the image if requested
// by the process configuration.
if proc.Pull {
if step.Pull {
responseBody, perr := e.client.ImagePull(ctx, config.Image, pullopts)
if perr == nil {
defer responseBody.Close()
@ -128,7 +128,7 @@ func (e *docker) Exec(ctx context.Context, proc *backend.Step) error {
}
// Fix "Show warning when fail to auth to docker registry"
// (https://web.archive.org/web/20201023145804/https://github.com/drone/drone/issues/1917)
if perr != nil && proc.AuthConfig.Password != "" {
if perr != nil && step.AuthConfig.Password != "" {
return perr
}
}
@ -136,7 +136,7 @@ func (e *docker) Exec(ctx context.Context, proc *backend.Step) error {
// add default volumes to the host configuration
hostConfig.Binds = append(hostConfig.Binds, e.volumes...)
_, err := e.client.ContainerCreate(ctx, config, hostConfig, nil, nil, proc.Name)
_, err := e.client.ContainerCreate(ctx, config, hostConfig, nil, nil, step.Name)
if client.IsErrNotFound(err) {
// automatically pull and try to re-create the image if the
// failure is caused because the image does not exist.
@ -150,15 +150,15 @@ func (e *docker) Exec(ctx context.Context, proc *backend.Step) error {
log.Error().Err(err).Msg("DisplayJSONMessagesStream")
}
_, err = e.client.ContainerCreate(ctx, config, hostConfig, nil, nil, proc.Name)
_, err = e.client.ContainerCreate(ctx, config, hostConfig, nil, nil, step.Name)
}
if err != nil {
return err
}
if len(proc.NetworkMode) == 0 {
for _, net := range proc.Networks {
err = e.client.NetworkConnect(ctx, net.Name, proc.Name, &network.EndpointSettings{
if len(step.NetworkMode) == 0 {
for _, net := range step.Networks {
err = e.client.NetworkConnect(ctx, net.Name, step.Name, &network.EndpointSettings{
Aliases: net.Aliases,
})
if err != nil {
@ -168,24 +168,24 @@ func (e *docker) Exec(ctx context.Context, proc *backend.Step) error {
// join the container to an existing network
if e.network != "" {
err = e.client.NetworkConnect(ctx, e.network, proc.Name, &network.EndpointSettings{})
err = e.client.NetworkConnect(ctx, e.network, step.Name, &network.EndpointSettings{})
if err != nil {
return err
}
}
}
return e.client.ContainerStart(ctx, proc.Name, startOpts)
return e.client.ContainerStart(ctx, step.Name, startOpts)
}
func (e *docker) Wait(ctx context.Context, proc *backend.Step) (*backend.State, error) {
wait, errc := e.client.ContainerWait(ctx, proc.Name, "")
func (e *docker) Wait(ctx context.Context, step *backend.Step) (*backend.State, error) {
wait, errc := e.client.ContainerWait(ctx, step.Name, "")
select {
case <-wait:
case <-errc:
}
info, err := e.client.ContainerInspect(ctx, proc.Name)
info, err := e.client.ContainerInspect(ctx, step.Name)
if err != nil {
return nil, err
}
@ -200,8 +200,8 @@ func (e *docker) Wait(ctx context.Context, proc *backend.Step) (*backend.State,
}, nil
}
func (e *docker) Tail(ctx context.Context, proc *backend.Step) (io.ReadCloser, error) {
logs, err := e.client.ContainerLogs(ctx, proc.Name, logsOpts)
func (e *docker) Tail(ctx context.Context, step *backend.Step) (io.ReadCloser, error) {
logs, err := e.client.ContainerLogs(ctx, step.Name, logsOpts)
if err != nil {
return nil, err
}

View file

@ -55,33 +55,33 @@ func (e *local) Load() error {
}
// Setup the pipeline environment.
func (e *local) Setup(ctx context.Context, proc *types.Config) error {
func (e *local) Setup(ctx context.Context, config *types.Config) error {
return nil
}
// Exec the pipeline step.
func (e *local) Exec(ctx context.Context, proc *types.Step) error {
func (e *local) Exec(ctx context.Context, step *types.Step) error {
// Get environment variables
Env := os.Environ()
for a, b := range proc.Environment {
for a, b := range step.Environment {
if a != "HOME" && a != "SHELL" { // Don't override $HOME and $SHELL
Env = append(Env, a+"="+b)
}
}
Command := []string{}
if proc.Image == constant.DefaultCloneImage {
if step.Image == constant.DefaultCloneImage {
// Default clone step
Env = append(Env, "CI_WORKSPACE="+e.workingdir+"/"+proc.Environment["CI_REPO"])
Env = append(Env, "CI_WORKSPACE="+e.workingdir+"/"+step.Environment["CI_REPO"])
Command = append(Command, "plugin-git")
} else {
// Use "image name" as run command
Command = append(Command, proc.Image)
Command = append(Command, step.Image)
Command = append(Command, "-c")
// Decode script and delete initial lines
// Deleting the initial lines removes netrc support but adds compatibility for more shells like fish
Script, _ := base64.RawStdEncoding.DecodeString(proc.Environment["CI_SCRIPT"])
Script, _ := base64.RawStdEncoding.DecodeString(step.Environment["CI_SCRIPT"])
Command = append(Command, string(Script)[strings.Index(string(Script), "\n\n")+2:])
}
@ -90,10 +90,10 @@ func (e *local) Exec(ctx context.Context, proc *types.Step) error {
e.cmd.Env = Env
// Prepare working directory
if proc.Image == constant.DefaultCloneImage {
e.cmd.Dir = e.workingdir + "/" + proc.Environment["CI_REPO_OWNER"]
if step.Image == constant.DefaultCloneImage {
e.cmd.Dir = e.workingdir + "/" + step.Environment["CI_REPO_OWNER"]
} else {
e.cmd.Dir = e.workingdir + "/" + proc.Environment["CI_REPO"]
e.cmd.Dir = e.workingdir + "/" + step.Environment["CI_REPO"]
}
err := os.MkdirAll(e.cmd.Dir, 0o700)
if err != nil {

View file

@ -84,33 +84,33 @@ func (e *ssh) Load() error {
}
// Setup the pipeline environment.
func (e *ssh) Setup(ctx context.Context, proc *types.Config) error {
func (e *ssh) Setup(ctx context.Context, config *types.Config) error {
return nil
}
// Exec the pipeline step.
func (e *ssh) Exec(ctx context.Context, proc *types.Step) error {
func (e *ssh) Exec(ctx context.Context, step *types.Step) error {
// Get environment variables
Command := []string{}
for a, b := range proc.Environment {
for a, b := range step.Environment {
if a != "HOME" && a != "SHELL" { // Don't override $HOME and $SHELL
Command = append(Command, a+"="+b)
}
}
if proc.Image == constant.DefaultCloneImage {
if step.Image == constant.DefaultCloneImage {
// Default clone step
Command = append(Command, "CI_WORKSPACE="+e.workingdir+"/"+proc.Environment["CI_REPO"])
Command = append(Command, "CI_WORKSPACE="+e.workingdir+"/"+step.Environment["CI_REPO"])
Command = append(Command, "plugin-git")
} else {
// Use "image name" as run command
Command = append(Command, proc.Image)
Command = append(Command, step.Image)
Command = append(Command, "-c")
// Decode script and delete initial lines
// Deleting the initial lines removes netrc support but adds compatibility for more shells like fish
Script, _ := base64.RawStdEncoding.DecodeString(proc.Environment["CI_SCRIPT"])
Command = append(Command, "cd "+e.workingdir+"/"+proc.Environment["CI_REPO"]+" && "+string(Script)[strings.Index(string(Script), "\n\n")+2:])
Script, _ := base64.RawStdEncoding.DecodeString(step.Environment["CI_SCRIPT"])
Command = append(Command, "cd "+e.workingdir+"/"+step.Environment["CI_REPO"]+" && "+string(Script)[strings.Index(string(Script), "\n\n")+2:])
}
// Prepare command

View file

@ -55,5 +55,5 @@ func (m *Metadata) setDroneEnviron(env map[string]string) {
env["DRONE_GIT_HTTP_URL"] = env["CI_REPO_REMOTE"]
// misc
env["DRONE_SYSTEM_HOST"] = env["CI_SYSTEM_HOST"]
env["DRONE_STEP_NUMBER"] = env["CI_JOB_NUMBER"]
env["DRONE_STEP_NUMBER"] = env["CI_STEP_NUMBER"]
}

View file

@ -39,7 +39,7 @@ type (
Repo Repo `json:"repo,omitempty"`
Curr Pipeline `json:"curr,omitempty"`
Prev Pipeline `json:"prev,omitempty"`
Job Job `json:"job,omitempty"`
Step Step `json:"step,omitempty"`
Sys System `json:"sys,omitempty"`
}
@ -88,8 +88,8 @@ type (
Avatar string `json:"avatar,omitempty"`
}
// Job defines runtime metadata for a job.
Job struct {
// Step defines runtime metadata for a step.
Step struct {
Number int `json:"number,omitempty"`
Matrix map[string]string `json:"matrix,omitempty"`
}
@ -171,10 +171,10 @@ func (m *Metadata) Environ() map[string]string {
"CI_PIPELINE_STARTED": strconv.FormatInt(m.Curr.Started, 10),
"CI_PIPELINE_FINISHED": strconv.FormatInt(m.Curr.Finished, 10),
"CI_JOB_NUMBER": strconv.Itoa(m.Job.Number),
"CI_JOB_STATUS": "", // will be set by agent
"CI_JOB_STARTED": "", // will be set by agent
"CI_JOB_FINISHED": "", // will be set by agent
"CI_STEP_NUMBER": strconv.Itoa(m.Step.Number),
"CI_STEP_STATUS": "", // will be set by agent
"CI_STEP_STARTED": "", // will be set by agent
"CI_STEP_FINISHED": "", // will be set by agent
"CI_PREV_COMMIT_SHA": m.Prev.Commit.Sha,
"CI_PREV_COMMIT_REF": m.Prev.Commit.Ref,
@ -224,6 +224,11 @@ func (m *Metadata) Environ() map[string]string {
"CI_PREV_BUILD_CREATED": strconv.FormatInt(m.Prev.Created, 10),
"CI_PREV_BUILD_STARTED": strconv.FormatInt(m.Prev.Started, 10),
"CI_PREV_BUILD_FINISHED": strconv.FormatInt(m.Prev.Finished, 10),
// use CI_STEP_*
"CI_JOB_NUMBER": strconv.Itoa(m.Step.Number),
"CI_JOB_STATUS": "", // will be set by agent
"CI_JOB_STARTED": "", // will be set by agent
"CI_JOB_FINISHED": "", // will be set by agent
}
if m.Curr.Event == EventTag {
params["CI_COMMIT_TAG"] = strings.TrimPrefix(m.Curr.Commit.Ref, "refs/tags/")

View file

@ -138,7 +138,7 @@ func (c *Constraint) Match(metadata frontend.Metadata, global bool) (bool, error
c.SetDefaultEventFilter()
// apply step only filters
match = c.Matrix.Match(metadata.Job.Matrix)
match = c.Matrix.Match(metadata.Step.Matrix)
}
match = match && c.Platform.Match(metadata.Sys.Platform) &&

View file

@ -21,11 +21,11 @@ func TestMarshalUlimit(t *testing.T) {
Soft: 65535,
Hard: 65535,
},
Name: "nproc",
Name: "nstep",
},
},
},
expected: `nproc: 65535
expected: `nstep: 65535
`,
},
{
@ -61,11 +61,11 @@ func TestUnmarshalUlimits(t *testing.T) {
expected *Ulimits
}{
{
yaml: "nproc: 65535",
yaml: "nstep: 65535",
expected: &Ulimits{
Elements: []Ulimit{
{
Name: "nproc",
Name: "nstep",
ulimitValues: ulimitValues{
Soft: 65535,
Hard: 65535,
@ -91,7 +91,7 @@ func TestUnmarshalUlimits(t *testing.T) {
},
},
{
yaml: `nproc: 65535
yaml: `nstep: 65535
nofile:
soft: 20000
hard: 40000`,
@ -105,7 +105,7 @@ nofile:
},
},
{
Name: "nproc",
Name: "nstep",
ulimitValues: ulimitValues{
Soft: 65535,
Hard: 65535,

View file

@ -14,7 +14,7 @@ type Logger interface {
// function for process logging.
type LogFunc func(*backend.Step, multipart.Reader) error
// Log calls f(proc, r).
// Log calls f(step, r).
func (f LogFunc) Log(step *backend.Step, r multipart.Reader) error {
return f(step, r)
}

View file

@ -122,7 +122,7 @@ func (c *client) Init(ctx context.Context, id string, state State) (err error) {
req.State.Exited = state.Exited
req.State.Finished = state.Finished
req.State.Started = state.Started
req.State.Name = state.Proc
req.State.Name = state.Step
for {
_, err = c.client.Init(ctx, req)
if err == nil {
@ -156,7 +156,7 @@ func (c *client) Done(ctx context.Context, id string, state State) (err error) {
req.State.Exited = state.Exited
req.State.Finished = state.Finished
req.State.Started = state.Started
req.State.Name = state.Proc
req.State.Name = state.Step
for {
_, err = c.client.Done(ctx, req)
if err == nil {
@ -217,7 +217,7 @@ func (c *client) Update(ctx context.Context, id string, state State) (err error)
req.State.Exited = state.Exited
req.State.Finished = state.Finished
req.State.Started = state.Started
req.State.Name = state.Proc
req.State.Name = state.Step
for {
_, err = c.client.Update(ctx, req)
if err == nil {
@ -248,7 +248,7 @@ func (c *client) Upload(ctx context.Context, id string, file *File) (err error)
req.File = new(proto.File)
req.File.Name = file.Name
req.File.Mime = file.Mime
req.File.Proc = file.Proc
req.File.Step = file.Step
req.File.Size = int32(file.Size)
req.File.Time = file.Time
req.File.Data = file.Data
@ -283,7 +283,7 @@ func (c *client) Log(ctx context.Context, id string, line *Line) (err error) {
req.Line = new(proto.Line)
req.Line.Out = line.Out
req.Line.Pos = int32(line.Pos)
req.Line.Proc = line.Proc
req.Line.Step = line.Step
req.Line.Time = line.Time
for {
_, err = c.client.Log(ctx, req)

View file

@ -22,7 +22,7 @@ const (
// Line is a line of console output.
type Line struct {
Proc string `json:"proc,omitempty"`
Step string `json:"step,omitempty"`
Time int64 `json:"time,omitempty"`
Type int `json:"type,omitempty"`
Pos int `json:"pos,omitempty"`
@ -32,9 +32,9 @@ type Line struct {
func (l *Line) String() string {
switch l.Type {
case LineExitCode:
return fmt.Sprintf("[%s] exit code %s", l.Proc, l.Out)
return fmt.Sprintf("[%s] exit code %s", l.Step, l.Out)
default:
return fmt.Sprintf("[%s:L%v:%vs] %s", l.Proc, l.Pos, l.Time, l.Out)
return fmt.Sprintf("[%s:L%v:%vs] %s", l.Step, l.Pos, l.Time, l.Out)
}
}
@ -70,7 +70,7 @@ func (w *LineWriter) Write(p []byte) (n int, err error) {
line := &Line{
Out: out,
Proc: w.name,
Step: w.name,
Pos: w.num,
Time: int64(time.Since(w.now).Seconds()),
Type: LineStdout,
@ -83,7 +83,7 @@ func (w *LineWriter) Write(p []byte) (n int, err error) {
// for _, part := range bytes.Split(p, []byte{'\n'}) {
// line := &Line{
// Out: string(part),
// Proc: w.name,
// Step: w.name,
// Pos: w.num,
// Time: int64(time.Since(w.now).Seconds()),
// Type: LineStdout,

View file

@ -6,7 +6,7 @@ import (
func TestLine(t *testing.T) {
line := Line{
Proc: "redis",
Step: "redis",
Time: 60,
Pos: 1,
Out: "starting redis server",

View file

@ -14,7 +14,7 @@ type (
// State defines the pipeline state.
State struct {
Proc string `json:"proc"`
Step string `json:"step"`
Exited bool `json:"exited"`
ExitCode int `json:"exit_code"`
Started int64 `json:"started"`
@ -32,7 +32,7 @@ type (
// File defines a pipeline artifact.
File struct {
Name string `json:"name"`
Proc string `json:"proc"`
Step string `json:"step"`
Mime string `json:"mime"`
Time int64 `json:"time"`
Size int `json:"size"`

View file

@ -1,7 +1,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.28.1
// protoc v3.12.4
// protoc v3.21.7
// source: woodpecker.proto
package proto
@ -75,7 +75,7 @@ type File struct {
unknownFields protoimpl.UnknownFields
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
Proc string `protobuf:"bytes,2,opt,name=proc,proto3" json:"proc,omitempty"`
Step string `protobuf:"bytes,2,opt,name=step,proto3" json:"step,omitempty"`
Mime string `protobuf:"bytes,3,opt,name=mime,proto3" json:"mime,omitempty"`
Time int64 `protobuf:"varint,4,opt,name=time,proto3" json:"time,omitempty"`
Size int32 `protobuf:"varint,5,opt,name=size,proto3" json:"size,omitempty"`
@ -122,9 +122,9 @@ func (x *File) GetName() string {
return ""
}
func (x *File) GetProc() string {
func (x *File) GetStep() string {
if x != nil {
return x.Proc
return x.Step
}
return ""
}
@ -256,7 +256,7 @@ type Line struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Proc string `protobuf:"bytes,1,opt,name=proc,proto3" json:"proc,omitempty"`
Step string `protobuf:"bytes,1,opt,name=step,proto3" json:"step,omitempty"`
Time int64 `protobuf:"varint,2,opt,name=time,proto3" json:"time,omitempty"`
Pos int32 `protobuf:"varint,3,opt,name=pos,proto3" json:"pos,omitempty"`
Out string `protobuf:"bytes,4,opt,name=out,proto3" json:"out,omitempty"`
@ -294,9 +294,9 @@ func (*Line) Descriptor() ([]byte, []int) {
return file_woodpecker_proto_rawDescGZIP(), []int{2}
}
func (x *Line) GetProc() string {
func (x *Line) GetStep() string {
if x != nil {
return x.Proc
return x.Step
}
return ""
}
@ -1033,8 +1033,8 @@ var file_woodpecker_proto_rawDesc = []byte{
0x0a, 0x10, 0x77, 0x6f, 0x6f, 0x64, 0x70, 0x65, 0x63, 0x6b, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x12, 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe2, 0x01, 0x0a, 0x04, 0x46, 0x69,
0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x72, 0x6f, 0x63, 0x18, 0x02,
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x72, 0x6f, 0x63, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x69,
0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x74, 0x65, 0x70, 0x18, 0x02,
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x73, 0x74, 0x65, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x69,
0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6d, 0x69, 0x6d, 0x65, 0x12, 0x12,
0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x74, 0x69,
0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05,
@ -1056,8 +1056,8 @@ var file_woodpecker_proto_rawDesc = []byte{
0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x66,
0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72,
0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x52, 0x0a,
0x04, 0x4c, 0x69, 0x6e, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x72, 0x6f, 0x63, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x72, 0x6f, 0x63, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x69, 0x6d,
0x04, 0x4c, 0x69, 0x6e, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x74, 0x65, 0x70, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x04, 0x73, 0x74, 0x65, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x69, 0x6d,
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x10, 0x0a,
0x03, 0x70, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x70, 0x6f, 0x73, 0x12,
0x10, 0x0a, 0x03, 0x6f, 0x75, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6f, 0x75,

View file

@ -5,7 +5,7 @@ package proto;
message File {
string name = 1;
string proc = 2;
string step = 2;
string mime = 3;
int64 time = 4;
int32 size = 5;
@ -23,7 +23,7 @@ message State {
}
message Line {
string proc = 1;
string step = 1;
int64 time = 2;
int32 pos = 3;
string out = 4;

View file

@ -1,7 +1,7 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.2.0
// - protoc v3.12.4
// - protoc v3.21.7
// source: woodpecker.proto
package proto

View file

@ -14,7 +14,7 @@ type Tracer interface {
// functions as a Tracer.
type TraceFunc func(*State) error
// Trace calls f(proc, state).
// Trace calls f(state).
func (f TraceFunc) Trace(state *State) error {
return f(state)
}
@ -32,20 +32,24 @@ var DefaultTracer = TraceFunc(func(state *State) error {
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_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
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_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
// DEPRECATED
state.Pipeline.Step.Environment["CI_BUILD_STATUS"] = "success"
state.Pipeline.Step.Environment["CI_BUILD_STARTED"] = strconv.FormatInt(state.Pipeline.Time, 10)
state.Pipeline.Step.Environment["CI_BUILD_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
state.Pipeline.Step.Environment["CI_JOB_STATUS"] = "success"
state.Pipeline.Step.Environment["CI_JOB_STARTED"] = strconv.FormatInt(state.Pipeline.Time, 10)
state.Pipeline.Step.Environment["CI_JOB_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
if state.Pipeline.Error != nil {
state.Pipeline.Step.Environment["CI_PIPELINE_STATUS"] = "failure"
state.Pipeline.Step.Environment["CI_STEP_STATUS"] = "failure"
// DEPRECATED
state.Pipeline.Step.Environment["CI_BUILD_STATUS"] = "failure"
state.Pipeline.Step.Environment["CI_JOB_STATUS"] = "failure"
}
return nil

View file

@ -71,7 +71,7 @@ func FileGet(c *gin.Context) {
return
}
pid, err := strconv.Atoi(c.Param("proc"))
pid, err := strconv.Atoi(c.Param("step"))
if err != nil {
_ = c.AbortWithError(http.StatusBadRequest, err)
return
@ -83,13 +83,13 @@ func FileGet(c *gin.Context) {
return
}
proc, err := _store.ProcFind(pipeline, pid)
step, err := _store.StepFind(pipeline, pid)
if err != nil {
_ = c.AbortWithError(http.StatusInternalServerError, err)
return
}
file, err := _store.FileFind(proc, name)
file, err := _store.FileFind(step, name)
if err != nil {
c.String(404, "Error getting file %q. %s", name, err)
return
@ -100,7 +100,7 @@ func FileGet(c *gin.Context) {
return
}
rc, err := _store.FileRead(proc, file.Name)
rc, err := _store.FileRead(step, file.Name)
if err != nil {
c.String(404, "Error getting file stream %q. %s", name, err)
return

View file

@ -127,8 +127,8 @@ func GetPipeline(c *gin.Context) {
return
}
files, _ := _store.FileList(pl)
procs, _ := _store.ProcList(pl)
if pl.Procs, err = model.Tree(procs); err != nil {
steps, _ := _store.StepList(pl)
if pl.Steps, err = model.Tree(steps); err != nil {
_ = c.AbortWithError(http.StatusInternalServerError, err)
return
}
@ -148,12 +148,12 @@ func GetPipelineLast(c *gin.Context) {
return
}
procs, err := _store.ProcList(pl)
steps, err := _store.StepList(pl)
if err != nil {
_ = c.AbortWithError(http.StatusInternalServerError, err)
return
}
if pl.Procs, err = model.Tree(procs); err != nil {
if pl.Steps, err = model.Tree(steps); err != nil {
_ = c.AbortWithError(http.StatusInternalServerError, err)
return
}
@ -164,11 +164,11 @@ func GetPipelineLogs(c *gin.Context) {
_store := store.FromContext(c)
repo := session.Repo(c)
// parse the pipeline number and job sequence number from
// parse the pipeline number and step sequence number from
// the request parameter.
num, _ := strconv.ParseInt(c.Params.ByName("number"), 10, 64)
ppid, _ := strconv.Atoi(c.Params.ByName("pid"))
name := c.Params.ByName("proc")
name := c.Params.ByName("step")
pl, err := _store.GetPipelineNumber(repo, num)
if err != nil {
@ -176,13 +176,13 @@ func GetPipelineLogs(c *gin.Context) {
return
}
proc, err := _store.ProcChild(pl, ppid, name)
step, err := _store.StepChild(pl, ppid, name)
if err != nil {
_ = c.AbortWithError(404, err)
return
}
rc, err := _store.LogFind(proc)
rc, err := _store.LogFind(step)
if err != nil {
_ = c.AbortWithError(404, err)
return
@ -196,11 +196,11 @@ func GetPipelineLogs(c *gin.Context) {
}
}
func GetProcLogs(c *gin.Context) {
func GetStepLogs(c *gin.Context) {
_store := store.FromContext(c)
repo := session.Repo(c)
// parse the pipeline number and job sequence number from
// parse the pipeline number and step sequence number from
// the request parameter.
num, _ := strconv.ParseInt(c.Params.ByName("number"), 10, 64)
pid, _ := strconv.Atoi(c.Params.ByName("pid"))
@ -211,13 +211,13 @@ func GetProcLogs(c *gin.Context) {
return
}
proc, err := _store.ProcFind(pl, pid)
step, err := _store.StepFind(pl, pid)
if err != nil {
_ = c.AbortWithError(http.StatusNotFound, err)
return
}
rc, err := _store.LogFind(proc)
rc, err := _store.LogFind(step)
if err != nil {
_ = c.AbortWithError(http.StatusNotFound, err)
return
@ -407,7 +407,7 @@ func DeletePipelineLogs(c *gin.Context) {
return
}
procs, err := _store.ProcList(pl)
steps, err := _store.StepList(pl)
if err != nil {
_ = c.AbortWithError(404, err)
return
@ -419,10 +419,10 @@ func DeletePipelineLogs(c *gin.Context) {
return
}
for _, proc := range procs {
for _, step := range steps {
t := time.Now().UTC()
buf := bytes.NewBufferString(fmt.Sprintf(deleteStr, proc.Name, user.Login, t.Format(time.UnixDate)))
lerr := _store.LogSave(proc, buf)
buf := bytes.NewBufferString(fmt.Sprintf(deleteStr, step.Name, user.Login, t.Format(time.UnixDate)))
lerr := _store.LogSave(step, buf)
if lerr != nil {
err = lerr
}
@ -437,7 +437,7 @@ func DeletePipelineLogs(c *gin.Context) {
var deleteStr = `[
{
"proc": %q,
"step": %q,
"pos": 0,
"out": "logs purged by %s on %s\n"
}

View file

@ -141,10 +141,10 @@ func LogStreamSSE(c *gin.Context) {
repo := session.Repo(c)
_store := store.FromContext(c)
// // parse the pipeline number and job sequence number from
// // parse the pipeline number and step sequence number from
// // the repquest parameter.
pipelinen, _ := strconv.ParseInt(c.Param("pipeline"), 10, 64)
jobn, _ := strconv.Atoi(c.Param("number"))
stepn, _ := strconv.Atoi(c.Param("number"))
pipeline, err := _store.GetPipelineNumber(repo, pipelinen)
if err != nil {
@ -152,13 +152,13 @@ func LogStreamSSE(c *gin.Context) {
logWriteStringErr(io.WriteString(rw, "event: error\ndata: pipeline not found\n\n"))
return
}
proc, err := _store.ProcFind(pipeline, jobn)
step, err := _store.StepFind(pipeline, stepn)
if err != nil {
log.Debug().Msgf("stream cannot get proc number: %v", err)
log.Debug().Msgf("stream cannot get step number: %v", err)
logWriteStringErr(io.WriteString(rw, "event: error\ndata: process not found\n\n"))
return
}
if proc.State != model.StatusRunning {
if step.State != model.StatusRunning {
log.Debug().Msg("stream not found.")
logWriteStringErr(io.WriteString(rw, "event: error\ndata: stream not found\n\n"))
return
@ -179,7 +179,7 @@ func LogStreamSSE(c *gin.Context) {
go func() {
// TODO remove global variable
err := server.Config.Services.Logs.Tail(ctx, fmt.Sprint(proc.ID), func(entries ...*logging.Entry) {
err := server.Config.Services.Logs.Tail(ctx, fmt.Sprint(step.ID), func(entries ...*logging.Entry) {
defer func() {
obj := recover() // fix #2480 // TODO: check if it's still needed
log.Trace().Msgf("pubsub subscribe recover return: %v", obj)

View file

@ -50,7 +50,7 @@ var Config = struct {
// Builds model.BuildStore
// Logs model.LogStore
Files model.FileStore
Procs model.ProcStore
Steps model.StepStore
// Registries model.RegistryStore
// Secrets model.SecretStore
}

View file

@ -97,26 +97,26 @@ func (s *RPC) Extend(c context.Context, id string) error {
// Update implements the rpc.Update function
func (s *RPC) Update(c context.Context, id string, state rpc.State) error {
procID, err := strconv.ParseInt(id, 10, 64)
stepID, err := strconv.ParseInt(id, 10, 64)
if err != nil {
return err
}
pproc, err := s.store.ProcLoad(procID)
pstep, err := s.store.StepLoad(stepID)
if err != nil {
log.Error().Msgf("error: rpc.update: cannot find pproc with id %d: %s", procID, err)
log.Error().Msgf("error: rpc.update: cannot find step with id %d: %s", stepID, err)
return err
}
pipeline, err := s.store.GetPipeline(pproc.PipelineID)
pipeline, err := s.store.GetPipeline(pstep.PipelineID)
if err != nil {
log.Error().Msgf("error: cannot find pipeline with id %d: %s", pproc.PipelineID, err)
log.Error().Msgf("error: cannot find pipeline with id %d: %s", pstep.PipelineID, err)
return err
}
proc, err := s.store.ProcChild(pipeline, pproc.PID, state.Proc)
step, err := s.store.StepChild(pipeline, pstep.PID, state.Step)
if err != nil {
log.Error().Msgf("error: cannot find proc with name %s: %s", state.Proc, err)
log.Error().Msgf("error: cannot find step with name %s: %s", state.Step, err)
return err
}
@ -124,7 +124,7 @@ func (s *RPC) Update(c context.Context, id string, state rpc.State) error {
if ok {
hostname, ok := metadata["hostname"]
if ok && len(hostname) != 0 {
proc.Machine = hostname[0]
step.Machine = hostname[0]
}
}
@ -134,15 +134,15 @@ func (s *RPC) Update(c context.Context, id string, state rpc.State) error {
return err
}
if _, err = shared.UpdateProcStatus(s.store, *proc, state, pipeline.Started); err != nil {
log.Error().Err(err).Msg("rpc.update: cannot update proc")
if _, err = shared.UpdateStepStatus(s.store, *step, state, pipeline.Started); err != nil {
log.Error().Err(err).Msg("rpc.update: cannot update step")
}
if pipeline.Procs, err = s.store.ProcList(pipeline); err != nil {
log.Error().Err(err).Msg("can not get proc list from store")
if pipeline.Steps, err = s.store.StepList(pipeline); err != nil {
log.Error().Err(err).Msg("can not get step list from store")
}
if pipeline.Procs, err = model.Tree(pipeline.Procs); err != nil {
log.Error().Err(err).Msg("can not build tree from proc list")
if pipeline.Steps, err = model.Tree(pipeline.Steps); err != nil {
log.Error().Err(err).Msg("can not build tree from step list")
return err
}
message := pubsub.Message{
@ -156,7 +156,7 @@ func (s *RPC) Update(c context.Context, id string, state rpc.State) error {
Pipeline: *pipeline,
})
if err := s.pubsub.Publish(c, "topic/events", message); err != nil {
log.Error().Err(err).Msg("can not publish proc list to")
log.Error().Err(err).Msg("can not publish step list to")
}
return nil
@ -164,40 +164,40 @@ func (s *RPC) Update(c context.Context, id string, state rpc.State) error {
// Upload implements the rpc.Upload function
func (s *RPC) Upload(c context.Context, id string, file *rpc.File) error {
procID, err := strconv.ParseInt(id, 10, 64)
stepID, err := strconv.ParseInt(id, 10, 64)
if err != nil {
return err
}
pproc, err := s.store.ProcLoad(procID)
pstep, err := s.store.StepLoad(stepID)
if err != nil {
log.Error().Msgf("error: cannot find parent proc with id %d: %s", procID, err)
log.Error().Msgf("error: cannot find parent step with id %d: %s", stepID, err)
return err
}
pipeline, err := s.store.GetPipeline(pproc.PipelineID)
pipeline, err := s.store.GetPipeline(pstep.PipelineID)
if err != nil {
log.Error().Msgf("error: cannot find pipeline with id %d: %s", pproc.PipelineID, err)
log.Error().Msgf("error: cannot find pipeline with id %d: %s", pstep.PipelineID, err)
return err
}
proc, err := s.store.ProcChild(pipeline, pproc.PID, file.Proc)
step, err := s.store.StepChild(pipeline, pstep.PID, file.Step)
if err != nil {
log.Error().Msgf("error: cannot find child proc with name %s: %s", file.Proc, err)
log.Error().Msgf("error: cannot find child step with name %s: %s", file.Step, err)
return err
}
if file.Mime == "application/json+logs" {
return s.store.LogSave(
proc,
step,
bytes.NewBuffer(file.Data),
)
}
report := &model.File{
PipelineID: proc.PipelineID,
ProcID: proc.ID,
PID: proc.PID,
PipelineID: step.PipelineID,
StepID: step.ID,
PID: step.PID,
Mime: file.Mime,
Name: file.Name,
Size: file.Size,
@ -237,27 +237,27 @@ func (s *RPC) Upload(c context.Context, id string, file *rpc.File) error {
// Init implements the rpc.Init function
func (s *RPC) Init(c context.Context, id string, state rpc.State) error {
procID, err := strconv.ParseInt(id, 10, 64)
stepID, err := strconv.ParseInt(id, 10, 64)
if err != nil {
return err
}
proc, err := s.store.ProcLoad(procID)
step, err := s.store.StepLoad(stepID)
if err != nil {
log.Error().Msgf("error: cannot find proc with id %d: %s", procID, err)
log.Error().Msgf("error: cannot find step with id %d: %s", stepID, err)
return err
}
metadata, ok := grpcMetadata.FromIncomingContext(c)
if ok {
hostname, ok := metadata["hostname"]
if ok && len(hostname) != 0 {
proc.Machine = hostname[0]
step.Machine = hostname[0]
}
}
pipeline, err := s.store.GetPipeline(proc.PipelineID)
pipeline, err := s.store.GetPipeline(step.PipelineID)
if err != nil {
log.Error().Msgf("error: cannot find pipeline with id %d: %s", proc.PipelineID, err)
log.Error().Msgf("error: cannot find pipeline with id %d: %s", step.PipelineID, err)
return err
}
@ -274,7 +274,7 @@ func (s *RPC) Init(c context.Context, id string, state rpc.State) error {
}
defer func() {
pipeline.Procs, _ = s.store.ProcList(pipeline)
pipeline.Steps, _ = s.store.StepList(pipeline)
message := pubsub.Message{
Labels: map[string]string{
"repo": repo.FullName,
@ -286,30 +286,30 @@ func (s *RPC) Init(c context.Context, id string, state rpc.State) error {
Pipeline: *pipeline,
})
if err := s.pubsub.Publish(c, "topic/events", message); err != nil {
log.Error().Err(err).Msg("can not publish proc list to")
log.Error().Err(err).Msg("can not publish step list to")
}
}()
_, err = shared.UpdateProcToStatusStarted(s.store, *proc, state)
_, err = shared.UpdateStepToStatusStarted(s.store, *step, state)
return err
}
// Done implements the rpc.Done function
func (s *RPC) Done(c context.Context, id string, state rpc.State) error {
procID, err := strconv.ParseInt(id, 10, 64)
stepID, err := strconv.ParseInt(id, 10, 64)
if err != nil {
return err
}
proc, err := s.store.ProcLoad(procID)
step, err := s.store.StepLoad(stepID)
if err != nil {
log.Error().Msgf("error: cannot find proc with id %d: %s", procID, err)
log.Error().Msgf("error: cannot find step with id %d: %s", stepID, err)
return err
}
pipeline, err := s.store.GetPipeline(proc.PipelineID)
pipeline, err := s.store.GetPipeline(step.PipelineID)
if err != nil {
log.Error().Msgf("error: cannot find pipeline with id %d: %s", proc.PipelineID, err)
log.Error().Msgf("error: cannot find pipeline with id %d: %s", step.PipelineID, err)
return err
}
@ -322,42 +322,42 @@ func (s *RPC) Done(c context.Context, id string, state rpc.State) error {
log.Trace().
Str("repo_id", fmt.Sprint(repo.ID)).
Str("build_id", fmt.Sprint(pipeline.ID)).
Str("proc_id", id).
Str("step_id", id).
Msgf("gRPC Done with state: %#v", state)
if proc, err = shared.UpdateProcStatusToDone(s.store, *proc, state); err != nil {
log.Error().Msgf("error: done: cannot update proc_id %d state: %s", proc.ID, err)
if step, err = shared.UpdateStepStatusToDone(s.store, *step, state); err != nil {
log.Error().Msgf("error: done: cannot update step_id %d state: %s", step.ID, err)
}
var queueErr error
if proc.Failing() {
queueErr = s.queue.Error(c, id, fmt.Errorf("Proc finished with exitcode %d, %s", state.ExitCode, state.Error))
if step.Failing() {
queueErr = s.queue.Error(c, id, fmt.Errorf("Step finished with exitcode %d, %s", state.ExitCode, state.Error))
} else {
queueErr = s.queue.Done(c, id, proc.State)
queueErr = s.queue.Done(c, id, step.State)
}
if queueErr != nil {
log.Error().Msgf("error: done: cannot ack proc_id %d: %s", procID, err)
log.Error().Msgf("error: done: cannot ack step_id %d: %s", stepID, err)
}
procs, err := s.store.ProcList(pipeline)
steps, err := s.store.StepList(pipeline)
if err != nil {
return err
}
s.completeChildrenIfParentCompleted(procs, proc)
s.completeChildrenIfParentCompleted(steps, step)
if !model.IsThereRunningStage(procs) {
if pipeline, err = shared.UpdateStatusToDone(s.store, *pipeline, model.PipelineStatus(procs), proc.Stopped); err != nil {
if !model.IsThereRunningStage(steps) {
if pipeline, err = shared.UpdateStatusToDone(s.store, *pipeline, model.PipelineStatus(steps), step.Stopped); err != nil {
log.Error().Err(err).Msgf("error: done: cannot update build_id %d final state", pipeline.ID)
}
}
s.updateRemoteStatus(c, repo, pipeline, proc)
s.updateRemoteStatus(c, repo, pipeline, step)
if err := s.logger.Close(c, id); err != nil {
log.Error().Err(err).Msgf("done: cannot close build_id %d logger", proc.ID)
log.Error().Err(err).Msgf("done: cannot close build_id %d logger", step.ID)
}
if err := s.notify(c, repo, pipeline, procs); err != nil {
if err := s.notify(c, repo, pipeline, steps); err != nil {
return err
}
@ -365,8 +365,8 @@ func (s *RPC) Done(c context.Context, id string, state rpc.State) error {
s.pipelineCount.WithLabelValues(repo.FullName, pipeline.Branch, string(pipeline.Status), "total").Inc()
s.pipelineTime.WithLabelValues(repo.FullName, pipeline.Branch, string(pipeline.Status), "total").Set(float64(pipeline.Finished - pipeline.Started))
}
if model.IsMultiPipeline(procs) {
s.pipelineTime.WithLabelValues(repo.FullName, pipeline.Branch, string(proc.State), proc.Name).Set(float64(proc.Stopped - proc.Started))
if model.IsMultiPipeline(steps) {
s.pipelineTime.WithLabelValues(repo.FullName, pipeline.Branch, string(step.State), step.Name).Set(float64(step.Stopped - step.Started))
}
return nil
@ -382,17 +382,17 @@ func (s *RPC) Log(c context.Context, id string, line *rpc.Line) error {
return nil
}
func (s *RPC) completeChildrenIfParentCompleted(procs []*model.Proc, completedProc *model.Proc) {
for _, p := range procs {
if p.Running() && p.PPID == completedProc.PID {
if _, err := shared.UpdateProcToStatusSkipped(s.store, *p, completedProc.Stopped); err != nil {
log.Error().Msgf("error: done: cannot update proc_id %d child state: %s", p.ID, err)
func (s *RPC) completeChildrenIfParentCompleted(steps []*model.Step, completedStep *model.Step) {
for _, p := range steps {
if p.Running() && p.PPID == completedStep.PID {
if _, err := shared.UpdateStepToStatusSkipped(s.store, *p, completedStep.Stopped); err != nil {
log.Error().Msgf("error: done: cannot update step_id %d child state: %s", p.ID, err)
}
}
}
}
func (s *RPC) updateRemoteStatus(ctx context.Context, repo *model.Repo, pipeline *model.Pipeline, proc *model.Proc) {
func (s *RPC) updateRemoteStatus(ctx context.Context, repo *model.Repo, pipeline *model.Pipeline, step *model.Step) {
user, err := s.store.GetUser(repo.UserID)
if err != nil {
log.Error().Err(err).Msgf("can not get user with id '%d'", repo.UserID)
@ -410,17 +410,17 @@ func (s *RPC) updateRemoteStatus(ctx context.Context, repo *model.Repo, pipeline
}
}
// only do status updates for parent procs
if proc != nil && proc.IsParent() {
err = s.remote.Status(ctx, user, repo, pipeline, proc)
// only do status updates for parent steps
if step != nil && step.IsParent() {
err = s.remote.Status(ctx, user, repo, pipeline, step)
if err != nil {
log.Error().Err(err).Msgf("error setting commit status for %s/%d", repo.FullName, pipeline.Number)
}
}
}
func (s *RPC) notify(c context.Context, repo *model.Repo, pipeline *model.Pipeline, procs []*model.Proc) (err error) {
if pipeline.Procs, err = model.Tree(procs); err != nil {
func (s *RPC) notify(c context.Context, repo *model.Repo, pipeline *model.Pipeline, steps []*model.Step) (err error) {
if pipeline.Steps, err = model.Tree(steps); err != nil {
return err
}
message := pubsub.Message{

View file

@ -88,7 +88,7 @@ func (s *WoodpeckerServer) Init(c context.Context, req *proto.InitRequest) (*pro
ExitCode: int(req.GetState().GetExitCode()),
Finished: req.GetState().GetFinished(),
Started: req.GetState().GetStarted(),
Proc: req.GetState().GetName(),
Step: req.GetState().GetName(),
Exited: req.GetState().GetExited(),
}
res := new(proto.Empty)
@ -102,7 +102,7 @@ func (s *WoodpeckerServer) Update(c context.Context, req *proto.UpdateRequest) (
ExitCode: int(req.GetState().GetExitCode()),
Finished: req.GetState().GetFinished(),
Started: req.GetState().GetStarted(),
Proc: req.GetState().GetName(),
Step: req.GetState().GetName(),
Exited: req.GetState().GetExited(),
}
res := new(proto.Empty)
@ -115,7 +115,7 @@ func (s *WoodpeckerServer) Upload(c context.Context, req *proto.UploadRequest) (
Data: req.GetFile().GetData(),
Mime: req.GetFile().GetMime(),
Name: req.GetFile().GetName(),
Proc: req.GetFile().GetProc(),
Step: req.GetFile().GetStep(),
Size: int(req.GetFile().GetSize()),
Time: req.GetFile().GetTime(),
Meta: req.GetFile().GetMeta(),
@ -132,7 +132,7 @@ func (s *WoodpeckerServer) Done(c context.Context, req *proto.DoneRequest) (*pro
ExitCode: int(req.GetState().GetExitCode()),
Finished: req.GetState().GetFinished(),
Started: req.GetState().GetStarted(),
Proc: req.GetState().GetName(),
Step: req.GetState().GetName(),
Exited: req.GetState().GetExited(),
}
res := new(proto.Empty)
@ -157,7 +157,7 @@ func (s *WoodpeckerServer) Log(c context.Context, req *proto.LogRequest) (*proto
Out: req.GetLine().GetOut(),
Pos: int(req.GetLine().GetPos()),
Time: req.GetLine().GetTime(),
Proc: req.GetLine().GetProc(),
Step: req.GetLine().GetStep(),
}
res := new(proto.Empty)
err := s.peer.Log(c, req.GetId(), line)

View file

@ -20,8 +20,8 @@ import "io"
// FileStore persists pipeline artifacts to storage.
type FileStore interface {
FileList(*Pipeline) ([]*File, error)
FileFind(*Proc, string) (*File, error)
FileRead(*Proc, string) (io.ReadCloser, error)
FileFind(*Step, string) (*File, error)
FileRead(*Step, string) (io.ReadCloser, error)
FileCreate(*File, io.Reader) error
}
@ -29,7 +29,7 @@ type FileStore interface {
type File struct {
ID int64 `json:"id" xorm:"pk autoincr 'file_id'"`
PipelineID int64 `json:"-" xorm:"INDEX 'file_pipeline_id'"`
ProcID int64 `json:"proc_id" xorm:"UNIQUE(s) INDEX 'file_proc_id'"`
StepID int64 `json:"step_id" xorm:"UNIQUE(s) INDEX 'file_step_id'"`
PID int `json:"pid" xorm:"file_pid"`
Name string `json:"name" xorm:"UNIQUE(s) file_name"`
Size int `json:"size" xorm:"file_size"`

View file

@ -16,7 +16,7 @@ package model
type Logs struct {
ID int64 `xorm:"pk autoincr 'log_id'"`
ProcID int64 `xorm:"UNIQUE 'log_job_id'"`
StepID int64 `xorm:"UNIQUE 'log_step_id'"`
Data []byte `xorm:"LONGBLOB 'log_data'"`
// TODO: add create timestamp
}

View file

@ -48,7 +48,7 @@ type Pipeline struct {
Verified bool `json:"verified" xorm:"pipeline_verified"` // deprecate
Reviewer string `json:"reviewed_by" xorm:"pipeline_reviewer"`
Reviewed int64 `json:"reviewed_at" xorm:"pipeline_reviewed"`
Procs []*Proc `json:"procs,omitempty" xorm:"-"`
Steps []*Step `json:"steps,omitempty" xorm:"-"`
Files []*File `json:"files,omitempty" xorm:"-"`
ChangedFiles []string `json:"changed_files,omitempty" xorm:"json 'changed_files'"`
AdditionalVariables map[string]string `json:"variables,omitempty" xorm:"json 'additional_variables'"`

View file

@ -17,66 +17,66 @@ package model
import "fmt"
// ProcStore persists process information to storage.
type ProcStore interface {
ProcLoad(int64) (*Proc, error)
ProcFind(*Pipeline, int) (*Proc, error)
ProcChild(*Pipeline, int, string) (*Proc, error)
ProcList(*Pipeline) ([]*Proc, error)
ProcCreate([]*Proc) error
ProcUpdate(*Proc) error
ProcClear(*Pipeline) error
// StepStore persists process information to storage.
type StepStore interface {
StepLoad(int64) (*Step, error)
StepFind(*Pipeline, int) (*Step, error)
StepChild(*Pipeline, int, string) (*Step, error)
StepList(*Pipeline) ([]*Step, error)
StepCreate([]*Step) error
StepUpdate(*Step) error
StepClear(*Pipeline) error
}
// Proc represents a process in the pipeline.
// swagger:model proc
type Proc struct {
ID int64 `json:"id" xorm:"pk autoincr 'proc_id'"`
PipelineID int64 `json:"pipeline_id" xorm:"UNIQUE(s) INDEX 'proc_pipeline_id'"`
PID int `json:"pid" xorm:"UNIQUE(s) 'proc_pid'"`
PPID int `json:"ppid" xorm:"proc_ppid"`
PGID int `json:"pgid" xorm:"proc_pgid"`
Name string `json:"name" xorm:"proc_name"`
State StatusValue `json:"state" xorm:"proc_state"`
Error string `json:"error,omitempty" xorm:"VARCHAR(500) proc_error"`
ExitCode int `json:"exit_code" xorm:"proc_exit_code"`
Started int64 `json:"start_time,omitempty" xorm:"proc_started"`
Stopped int64 `json:"end_time,omitempty" xorm:"proc_stopped"`
Machine string `json:"machine,omitempty" xorm:"proc_machine"`
Platform string `json:"platform,omitempty" xorm:"proc_platform"`
Environ map[string]string `json:"environ,omitempty" xorm:"json 'proc_environ'"`
Children []*Proc `json:"children,omitempty" xorm:"-"`
// Step represents a process in the pipeline.
// swagger:model step
type Step struct {
ID int64 `json:"id" xorm:"pk autoincr 'step_id'"`
PipelineID int64 `json:"pipeline_id" xorm:"UNIQUE(s) INDEX 'step_pipeline_id'"`
PID int `json:"pid" xorm:"UNIQUE(s) 'step_pid'"`
PPID int `json:"ppid" xorm:"step_ppid"`
PGID int `json:"pgid" xorm:"step_pgid"`
Name string `json:"name" xorm:"step_name"`
State StatusValue `json:"state" xorm:"step_state"`
Error string `json:"error,omitempty" xorm:"VARCHAR(500) step_error"`
ExitCode int `json:"exit_code" xorm:"step_exit_code"`
Started int64 `json:"start_time,omitempty" xorm:"step_started"`
Stopped int64 `json:"end_time,omitempty" xorm:"step_stopped"`
Machine string `json:"machine,omitempty" xorm:"step_machine"`
Platform string `json:"platform,omitempty" xorm:"step_platform"`
Environ map[string]string `json:"environ,omitempty" xorm:"json 'step_environ'"`
Children []*Step `json:"children,omitempty" xorm:"-"`
}
type UpdateProcStore interface {
ProcUpdate(*Proc) error
type UpdateStepStore interface {
StepUpdate(*Step) error
}
// TableName return database table name for xorm
func (Proc) TableName() string {
return "procs"
func (Step) TableName() string {
return "steps"
}
// Running returns true if the process state is pending or running.
func (p *Proc) Running() bool {
func (p *Step) Running() bool {
return p.State == StatusPending || p.State == StatusRunning
}
// Failing returns true if the process state is failed, killed or error.
func (p *Proc) Failing() bool {
func (p *Step) Failing() bool {
return p.State == StatusError || p.State == StatusKilled || p.State == StatusFailure
}
// IsParent returns true if the process is a parent process.
func (p *Proc) IsParent() bool {
func (p *Step) IsParent() bool {
return p.PPID == 0
}
// IsMultiPipeline checks if proc list contain more than one parent proc
func IsMultiPipeline(procs []*Proc) bool {
// IsMultiPipeline checks if step list contain more than one parent step
func IsMultiPipeline(steps []*Step) bool {
c := 0
for _, proc := range procs {
if proc.IsParent() {
for _, step := range steps {
if step.IsParent() {
c++
}
if c > 1 {
@ -87,35 +87,35 @@ func IsMultiPipeline(procs []*Proc) bool {
}
// Tree creates a process tree from a flat process list.
func Tree(procs []*Proc) ([]*Proc, error) {
var nodes []*Proc
func Tree(steps []*Step) ([]*Step, error) {
var nodes []*Step
// init parent nodes
for i := range procs {
if procs[i].IsParent() {
nodes = append(nodes, procs[i])
for i := range steps {
if steps[i].IsParent() {
nodes = append(nodes, steps[i])
}
}
// assign children to parrents
for i := range procs {
if !procs[i].IsParent() {
parent, err := findNode(nodes, procs[i].PPID)
for i := range steps {
if !steps[i].IsParent() {
parent, err := findNode(nodes, steps[i].PPID)
if err != nil {
return nil, err
}
parent.Children = append(parent.Children, procs[i])
parent.Children = append(parent.Children, steps[i])
}
}
return nodes, nil
}
// PipelineStatus determine pipeline status based on corresponding proc list
func PipelineStatus(procs []*Proc) StatusValue {
// PipelineStatus determine pipeline status based on corresponding step list
func PipelineStatus(steps []*Step) StatusValue {
status := StatusSuccess
for _, p := range procs {
for _, p := range steps {
if p.IsParent() && p.Failing() {
status = p.State
}
@ -124,10 +124,10 @@ func PipelineStatus(procs []*Proc) StatusValue {
return status
}
// IsThereRunningStage determine if it contains procs running or pending to run
// IsThereRunningStage determine if it contains steps running or pending to run
// TODO: return false based on depends_on (https://github.com/woodpecker-ci/woodpecker/pull/730#discussion_r795681697)
func IsThereRunningStage(procs []*Proc) bool {
for _, p := range procs {
func IsThereRunningStage(steps []*Step) bool {
for _, p := range steps {
if p.IsParent() {
if p.Running() {
return true
@ -137,12 +137,12 @@ func IsThereRunningStage(procs []*Proc) bool {
return false
}
func findNode(nodes []*Proc, pid int) (*Proc, error) {
func findNode(nodes []*Step, pid int) (*Step, error) {
for _, node := range nodes {
if node.PID == pid {
return node, nil
}
}
return nil, fmt.Errorf("Corrupt proc structure")
return nil, fmt.Errorf("Corrupt step structure")
}

View file

@ -21,7 +21,7 @@ import (
)
func TestTree(t *testing.T) {
procs := []*Proc{{
steps := []*Step{{
ID: 25,
PID: 2,
PipelineID: 6,
@ -49,12 +49,12 @@ func TestTree(t *testing.T) {
State: StatusFailure,
Error: "1",
}}
procs, err := Tree(procs)
steps, err := Tree(steps)
assert.NoError(t, err)
assert.Len(t, procs, 1)
assert.Len(t, procs[0].Children, 2)
assert.Len(t, steps, 1)
assert.Len(t, steps[0].Children, 2)
procs = []*Proc{{
steps = []*Step{{
ID: 25,
PID: 2,
PipelineID: 6,
@ -64,6 +64,6 @@ func TestTree(t *testing.T) {
State: StatusSuccess,
Error: "0",
}}
_, err = Tree(procs)
_, err = Tree(steps)
assert.Error(t, err)
}

View file

@ -33,53 +33,53 @@ func Cancel(ctx context.Context, store store.Store, repo *model.Repo, pipeline *
return ErrBadRequest{Msg: "Cannot cancel a non-running or non-pending or non-blocked pipeline"}
}
procs, err := store.ProcList(pipeline)
steps, err := store.StepList(pipeline)
if err != nil {
return ErrNotFound{Msg: err.Error()}
}
// First cancel/evict procs in the queue in one go
// First cancel/evict steps in the queue in one go
var (
procsToCancel []string
procsToEvict []string
stepsToCancel []string
stepsToEvict []string
)
for _, proc := range procs {
if proc.PPID != 0 {
for _, step := range steps {
if step.PPID != 0 {
continue
}
if proc.State == model.StatusRunning {
procsToCancel = append(procsToCancel, fmt.Sprint(proc.ID))
if step.State == model.StatusRunning {
stepsToCancel = append(stepsToCancel, fmt.Sprint(step.ID))
}
if proc.State == model.StatusPending {
procsToEvict = append(procsToEvict, fmt.Sprint(proc.ID))
if step.State == model.StatusPending {
stepsToEvict = append(stepsToEvict, fmt.Sprint(step.ID))
}
}
if len(procsToEvict) != 0 {
if err := server.Config.Services.Queue.EvictAtOnce(ctx, procsToEvict); err != nil {
log.Error().Err(err).Msgf("queue: evict_at_once: %v", procsToEvict)
if len(stepsToEvict) != 0 {
if err := server.Config.Services.Queue.EvictAtOnce(ctx, stepsToEvict); err != nil {
log.Error().Err(err).Msgf("queue: evict_at_once: %v", stepsToEvict)
}
if err := server.Config.Services.Queue.ErrorAtOnce(ctx, procsToEvict, queue.ErrCancel); err != nil {
log.Error().Err(err).Msgf("queue: evict_at_once: %v", procsToEvict)
if err := server.Config.Services.Queue.ErrorAtOnce(ctx, stepsToEvict, queue.ErrCancel); err != nil {
log.Error().Err(err).Msgf("queue: evict_at_once: %v", stepsToEvict)
}
}
if len(procsToCancel) != 0 {
if err := server.Config.Services.Queue.ErrorAtOnce(ctx, procsToCancel, queue.ErrCancel); err != nil {
log.Error().Err(err).Msgf("queue: evict_at_once: %v", procsToCancel)
if len(stepsToCancel) != 0 {
if err := server.Config.Services.Queue.ErrorAtOnce(ctx, stepsToCancel, queue.ErrCancel); err != nil {
log.Error().Err(err).Msgf("queue: evict_at_once: %v", stepsToCancel)
}
}
// Then update the DB status for pending pipelines
// Running ones will be set when the agents stop on the cancel signal
for _, proc := range procs {
if proc.State == model.StatusPending {
if proc.PPID != 0 {
if _, err = shared.UpdateProcToStatusSkipped(store, *proc, 0); err != nil {
log.Error().Msgf("error: done: cannot update proc_id %d state: %s", proc.ID, err)
for _, step := range steps {
if step.State == model.StatusPending {
if step.PPID != 0 {
if _, err = shared.UpdateStepToStatusSkipped(store, *step, 0); err != nil {
log.Error().Msgf("error: done: cannot update step_id %d state: %s", step.ID, err)
}
} else {
if _, err = shared.UpdateProcToStatusKilled(store, *proc); err != nil {
log.Error().Msgf("error: done: cannot update proc_id %d state: %s", proc.ID, err)
if _, err = shared.UpdateStepToStatusKilled(store, *step); err != nil {
log.Error().Msgf("error: done: cannot update step_id %d state: %s", step.ID, err)
}
}
}
@ -91,11 +91,11 @@ func Cancel(ctx context.Context, store store.Store, repo *model.Repo, pipeline *
return err
}
procs, err = store.ProcList(killedBuild)
steps, err = store.StepList(killedBuild)
if err != nil {
return ErrNotFound{Msg: err.Error()}
}
if killedBuild.Procs, err = model.Tree(procs); err != nil {
if killedBuild.Steps, err = model.Tree(steps); err != nil {
return err
}
if err := publishToTopic(ctx, killedBuild, repo); err != nil {

View file

@ -101,7 +101,7 @@ func Create(ctx context.Context, _store store.Store, repo *model.Repo, pipeline
pipeline.Status = model.StatusBlocked
}
err = _store.CreatePipeline(pipeline, pipeline.Procs...)
err = _store.CreatePipeline(pipeline, pipeline.Steps...)
if err != nil {
msg := fmt.Sprintf("failure to save pipeline for %s", repo.FullName)
log.Error().Err(err).Msg(msg)

View file

@ -35,11 +35,11 @@ func Decline(ctx context.Context, store store.Store, pipeline *model.Pipeline, u
return nil, fmt.Errorf("error updating pipeline. %s", err)
}
if pipeline.Procs, err = store.ProcList(pipeline); err != nil {
log.Error().Err(err).Msg("can not get proc list from store")
if pipeline.Steps, err = store.StepList(pipeline); err != nil {
log.Error().Err(err).Msg("can not get step list from store")
}
if pipeline.Procs, err = model.Tree(pipeline.Procs); err != nil {
log.Error().Err(err).Msg("can not build tree from proc list")
if pipeline.Steps, err = model.Tree(pipeline.Steps); err != nil {
log.Error().Err(err).Msg("can not build tree from step list")
}
if err := updatePipelineStatus(ctx, pipeline, repo, user); err != nil {

View file

@ -27,7 +27,7 @@ import (
)
func zeroSteps(pipeline *model.Pipeline, remoteYamlConfigs []*remote.FileMeta) bool {
b := shared.ProcBuilder{
b := shared.StepBuilder{
Repo: &model.Repo{},
Curr: pipeline,
Last: &model.Pipeline{},

View file

@ -24,13 +24,13 @@ import (
)
func updatePipelineStatus(ctx context.Context, pipeline *model.Pipeline, repo *model.Repo, user *model.User) error {
for _, proc := range pipeline.Procs {
// skip child procs
if !proc.IsParent() {
for _, step := range pipeline.Steps {
// skip child steps
if !step.IsParent() {
continue
}
err := server.Config.Services.Remote.Status(ctx, user, repo, pipeline, proc)
err := server.Config.Services.Remote.Status(ctx, user, repo, pipeline, step)
if err != nil {
log.Error().Err(err).Msgf("error setting commit status for %s/%d", repo.FullName, pipeline.Number)
return err

View file

@ -64,7 +64,7 @@ func createPipelineItems(ctx context.Context, store store.Store, pipeline *model
envs[k] = v
}
b := shared.ProcBuilder{
b := shared.StepBuilder{
Repo: repo,
Curr: pipeline,
Last: last,

View file

@ -29,11 +29,11 @@ import (
func queueBuild(pipeline *model.Pipeline, repo *model.Repo, pipelineItems []*shared.PipelineItem) error {
var tasks []*queue.Task
for _, item := range pipelineItems {
if item.Proc.State == model.StatusSkipped {
if item.Step.State == model.StatusSkipped {
continue
}
task := new(queue.Task)
task.ID = fmt.Sprint(item.Proc.ID)
task.ID = fmt.Sprint(item.Step.ID)
task.Labels = map[string]string{}
for k, v := range item.Labels {
task.Labels[k] = v
@ -45,7 +45,7 @@ func queueBuild(pipeline *model.Pipeline, repo *model.Repo, pipelineItems []*sha
task.DepStatus = make(map[string]string)
task.Data, _ = json.Marshal(rpc.Pipeline{
ID: fmt.Sprint(item.Proc.ID),
ID: fmt.Sprint(item.Step.ID),
Config: item.Config,
Timeout: repo.Timeout,
})
@ -61,8 +61,8 @@ func queueBuild(pipeline *model.Pipeline, repo *model.Repo, pipelineItems []*sha
func taskIds(dependsOn []string, pipelineItems []*shared.PipelineItem) (taskIds []string) {
for _, dep := range dependsOn {
for _, pipelineItem := range pipelineItems {
if pipelineItem.Proc.Name == dep {
taskIds = append(taskIds, fmt.Sprint(pipelineItem.Proc.ID))
if pipelineItem.Step.Name == dep {
taskIds = append(taskIds, fmt.Sprint(pipelineItem.Step.ID))
}
}
}

View file

@ -32,8 +32,8 @@ func start(ctx context.Context, store store.Store, activePipeline *model.Pipelin
log.Error().Err(err).Msg("Failed to cancel previous pipelines")
}
if err := store.ProcCreate(activePipeline.Procs); err != nil {
log.Error().Err(err).Str("repo", repo.FullName).Msgf("error persisting procs for %s#%d", repo.FullName, activePipeline.Number)
if err := store.StepCreate(activePipeline.Steps); err != nil {
log.Error().Err(err).Str("repo", repo.FullName).Msgf("error persisting steps for %s#%d", repo.FullName, activePipeline.Number)
return nil, err
}

View file

@ -33,7 +33,7 @@ func publishToTopic(c context.Context, pipeline *model.Pipeline, repo *model.Rep
},
}
pipelineCopy := *pipeline
if pipelineCopy.Procs, err = model.Tree(pipelineCopy.Procs); err != nil {
if pipelineCopy.Steps, err = model.Tree(pipelineCopy.Steps); err != nil {
return err
}

View file

@ -227,7 +227,7 @@ func (c *config) Dir(ctx context.Context, u *model.User, r *model.Repo, p *model
}
// Status creates a pipeline status for the Bitbucket commit.
func (c *config) Status(ctx context.Context, user *model.User, repo *model.Repo, pipeline *model.Pipeline, proc *model.Proc) error {
func (c *config) Status(ctx context.Context, user *model.User, repo *model.Repo, pipeline *model.Pipeline, step *model.Step) error {
status := internal.PipelineStatus{
State: convertStatus(pipeline.Status),
Desc: common.GetPipelineStatusDescription(pipeline.Status),

View file

@ -255,7 +255,7 @@ func Test_bitbucket(t *testing.T) {
})
g.It("Should update the status", func() {
err := c.Status(ctx, fakeUser, fakeRepo, fakePipeline, fakeProc)
err := c.Status(ctx, fakeUser, fakeRepo, fakePipeline, fakeStep)
g.Assert(err).IsNil()
})
@ -355,7 +355,7 @@ var (
Commit: "9ecad50",
}
fakeProc = &model.Proc{
fakeStep = &model.Step{
Name: "test",
State: model.StatusSuccess,
}

View file

@ -190,7 +190,7 @@ func (c *Config) Dir(ctx context.Context, u *model.User, r *model.Repo, p *model
}
// Status is not supported by the bitbucketserver driver.
func (c *Config) Status(ctx context.Context, user *model.User, repo *model.Repo, pipeline *model.Pipeline, proc *model.Proc) error {
func (c *Config) Status(ctx context.Context, user *model.User, repo *model.Repo, pipeline *model.Pipeline, step *model.Step) error {
status := internal.PipelineStatus{
State: convertStatus(pipeline.Status),
Desc: common.GetPipelineStatusDescription(pipeline.Status),

View file

@ -249,7 +249,7 @@ func (c *Coding) Dir(ctx context.Context, u *model.User, r *model.Repo, b *model
}
// Status sends the commit status to the remote system.
func (c *Coding) Status(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, proc *model.Proc) error {
func (c *Coding) Status(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, step *model.Step) error {
// EMPTY: not implemented in Coding OAuth API
return nil
}

View file

@ -23,7 +23,7 @@ import (
"github.com/woodpecker-ci/woodpecker/server/model"
)
func GetPipelineStatusContext(repo *model.Repo, pipeline *model.Pipeline, proc *model.Proc) string {
func GetPipelineStatusContext(repo *model.Repo, pipeline *model.Pipeline, step *model.Step) string {
event := string(pipeline.Event)
switch pipeline.Event {
case model.EventPull:
@ -38,7 +38,7 @@ func GetPipelineStatusContext(repo *model.Repo, pipeline *model.Pipeline, proc *
err = tmpl.Execute(&ctx, map[string]interface{}{
"context": server.Config.Server.StatusContext,
"event": event,
"pipeline": proc.Name,
"pipeline": step.Name,
"owner": repo.Owner,
"repo": repo.Name,
})
@ -72,10 +72,10 @@ func GetPipelineStatusDescription(status model.StatusValue) string {
}
}
func GetPipelineStatusLink(repo *model.Repo, pipeline *model.Pipeline, proc *model.Proc) string {
if proc == nil {
func GetPipelineStatusLink(repo *model.Repo, pipeline *model.Pipeline, step *model.Step) string {
if step == nil {
return fmt.Sprintf("%s/%s/pipeline/%d", server.Config.Server.Host, repo.FullName, pipeline.Number)
}
return fmt.Sprintf("%s/%s/pipeline/%d/%d", server.Config.Server.Host, repo.FullName, pipeline.Number, proc.PID)
return fmt.Sprintf("%s/%s/pipeline/%d/%d", server.Config.Server.Host, repo.FullName, pipeline.Number, step.PID)
}

View file

@ -33,17 +33,17 @@ func TestGetPipelineStatusContext(t *testing.T) {
repo := &model.Repo{Owner: "user1", Name: "repo1"}
pipeline := &model.Pipeline{Event: model.EventPull}
proc := &model.Proc{Name: "lint"}
step := &model.Step{Name: "lint"}
assert.EqualValues(t, "", GetPipelineStatusContext(repo, pipeline, proc))
assert.EqualValues(t, "", GetPipelineStatusContext(repo, pipeline, step))
server.Config.Server.StatusContext = "ci/woodpecker"
server.Config.Server.StatusContextFormat = "{{ .context }}/{{ .event }}/{{ .pipeline }}"
assert.EqualValues(t, "ci/woodpecker/pr/lint", GetPipelineStatusContext(repo, pipeline, proc))
assert.EqualValues(t, "ci/woodpecker/pr/lint", GetPipelineStatusContext(repo, pipeline, step))
pipeline.Event = model.EventPush
assert.EqualValues(t, "ci/woodpecker/push/lint", GetPipelineStatusContext(repo, pipeline, proc))
assert.EqualValues(t, "ci/woodpecker/push/lint", GetPipelineStatusContext(repo, pipeline, step))
server.Config.Server.StatusContext = "ci"
server.Config.Server.StatusContextFormat = "{{ .context }}:{{ .owner }}/{{ .repo }}:{{ .event }}:{{ .pipeline }}"
assert.EqualValues(t, "ci:user1/repo1:push:lint", GetPipelineStatusContext(repo, pipeline, proc))
assert.EqualValues(t, "ci:user1/repo1:push:lint", GetPipelineStatusContext(repo, pipeline, step))
}

View file

@ -326,7 +326,7 @@ func (c *Gitea) Dir(ctx context.Context, u *model.User, r *model.Repo, b *model.
}
// Status is supported by the Gitea driver.
func (c *Gitea) Status(ctx context.Context, user *model.User, repo *model.Repo, pipeline *model.Pipeline, proc *model.Proc) error {
func (c *Gitea) Status(ctx context.Context, user *model.User, repo *model.Repo, pipeline *model.Pipeline, step *model.Step) error {
client, err := c.newClientToken(ctx, user.Token)
if err != nil {
return err
@ -337,10 +337,10 @@ func (c *Gitea) Status(ctx context.Context, user *model.User, repo *model.Repo,
repo.Name,
pipeline.Commit,
gitea.CreateStatusOption{
State: getStatus(proc.State),
TargetURL: common.GetPipelineStatusLink(repo, pipeline, proc),
Description: common.GetPipelineStatusDescription(proc.State),
Context: common.GetPipelineStatusContext(repo, pipeline, proc),
State: getStatus(step.State),
TargetURL: common.GetPipelineStatusLink(repo, pipeline, step),
Description: common.GetPipelineStatusDescription(step.State),
Context: common.GetPipelineStatusContext(repo, pipeline, step),
},
)
return err

View file

@ -138,7 +138,7 @@ func Test_gitea(t *testing.T) {
})
g.It("Should return nil from send pipeline status", func() {
err := c.Status(ctx, fakeUser, fakeRepo, fakePipeline, fakeProc)
err := c.Status(ctx, fakeUser, fakeRepo, fakePipeline, fakeStep)
g.Assert(err).IsNil()
})
@ -186,7 +186,7 @@ var (
Commit: "9ecad50",
}
fakeProc = &model.Proc{
fakeStep = &model.Step{
Name: "test",
State: model.StatusSuccess,
}

View file

@ -437,7 +437,7 @@ var reDeploy = regexp.MustCompile(`.+/deployments/(\d+)`)
// Status sends the commit status to the remote system.
// An example would be the GitHub pull request status.
func (c *client) Status(ctx context.Context, user *model.User, repo *model.Repo, pipeline *model.Pipeline, proc *model.Proc) error {
func (c *client) Status(ctx context.Context, user *model.User, repo *model.Repo, pipeline *model.Pipeline, step *model.Step) error {
client := c.newClientToken(ctx, user.Token)
if pipeline.Event == model.EventDeploy {
@ -456,10 +456,10 @@ func (c *client) Status(ctx context.Context, user *model.User, repo *model.Repo,
}
_, _, err := client.Repositories.CreateStatus(ctx, repo.Owner, repo.Name, pipeline.Commit, &github.RepoStatus{
Context: github.String(common.GetPipelineStatusContext(repo, pipeline, proc)),
State: github.String(convertStatus(proc.State)),
Description: github.String(common.GetPipelineStatusDescription(proc.State)),
TargetURL: github.String(common.GetPipelineStatusLink(repo, pipeline, proc)),
Context: github.String(common.GetPipelineStatusContext(repo, pipeline, step)),
State: github.String(convertStatus(step.State)),
Description: github.String(common.GetPipelineStatusDescription(step.State)),
TargetURL: github.String(common.GetPipelineStatusLink(repo, pipeline, step)),
})
return err
}

View file

@ -387,7 +387,7 @@ func (g *Gitlab) Dir(ctx context.Context, user *model.User, repo *model.Repo, pi
}
// Status sends the commit status back to gitlab.
func (g *Gitlab) Status(ctx context.Context, user *model.User, repo *model.Repo, pipeline *model.Pipeline, proc *model.Proc) error {
func (g *Gitlab) Status(ctx context.Context, user *model.User, repo *model.Repo, pipeline *model.Pipeline, step *model.Step) error {
client, err := newClient(g.URL, user.Token, g.SkipVerify)
if err != nil {
return err
@ -399,10 +399,10 @@ func (g *Gitlab) Status(ctx context.Context, user *model.User, repo *model.Repo,
}
_, _, err = client.Commits.SetCommitStatus(_repo.ID, pipeline.Commit, &gitlab.SetCommitStatusOptions{
State: getStatus(proc.State),
Description: gitlab.String(common.GetPipelineStatusDescription(proc.State)),
TargetURL: gitlab.String(common.GetPipelineStatusLink(repo, pipeline, proc)),
Context: gitlab.String(common.GetPipelineStatusContext(repo, pipeline, proc)),
State: getStatus(step.State),
Description: gitlab.String(common.GetPipelineStatusDescription(step.State)),
TargetURL: gitlab.String(common.GetPipelineStatusLink(repo, pipeline, step)),
Context: gitlab.String(common.GetPipelineStatusContext(repo, pipeline, step)),
}, gitlab.WithContext(ctx))
return err

View file

@ -214,7 +214,7 @@ func (c *client) Dir(ctx context.Context, u *model.User, r *model.Repo, b *model
}
// Status is not supported by the Gogs driver.
func (c *client) Status(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, proc *model.Proc) error {
func (c *client) Status(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, step *model.Step) error {
return nil
}

View file

@ -342,11 +342,11 @@ func (_m *Remote) Repos(ctx context.Context, u *model.User) ([]*model.Repo, erro
}
// Status provides a mock function with given fields: ctx, u, r, b, p
func (_m *Remote) Status(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, p *model.Proc) error {
func (_m *Remote) Status(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, p *model.Step) error {
ret := _m.Called(ctx, u, r, b, p)
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, *model.User, *model.Repo, *model.Pipeline, *model.Proc) error); ok {
if rf, ok := ret.Get(0).(func(context.Context, *model.User, *model.Repo, *model.Pipeline, *model.Step) error); ok {
r0 = rf(ctx, u, r, b, p)
} else {
r0 = ret.Error(0)

View file

@ -62,7 +62,7 @@ type Remote interface {
// Status sends the commit status to the remote system.
// An example would be the GitHub pull request status.
Status(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, p *model.Proc) error
Status(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, p *model.Step) error
// Netrc returns a .netrc file that can be used to clone
// private repositories from a remote system.

View file

@ -85,16 +85,15 @@ func apiRoutes(e *gin.Engine) {
repo.DELETE("/pipelines/:number", session.MustPush, api.DeletePipeline)
repo.POST("/pipelines/:number/approve", session.MustPush, api.PostApproval)
repo.POST("/pipelines/:number/decline", session.MustPush, api.PostDecline)
repo.DELETE("/pipelines/:number/:job", session.MustPush, api.DeletePipeline)
repo.GET("/logs/:number/:pid", api.GetProcLogs)
repo.GET("/logs/:number/:pid/:proc", api.GetPipelineLogs)
repo.GET("/logs/:number/:pid", api.GetStepLogs)
repo.GET("/logs/:number/:pid/:step", api.GetPipelineLogs)
// requires push permissions
repo.DELETE("/logs/:number", session.MustPush, api.DeletePipelineLogs)
repo.GET("/files/:number", api.FileList)
repo.GET("/files/:number/:proc/*file", api.FileGet)
repo.GET("/files/:number/:step/*file", api.FileGet)
// requires push permissions
repo.GET("/secrets", session.MustPush, api.GetSecretList)

View file

@ -1,87 +0,0 @@
// Copyright 2019 mhmxs.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package shared
import (
"time"
"github.com/woodpecker-ci/woodpecker/pipeline/rpc"
"github.com/woodpecker-ci/woodpecker/server/model"
)
// TODO(974) move to server/pipeline/*
func UpdateProcStatus(store model.UpdateProcStore, proc model.Proc, state rpc.State, started int64) (*model.Proc, error) {
if state.Exited {
proc.Stopped = state.Finished
proc.ExitCode = state.ExitCode
proc.Error = state.Error
proc.State = model.StatusSuccess
if state.ExitCode != 0 || state.Error != "" {
proc.State = model.StatusFailure
}
if state.ExitCode == 137 {
proc.State = model.StatusKilled
}
} else {
proc.Started = state.Started
proc.State = model.StatusRunning
}
if proc.Started == 0 && proc.Stopped != 0 {
proc.Started = started
}
return &proc, store.ProcUpdate(&proc)
}
func UpdateProcToStatusStarted(store model.UpdateProcStore, proc model.Proc, state rpc.State) (*model.Proc, error) {
proc.Started = state.Started
proc.State = model.StatusRunning
return &proc, store.ProcUpdate(&proc)
}
func UpdateProcToStatusSkipped(store model.UpdateProcStore, proc model.Proc, stopped int64) (*model.Proc, error) {
proc.State = model.StatusSkipped
if proc.Started != 0 {
proc.State = model.StatusSuccess // for daemons that are killed
proc.Stopped = stopped
}
return &proc, store.ProcUpdate(&proc)
}
func UpdateProcStatusToDone(store model.UpdateProcStore, proc model.Proc, state rpc.State) (*model.Proc, error) {
proc.Stopped = state.Finished
proc.Error = state.Error
proc.ExitCode = state.ExitCode
if state.Started == 0 {
proc.State = model.StatusSkipped
} else {
proc.State = model.StatusSuccess
}
if proc.ExitCode != 0 || proc.Error != "" {
proc.State = model.StatusFailure
}
return &proc, store.ProcUpdate(&proc)
}
func UpdateProcToStatusKilled(store model.UpdateProcStore, proc model.Proc) (*model.Proc, error) {
proc.State = model.StatusKilled
proc.Stopped = time.Now().Unix()
if proc.Started == 0 {
proc.Started = proc.Stopped
}
proc.ExitCode = 137
return &proc, store.ProcUpdate(&proc)
}

View file

@ -1,286 +0,0 @@
// Copyright 2019 mhmxs.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package shared
import (
"testing"
"time"
"github.com/woodpecker-ci/woodpecker/pipeline/rpc"
"github.com/woodpecker-ci/woodpecker/server/model"
)
// TODO(974) move to server/pipeline/*
type mockUpdateProcStore struct{}
func (m *mockUpdateProcStore) ProcUpdate(build *model.Proc) error {
return nil
}
func TestUpdateProcStatusNotExited(t *testing.T) {
t.Parallel()
state := rpc.State{
Started: int64(42),
Exited: false,
// Dummy data
Finished: int64(1),
ExitCode: 137,
Error: "not an error",
}
proc, _ := UpdateProcStatus(&mockUpdateProcStore{}, model.Proc{}, state, int64(1))
if proc.State != model.StatusRunning {
t.Errorf("Proc status not equals '%s' != '%s'", model.StatusRunning, proc.State)
} else if proc.Started != int64(42) {
t.Errorf("Proc started not equals 42 != %d", proc.Started)
} else if proc.Stopped != int64(0) {
t.Errorf("Proc stopped not equals 0 != %d", proc.Stopped)
} else if proc.ExitCode != 0 {
t.Errorf("Proc exit code not equals 0 != %d", proc.ExitCode)
} else if proc.Error != "" {
t.Errorf("Proc error not equals '' != '%s'", proc.Error)
}
}
func TestUpdateProcStatusNotExitedButStopped(t *testing.T) {
t.Parallel()
proc := &model.Proc{Stopped: int64(64)}
state := rpc.State{
Exited: false,
// Dummy data
Finished: int64(1),
ExitCode: 137,
Error: "not an error",
}
proc, _ = UpdateProcStatus(&mockUpdateProcStore{}, *proc, state, int64(42))
if proc.State != model.StatusRunning {
t.Errorf("Proc status not equals '%s' != '%s'", model.StatusRunning, proc.State)
} else if proc.Started != int64(42) {
t.Errorf("Proc started not equals 42 != %d", proc.Started)
} else if proc.Stopped != int64(64) {
t.Errorf("Proc stopped not equals 64 != %d", proc.Stopped)
} else if proc.ExitCode != 0 {
t.Errorf("Proc exit code not equals 0 != %d", proc.ExitCode)
} else if proc.Error != "" {
t.Errorf("Proc error not equals '' != '%s'", proc.Error)
}
}
func TestUpdateProcStatusExited(t *testing.T) {
t.Parallel()
state := rpc.State{
Started: int64(42),
Exited: true,
Finished: int64(34),
ExitCode: 137,
Error: "an error",
}
proc, _ := UpdateProcStatus(&mockUpdateProcStore{}, model.Proc{}, state, int64(42))
if proc.State != model.StatusKilled {
t.Errorf("Proc status not equals '%s' != '%s'", model.StatusKilled, proc.State)
} else if proc.Started != int64(42) {
t.Errorf("Proc started not equals 42 != %d", proc.Started)
} else if proc.Stopped != int64(34) {
t.Errorf("Proc stopped not equals 34 != %d", proc.Stopped)
} else if proc.ExitCode != 137 {
t.Errorf("Proc exit code not equals 137 != %d", proc.ExitCode)
} else if proc.Error != "an error" {
t.Errorf("Proc error not equals 'an error' != '%s'", proc.Error)
}
}
func TestUpdateProcStatusExitedButNot137(t *testing.T) {
t.Parallel()
state := rpc.State{
Started: int64(42),
Exited: true,
Finished: int64(34),
Error: "an error",
}
proc, _ := UpdateProcStatus(&mockUpdateProcStore{}, model.Proc{}, state, int64(42))
if proc.State != model.StatusFailure {
t.Errorf("Proc status not equals '%s' != '%s'", model.StatusFailure, proc.State)
} else if proc.Started != int64(42) {
t.Errorf("Proc started not equals 42 != %d", proc.Started)
} else if proc.Stopped != int64(34) {
t.Errorf("Proc stopped not equals 34 != %d", proc.Stopped)
} else if proc.ExitCode != 0 {
t.Errorf("Proc exit code not equals 0 != %d", proc.ExitCode)
} else if proc.Error != "an error" {
t.Errorf("Proc error not equals 'an error' != '%s'", proc.Error)
}
}
func TestUpdateProcStatusExitedWithCode(t *testing.T) {
t.Parallel()
state := rpc.State{
Started: int64(42),
Exited: true,
Finished: int64(34),
ExitCode: 1,
Error: "an error",
}
proc, _ := UpdateProcStatus(&mockUpdateProcStore{}, model.Proc{}, state, int64(42))
if proc.State != model.StatusFailure {
t.Errorf("Proc status not equals '%s' != '%s'", model.StatusFailure, proc.State)
} else if proc.ExitCode != 1 {
t.Errorf("Proc exit code not equals 1 != %d", proc.ExitCode)
}
}
func TestUpdateProcToStatusStarted(t *testing.T) {
t.Parallel()
state := rpc.State{Started: int64(42)}
proc, _ := UpdateProcToStatusStarted(&mockUpdateProcStore{}, model.Proc{}, state)
if proc.State != model.StatusRunning {
t.Errorf("Proc status not equals '%s' != '%s'", model.StatusRunning, proc.State)
} else if proc.Started != int64(42) {
t.Errorf("Proc started not equals 42 != %d", proc.Started)
}
}
func TestUpdateProcToStatusSkipped(t *testing.T) {
t.Parallel()
proc, _ := UpdateProcToStatusSkipped(&mockUpdateProcStore{}, model.Proc{}, int64(1))
if proc.State != model.StatusSkipped {
t.Errorf("Proc status not equals '%s' != '%s'", model.StatusSkipped, proc.State)
} else if proc.Stopped != int64(0) {
t.Errorf("Proc stopped not equals 0 != %d", proc.Stopped)
}
}
func TestUpdateProcToStatusSkippedButStarted(t *testing.T) {
t.Parallel()
proc := &model.Proc{
Started: int64(42),
}
proc, _ = UpdateProcToStatusSkipped(&mockUpdateProcStore{}, *proc, int64(1))
if proc.State != model.StatusSuccess {
t.Errorf("Proc status not equals '%s' != '%s'", model.StatusSuccess, proc.State)
} else if proc.Stopped != int64(1) {
t.Errorf("Proc stopped not equals 1 != %d", proc.Stopped)
}
}
func TestUpdateProcStatusToDoneSkipped(t *testing.T) {
t.Parallel()
state := rpc.State{
Finished: int64(34),
}
proc, _ := UpdateProcStatusToDone(&mockUpdateProcStore{}, model.Proc{}, state)
if proc.State != model.StatusSkipped {
t.Errorf("Proc status not equals '%s' != '%s'", model.StatusSkipped, proc.State)
} else if proc.Stopped != int64(34) {
t.Errorf("Proc stopped not equals 34 != %d", proc.Stopped)
} else if proc.Error != "" {
t.Errorf("Proc error not equals '' != '%s'", proc.Error)
} else if proc.ExitCode != 0 {
t.Errorf("Proc exit code not equals 0 != %d", proc.ExitCode)
}
}
func TestUpdateProcStatusToDoneSuccess(t *testing.T) {
t.Parallel()
state := rpc.State{
Started: int64(42),
Finished: int64(34),
}
proc, _ := UpdateProcStatusToDone(&mockUpdateProcStore{}, model.Proc{}, state)
if proc.State != model.StatusSuccess {
t.Errorf("Proc status not equals '%s' != '%s'", model.StatusSuccess, proc.State)
} else if proc.Stopped != int64(34) {
t.Errorf("Proc stopped not equals 34 != %d", proc.Stopped)
} else if proc.Error != "" {
t.Errorf("Proc error not equals '' != '%s'", proc.Error)
} else if proc.ExitCode != 0 {
t.Errorf("Proc exit code not equals 0 != %d", proc.ExitCode)
}
}
func TestUpdateProcStatusToDoneFailureWithError(t *testing.T) {
t.Parallel()
state := rpc.State{Error: "an error"}
proc, _ := UpdateProcStatusToDone(&mockUpdateProcStore{}, model.Proc{}, state)
if proc.State != model.StatusFailure {
t.Errorf("Proc status not equals '%s' != '%s'", model.StatusFailure, proc.State)
}
}
func TestUpdateProcStatusToDoneFailureWithExitCode(t *testing.T) {
t.Parallel()
state := rpc.State{ExitCode: 43}
proc, _ := UpdateProcStatusToDone(&mockUpdateProcStore{}, model.Proc{}, state)
if proc.State != model.StatusFailure {
t.Errorf("Proc status not equals '%s' != '%s'", model.StatusFailure, proc.State)
}
}
func TestUpdateProcToStatusKilledStarted(t *testing.T) {
t.Parallel()
now := time.Now().Unix()
proc, _ := UpdateProcToStatusKilled(&mockUpdateProcStore{}, model.Proc{})
if proc.State != model.StatusKilled {
t.Errorf("Proc status not equals '%s' != '%s'", model.StatusKilled, proc.State)
} else if proc.Stopped < now {
t.Errorf("Proc stopped not equals %d < %d", now, proc.Stopped)
} else if proc.Started != proc.Stopped {
t.Errorf("Proc started not equals %d != %d", proc.Stopped, proc.Started)
} else if proc.ExitCode != 137 {
t.Errorf("Proc exit code not equals 137 != %d", proc.ExitCode)
}
}
func TestUpdateProcToStatusKilledNotStarted(t *testing.T) {
t.Parallel()
proc, _ := UpdateProcToStatusKilled(&mockUpdateProcStore{}, model.Proc{Started: int64(1)})
if proc.Started != int64(1) {
t.Errorf("Proc started not equals 1 != %d", proc.Started)
}
}

View file

@ -39,8 +39,8 @@ import (
// TODO(974) move to pipeline/*
// ProcBuilder Takes the hook data and the yaml and returns in internal data model
type ProcBuilder struct {
// StepBuilder Takes the hook data and the yaml and returns in internal data model
type StepBuilder struct {
Repo *model.Repo
Curr *model.Pipeline
Last *model.Pipeline
@ -53,7 +53,7 @@ type ProcBuilder struct {
}
type PipelineItem struct {
Proc *model.Proc
Step *model.Step
Platform string
Labels map[string]string
DependsOn []string
@ -61,7 +61,7 @@ type PipelineItem struct {
Config *backend.Config
}
func (b *ProcBuilder) Build() ([]*PipelineItem, error) {
func (b *StepBuilder) Build() ([]*PipelineItem, error) {
var items []*PipelineItem
sort.Sort(remote.ByName(b.Yamls))
@ -79,7 +79,7 @@ func (b *ProcBuilder) Build() ([]*PipelineItem, error) {
}
for _, axis := range axes {
proc := &model.Proc{
step := &model.Step{
PipelineID: b.Curr.ID,
PID: pidSequence,
PGID: pidSequence,
@ -88,7 +88,7 @@ func (b *ProcBuilder) Build() ([]*PipelineItem, error) {
Name: SanitizePath(y.Name),
}
metadata := metadataFromStruct(b.Repo, b.Curr, b.Last, proc, b.Link)
metadata := metadataFromStruct(b.Repo, b.Curr, b.Last, step, b.Link)
environ := b.environmentVariables(metadata, axis)
// add global environment variables for substituting
@ -121,12 +121,12 @@ func (b *ProcBuilder) Build() ([]*PipelineItem, error) {
// checking if filtered.
if match, err := parsed.When.Match(metadata, true); !match && err == nil {
log.Debug().Str("pipeline", proc.Name).Msg(
log.Debug().Str("pipeline", step.Name).Msg(
"Marked as skipped, dose not match metadata",
)
proc.State = model.StatusSkipped
step.State = model.StatusSkipped
} else if err != nil {
log.Debug().Str("pipeline", proc.Name).Msg(
log.Debug().Str("pipeline", step.Name).Msg(
"Pipeline config could not be parsed",
)
return nil, err
@ -134,13 +134,13 @@ func (b *ProcBuilder) Build() ([]*PipelineItem, error) {
// TODO: deprecated branches filter => remove after some time
if !parsed.Branches.Match(b.Curr.Branch) && (b.Curr.Event != model.EventDeploy && b.Curr.Event != model.EventTag) {
log.Debug().Str("pipeline", proc.Name).Msg(
log.Debug().Str("pipeline", step.Name).Msg(
"Marked as skipped, dose not match branch",
)
proc.State = model.StatusSkipped
step.State = model.StatusSkipped
}
ir, err := b.toInternalRepresentation(parsed, environ, metadata, proc.ID)
ir, err := b.toInternalRepresentation(parsed, environ, metadata, step.ID)
if err != nil {
return nil, err
}
@ -150,7 +150,7 @@ func (b *ProcBuilder) Build() ([]*PipelineItem, error) {
}
item := &PipelineItem{
Proc: proc,
Step: step,
Config: ir,
Labels: parsed.Labels,
DependsOn: parsed.DependsOn,
@ -168,17 +168,17 @@ func (b *ProcBuilder) Build() ([]*PipelineItem, error) {
items = filterItemsWithMissingDependencies(items)
// check if at least one proc can start, if list is not empty
if len(items) > 0 && !procListContainsItemsToRun(items) {
// check if at least one step can start, if list is not empty
if len(items) > 0 && !stepListContainsItemsToRun(items) {
return nil, fmt.Errorf("pipeline has no startpoint")
}
return items, nil
}
func procListContainsItemsToRun(items []*PipelineItem) bool {
func stepListContainsItemsToRun(items []*PipelineItem) bool {
for i := range items {
if items[i].Proc.State == model.StatusPending {
if items[i].Step.State == model.StatusPending {
return true
}
}
@ -199,7 +199,7 @@ func filterItemsWithMissingDependencies(items []*PipelineItem) []*PipelineItem {
if len(itemsToRemove) > 0 {
filtered := make([]*PipelineItem, 0)
for _, item := range items {
if !containsItemWithName(item.Proc.Name, itemsToRemove) {
if !containsItemWithName(item.Step.Name, itemsToRemove) {
filtered = append(filtered, item)
}
}
@ -212,14 +212,14 @@ func filterItemsWithMissingDependencies(items []*PipelineItem) []*PipelineItem {
func containsItemWithName(name string, items []*PipelineItem) bool {
for _, item := range items {
if name == item.Proc.Name {
if name == item.Step.Name {
return true
}
}
return false
}
func (b *ProcBuilder) envsubst(y string, environ map[string]string) (string, error) {
func (b *StepBuilder) envsubst(y string, environ map[string]string) (string, error) {
return envsubst.Eval(y, func(name string) string {
env := environ[name]
if strings.Contains(env, "\n") {
@ -229,7 +229,7 @@ func (b *ProcBuilder) envsubst(y string, environ map[string]string) (string, err
})
}
func (b *ProcBuilder) environmentVariables(metadata frontend.Metadata, axis matrix.Axis) map[string]string {
func (b *StepBuilder) environmentVariables(metadata frontend.Metadata, axis matrix.Axis) map[string]string {
environ := metadata.Environ()
for k, v := range axis {
environ[k] = v
@ -237,7 +237,7 @@ func (b *ProcBuilder) environmentVariables(metadata frontend.Metadata, axis matr
return environ
}
func (b *ProcBuilder) toInternalRepresentation(parsed *yaml.Config, environ map[string]string, metadata frontend.Metadata, procID int64) (*backend.Config, error) {
func (b *StepBuilder) toInternalRepresentation(parsed *yaml.Config, environ map[string]string, metadata frontend.Metadata, stepID int64) (*backend.Config, error) {
var secrets []compiler.Secret
for _, sec := range b.Secs {
if !sec.Match(b.Curr.Event) {
@ -283,7 +283,7 @@ func (b *ProcBuilder) toInternalRepresentation(parsed *yaml.Config, environ map[
compiler.WithPrefix(
fmt.Sprintf(
"wp_%d_%d",
procID,
stepID,
rand.Int(),
),
),
@ -296,9 +296,9 @@ func (b *ProcBuilder) toInternalRepresentation(parsed *yaml.Config, environ map[
func SetPipelineStepsOnPipeline(pipeline *model.Pipeline, pipelineItems []*PipelineItem) *model.Pipeline {
var pidSequence int
for _, item := range pipelineItems {
pipeline.Procs = append(pipeline.Procs, item.Proc)
if pidSequence < item.Proc.PID {
pidSequence = item.Proc.PID
pipeline.Steps = append(pipeline.Steps, item.Step)
if pidSequence < item.Step.PID {
pidSequence = item.Step.PID
}
}
@ -310,18 +310,18 @@ func SetPipelineStepsOnPipeline(pipeline *model.Pipeline, pipelineItems []*Pipel
if gid == 0 {
gid = pidSequence
}
proc := &model.Proc{
step := &model.Step{
PipelineID: pipeline.ID,
Name: step.Alias,
PID: pidSequence,
PPID: item.Proc.PID,
PPID: item.Step.PID,
PGID: gid,
State: model.StatusPending,
}
if item.Proc.State == model.StatusSkipped {
proc.State = model.StatusSkipped
if item.Step.State == model.StatusSkipped {
step.State = model.StatusSkipped
}
pipeline.Procs = append(pipeline.Procs, proc)
pipeline.Steps = append(pipeline.Steps, step)
}
}
}
@ -330,7 +330,7 @@ func SetPipelineStepsOnPipeline(pipeline *model.Pipeline, pipelineItems []*Pipel
}
// return the metadata from the cli context.
func metadataFromStruct(repo *model.Repo, pipeline, last *model.Pipeline, proc *model.Proc, link string) frontend.Metadata {
func metadataFromStruct(repo *model.Repo, pipeline, last *model.Pipeline, step *model.Step, link string) frontend.Metadata {
host := link
uri, err := url.Parse(link)
if err == nil {
@ -346,9 +346,9 @@ func metadataFromStruct(repo *model.Repo, pipeline, last *model.Pipeline, proc *
},
Curr: metadataPipelineFromModelPipeline(pipeline, true),
Prev: metadataPipelineFromModelPipeline(last, false),
Job: frontend.Job{
Number: proc.PID,
Matrix: proc.Environ,
Step: frontend.Step{
Number: step.PID,
Matrix: step.Environ,
},
Sys: frontend.System{
Name: "woodpecker",

View file

@ -28,7 +28,7 @@ import (
func TestGlobalEnvsubst(t *testing.T) {
t.Parallel()
b := ProcBuilder{
b := StepBuilder{
Envs: map[string]string{
"KEY_K": "VALUE_V",
"IMAGE": "scratch",
@ -62,7 +62,7 @@ pipeline:
func TestMissingGlobalEnvsubst(t *testing.T) {
t.Parallel()
b := ProcBuilder{
b := StepBuilder{
Envs: map[string]string{
"KEY_K": "VALUE_V",
"NO_IMAGE": "scratch",
@ -96,7 +96,7 @@ pipeline:
func TestMultilineEnvsubst(t *testing.T) {
t.Parallel()
b := ProcBuilder{
b := StepBuilder{
Repo: &model.Repo{},
Curr: &model.Pipeline{
Message: `aaa
@ -133,7 +133,7 @@ pipeline:
func TestMultiPipeline(t *testing.T) {
t.Parallel()
b := ProcBuilder{
b := StepBuilder{
Repo: &model.Repo{},
Curr: &model.Pipeline{},
Last: &model.Pipeline{},
@ -167,7 +167,7 @@ pipeline:
func TestDependsOn(t *testing.T) {
t.Parallel()
b := ProcBuilder{
b := StepBuilder{
Repo: &model.Repo{},
Curr: &model.Pipeline{},
Last: &model.Pipeline{},
@ -213,7 +213,7 @@ depends_on:
func TestRunsOn(t *testing.T) {
t.Parallel()
b := ProcBuilder{
b := StepBuilder{
Repo: &model.Repo{},
Curr: &model.Pipeline{},
Last: &model.Pipeline{},
@ -249,7 +249,7 @@ runs_on:
func TestPipelineName(t *testing.T) {
t.Parallel()
b := ProcBuilder{
b := StepBuilder{
Repo: &model.Repo{Config: ".woodpecker"},
Curr: &model.Pipeline{},
Last: &model.Pipeline{},
@ -275,7 +275,7 @@ pipeline:
if err != nil {
t.Fatal(err)
}
pipelineNames := []string{pipelineItems[0].Proc.Name, pipelineItems[1].Proc.Name}
pipelineNames := []string{pipelineItems[0].Step.Name, pipelineItems[1].Step.Name}
if !containsItemWithName("lint", pipelineItems) || !containsItemWithName("test", pipelineItems) {
t.Fatalf("Pipeline name should be 'lint' and 'test' but are '%v'", pipelineNames)
}
@ -284,7 +284,7 @@ pipeline:
func TestBranchFilter(t *testing.T) {
t.Parallel()
b := ProcBuilder{
b := StepBuilder{
Repo: &model.Repo{},
Curr: &model.Pipeline{Branch: "dev"},
Last: &model.Pipeline{},
@ -314,15 +314,15 @@ pipeline:
if len(pipelineItems) != 2 {
t.Fatal("Should have generated 2 pipeline")
}
if pipelineItems[0].Proc.State != model.StatusSkipped {
if pipelineItems[0].Step.State != model.StatusSkipped {
t.Fatal("Should not run on dev branch")
}
for _, child := range pipelineItems[0].Proc.Children {
for _, child := range pipelineItems[0].Step.Children {
if child.State != model.StatusSkipped {
t.Fatal("Children should skipped status too")
}
}
if pipelineItems[1].Proc.State != model.StatusPending {
if pipelineItems[1].Step.State != model.StatusPending {
t.Fatal("Should run on dev branch")
}
}
@ -330,7 +330,7 @@ pipeline:
func TestRootWhenFilter(t *testing.T) {
t.Parallel()
b := ProcBuilder{
b := StepBuilder{
Repo: &model.Repo{},
Curr: &model.Pipeline{Event: "tester"},
Last: &model.Pipeline{},
@ -378,7 +378,7 @@ func TestZeroSteps(t *testing.T) {
pipeline := &model.Pipeline{Branch: "dev"}
b := ProcBuilder{
b := StepBuilder{
Repo: &model.Repo{},
Curr: pipeline,
Last: &model.Pipeline{},
@ -412,7 +412,7 @@ func TestZeroStepsAsMultiPipelineDeps(t *testing.T) {
pipeline := &model.Pipeline{Branch: "dev"}
b := ProcBuilder{
b := StepBuilder{
Repo: &model.Repo{},
Curr: pipeline,
Last: &model.Pipeline{},
@ -450,7 +450,7 @@ depends_on: [ zerostep ]
if len(pipelineItems) != 1 {
t.Fatal("Zerostep and the step that depends on it should not generate a pipeline item")
}
if pipelineItems[0].Proc.Name != "justastep" {
if pipelineItems[0].Step.Name != "justastep" {
t.Fatal("justastep should have been generated")
}
}
@ -460,7 +460,7 @@ func TestZeroStepsAsMultiPipelineTransitiveDeps(t *testing.T) {
pipeline := &model.Pipeline{Branch: "dev"}
b := ProcBuilder{
b := StepBuilder{
Repo: &model.Repo{},
Curr: pipeline,
Last: &model.Pipeline{},
@ -504,7 +504,7 @@ depends_on: [ shouldbefiltered ]
if len(pipelineItems) != 1 {
t.Fatal("Zerostep and the step that depends on it, and the one depending on it should not generate a pipeline item")
}
if pipelineItems[0].Proc.Name != "justastep" {
if pipelineItems[0].Step.Name != "justastep" {
t.Fatal("justastep should have been generated")
}
}
@ -516,7 +516,7 @@ func TestTree(t *testing.T) {
Event: model.EventPush,
}
b := ProcBuilder{
b := StepBuilder{
Repo: &model.Repo{},
Curr: pipeline,
Last: &model.Pipeline{},
@ -538,13 +538,13 @@ pipeline:
if err != nil {
t.Fatal(err)
}
if len(pipeline.Procs) != 3 {
if len(pipeline.Steps) != 3 {
t.Fatal("Should generate three in total")
}
if pipeline.Procs[1].PPID != 1 {
if pipeline.Steps[1].PPID != 1 {
t.Fatal("Clone step should be a children of the stage")
}
if pipeline.Procs[2].PPID != 1 {
if pipeline.Steps[2].PPID != 1 {
t.Fatal("Pipeline step should be a children of the stage")
}
}

View file

@ -0,0 +1,88 @@
// Copyright 2022 Woodpecker Authors
// Copyright 2019 mhmxs
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package shared
import (
"time"
"github.com/woodpecker-ci/woodpecker/pipeline/rpc"
"github.com/woodpecker-ci/woodpecker/server/model"
)
// TODO(974) move to server/pipeline/*
func UpdateStepStatus(store model.UpdateStepStore, step model.Step, state rpc.State, started int64) (*model.Step, error) {
if state.Exited {
step.Stopped = state.Finished
step.ExitCode = state.ExitCode
step.Error = state.Error
step.State = model.StatusSuccess
if state.ExitCode != 0 || state.Error != "" {
step.State = model.StatusFailure
}
if state.ExitCode == 137 {
step.State = model.StatusKilled
}
} else {
step.Started = state.Started
step.State = model.StatusRunning
}
if step.Started == 0 && step.Stopped != 0 {
step.Started = started
}
return &step, store.StepUpdate(&step)
}
func UpdateStepToStatusStarted(store model.UpdateStepStore, step model.Step, state rpc.State) (*model.Step, error) {
step.Started = state.Started
step.State = model.StatusRunning
return &step, store.StepUpdate(&step)
}
func UpdateStepToStatusSkipped(store model.UpdateStepStore, step model.Step, stopped int64) (*model.Step, error) {
step.State = model.StatusSkipped
if step.Started != 0 {
step.State = model.StatusSuccess // for daemons that are killed
step.Stopped = stopped
}
return &step, store.StepUpdate(&step)
}
func UpdateStepStatusToDone(store model.UpdateStepStore, step model.Step, state rpc.State) (*model.Step, error) {
step.Stopped = state.Finished
step.Error = state.Error
step.ExitCode = state.ExitCode
if state.Started == 0 {
step.State = model.StatusSkipped
} else {
step.State = model.StatusSuccess
}
if step.ExitCode != 0 || step.Error != "" {
step.State = model.StatusFailure
}
return &step, store.StepUpdate(&step)
}
func UpdateStepToStatusKilled(store model.UpdateStepStore, step model.Step) (*model.Step, error) {
step.State = model.StatusKilled
step.Stopped = time.Now().Unix()
if step.Started == 0 {
step.Started = step.Stopped
}
step.ExitCode = 137
return &step, store.StepUpdate(&step)
}

View file

@ -0,0 +1,287 @@
// Copyright 2022 Woodpecker Authors
// Copyright 2019 mhmxs
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package shared
import (
"testing"
"time"
"github.com/woodpecker-ci/woodpecker/pipeline/rpc"
"github.com/woodpecker-ci/woodpecker/server/model"
)
// TODO(974) move to server/pipeline/*
type mockUpdateStepStore struct{}
func (m *mockUpdateStepStore) StepUpdate(build *model.Step) error {
return nil
}
func TestUpdateStepStatusNotExited(t *testing.T) {
t.Parallel()
state := rpc.State{
Started: int64(42),
Exited: false,
// Dummy data
Finished: int64(1),
ExitCode: 137,
Error: "not an error",
}
step, _ := UpdateStepStatus(&mockUpdateStepStore{}, model.Step{}, state, int64(1))
if step.State != model.StatusRunning {
t.Errorf("Step status not equals '%s' != '%s'", model.StatusRunning, step.State)
} else if step.Started != int64(42) {
t.Errorf("Step started not equals 42 != %d", step.Started)
} else if step.Stopped != int64(0) {
t.Errorf("Step stopped not equals 0 != %d", step.Stopped)
} else if step.ExitCode != 0 {
t.Errorf("Step exit code not equals 0 != %d", step.ExitCode)
} else if step.Error != "" {
t.Errorf("Step error not equals '' != '%s'", step.Error)
}
}
func TestUpdateStepStatusNotExitedButStopped(t *testing.T) {
t.Parallel()
step := &model.Step{Stopped: int64(64)}
state := rpc.State{
Exited: false,
// Dummy data
Finished: int64(1),
ExitCode: 137,
Error: "not an error",
}
step, _ = UpdateStepStatus(&mockUpdateStepStore{}, *step, state, int64(42))
if step.State != model.StatusRunning {
t.Errorf("Step status not equals '%s' != '%s'", model.StatusRunning, step.State)
} else if step.Started != int64(42) {
t.Errorf("Step started not equals 42 != %d", step.Started)
} else if step.Stopped != int64(64) {
t.Errorf("Step stopped not equals 64 != %d", step.Stopped)
} else if step.ExitCode != 0 {
t.Errorf("Step exit code not equals 0 != %d", step.ExitCode)
} else if step.Error != "" {
t.Errorf("Step error not equals '' != '%s'", step.Error)
}
}
func TestUpdateStepStatusExited(t *testing.T) {
t.Parallel()
state := rpc.State{
Started: int64(42),
Exited: true,
Finished: int64(34),
ExitCode: 137,
Error: "an error",
}
step, _ := UpdateStepStatus(&mockUpdateStepStore{}, model.Step{}, state, int64(42))
if step.State != model.StatusKilled {
t.Errorf("Step status not equals '%s' != '%s'", model.StatusKilled, step.State)
} else if step.Started != int64(42) {
t.Errorf("Step started not equals 42 != %d", step.Started)
} else if step.Stopped != int64(34) {
t.Errorf("Step stopped not equals 34 != %d", step.Stopped)
} else if step.ExitCode != 137 {
t.Errorf("Step exit code not equals 137 != %d", step.ExitCode)
} else if step.Error != "an error" {
t.Errorf("Step error not equals 'an error' != '%s'", step.Error)
}
}
func TestUpdateStepStatusExitedButNot137(t *testing.T) {
t.Parallel()
state := rpc.State{
Started: int64(42),
Exited: true,
Finished: int64(34),
Error: "an error",
}
step, _ := UpdateStepStatus(&mockUpdateStepStore{}, model.Step{}, state, int64(42))
if step.State != model.StatusFailure {
t.Errorf("Step status not equals '%s' != '%s'", model.StatusFailure, step.State)
} else if step.Started != int64(42) {
t.Errorf("Step started not equals 42 != %d", step.Started)
} else if step.Stopped != int64(34) {
t.Errorf("Step stopped not equals 34 != %d", step.Stopped)
} else if step.ExitCode != 0 {
t.Errorf("Step exit code not equals 0 != %d", step.ExitCode)
} else if step.Error != "an error" {
t.Errorf("Step error not equals 'an error' != '%s'", step.Error)
}
}
func TestUpdateStepStatusExitedWithCode(t *testing.T) {
t.Parallel()
state := rpc.State{
Started: int64(42),
Exited: true,
Finished: int64(34),
ExitCode: 1,
Error: "an error",
}
step, _ := UpdateStepStatus(&mockUpdateStepStore{}, model.Step{}, state, int64(42))
if step.State != model.StatusFailure {
t.Errorf("Step status not equals '%s' != '%s'", model.StatusFailure, step.State)
} else if step.ExitCode != 1 {
t.Errorf("Step exit code not equals 1 != %d", step.ExitCode)
}
}
func TestUpdateStepPToStatusStarted(t *testing.T) {
t.Parallel()
state := rpc.State{Started: int64(42)}
step, _ := UpdateStepToStatusStarted(&mockUpdateStepStore{}, model.Step{}, state)
if step.State != model.StatusRunning {
t.Errorf("Step status not equals '%s' != '%s'", model.StatusRunning, step.State)
} else if step.Started != int64(42) {
t.Errorf("Step started not equals 42 != %d", step.Started)
}
}
func TestUpdateStepToStatusSkipped(t *testing.T) {
t.Parallel()
step, _ := UpdateStepToStatusSkipped(&mockUpdateStepStore{}, model.Step{}, int64(1))
if step.State != model.StatusSkipped {
t.Errorf("Step status not equals '%s' != '%s'", model.StatusSkipped, step.State)
} else if step.Stopped != int64(0) {
t.Errorf("Step stopped not equals 0 != %d", step.Stopped)
}
}
func TestUpdateStepToStatusSkippedButStarted(t *testing.T) {
t.Parallel()
step := &model.Step{
Started: int64(42),
}
step, _ = UpdateStepToStatusSkipped(&mockUpdateStepStore{}, *step, int64(1))
if step.State != model.StatusSuccess {
t.Errorf("Step status not equals '%s' != '%s'", model.StatusSuccess, step.State)
} else if step.Stopped != int64(1) {
t.Errorf("Step stopped not equals 1 != %d", step.Stopped)
}
}
func TestUpdateStepStatusToDoneSkipped(t *testing.T) {
t.Parallel()
state := rpc.State{
Finished: int64(34),
}
step, _ := UpdateStepStatusToDone(&mockUpdateStepStore{}, model.Step{}, state)
if step.State != model.StatusSkipped {
t.Errorf("Step status not equals '%s' != '%s'", model.StatusSkipped, step.State)
} else if step.Stopped != int64(34) {
t.Errorf("Step stopped not equals 34 != %d", step.Stopped)
} else if step.Error != "" {
t.Errorf("Step error not equals '' != '%s'", step.Error)
} else if step.ExitCode != 0 {
t.Errorf("Step exit code not equals 0 != %d", step.ExitCode)
}
}
func TestUpdateStepStatusToDoneSuccess(t *testing.T) {
t.Parallel()
state := rpc.State{
Started: int64(42),
Finished: int64(34),
}
step, _ := UpdateStepStatusToDone(&mockUpdateStepStore{}, model.Step{}, state)
if step.State != model.StatusSuccess {
t.Errorf("Step status not equals '%s' != '%s'", model.StatusSuccess, step.State)
} else if step.Stopped != int64(34) {
t.Errorf("Step stopped not equals 34 != %d", step.Stopped)
} else if step.Error != "" {
t.Errorf("Step error not equals '' != '%s'", step.Error)
} else if step.ExitCode != 0 {
t.Errorf("Step exit code not equals 0 != %d", step.ExitCode)
}
}
func TestUpdateStepStatusToDoneFailureWithError(t *testing.T) {
t.Parallel()
state := rpc.State{Error: "an error"}
step, _ := UpdateStepStatusToDone(&mockUpdateStepStore{}, model.Step{}, state)
if step.State != model.StatusFailure {
t.Errorf("Step status not equals '%s' != '%s'", model.StatusFailure, step.State)
}
}
func TestUpdateStepStatusToDoneFailureWithExitCode(t *testing.T) {
t.Parallel()
state := rpc.State{ExitCode: 43}
step, _ := UpdateStepStatusToDone(&mockUpdateStepStore{}, model.Step{}, state)
if step.State != model.StatusFailure {
t.Errorf("Step status not equals '%s' != '%s'", model.StatusFailure, step.State)
}
}
func TestUpdateStepToStatusKilledStarted(t *testing.T) {
t.Parallel()
now := time.Now().Unix()
step, _ := UpdateStepToStatusKilled(&mockUpdateStepStore{}, model.Step{})
if step.State != model.StatusKilled {
t.Errorf("Step status not equals '%s' != '%s'", model.StatusKilled, step.State)
} else if step.Stopped < now {
t.Errorf("Step stopped not equals %d < %d", now, step.Stopped)
} else if step.Started != step.Stopped {
t.Errorf("Step started not equals %d != %d", step.Stopped, step.Started)
} else if step.ExitCode != 137 {
t.Errorf("Step exit code not equals 137 != %d", step.ExitCode)
}
}
func TestUpdateStepToStatusKilledNotStarted(t *testing.T) {
t.Parallel()
step, _ := UpdateStepToStatusKilled(&mockUpdateStepStore{}, model.Step{Started: int64(1)})
if step.Started != int64(1) {
t.Errorf("Step started not equals 1 != %d", step.Started)
}
}

View file

@ -200,7 +200,7 @@ func TestConfigApproved(t *testing.T) {
}
func TestConfigIndexes(t *testing.T) {
store, closer := newTestStore(t, new(model.Config), new(model.Proc), new(model.Pipeline), new(model.Repo))
store, closer := newTestStore(t, new(model.Config), new(model.Step), new(model.Pipeline), new(model.Repo))
defer closer()
var (

View file

@ -26,16 +26,16 @@ func (s storage) FileList(pipeline *model.Pipeline) ([]*model.File, error) {
return files, s.engine.Where("file_pipeline_id = ?", pipeline.ID).Find(&files)
}
func (s storage) FileFind(proc *model.Proc, name string) (*model.File, error) {
func (s storage) FileFind(step *model.Step, name string) (*model.File, error) {
file := &model.File{
ProcID: proc.ID,
StepID: step.ID,
Name: name,
}
return file, wrapGet(s.engine.Get(file))
}
func (s storage) FileRead(proc *model.Proc, name string) (io.ReadCloser, error) {
file, err := s.FileFind(proc, name)
func (s storage) FileRead(step *model.Step, name string) (io.ReadCloser, error) {
file, err := s.FileFind(step, name)
if err != nil {
return nil, err
}

View file

@ -25,13 +25,13 @@ import (
)
func TestFileFind(t *testing.T) {
store, closer := newTestStore(t, new(model.File), new(model.Proc))
store, closer := newTestStore(t, new(model.File), new(model.Step))
defer closer()
if err := store.FileCreate(
&model.File{
PipelineID: 2,
ProcID: 1,
StepID: 1,
Name: "hello.txt",
Mime: "text/plain",
Size: 11,
@ -42,7 +42,7 @@ func TestFileFind(t *testing.T) {
return
}
file, err := store.FileFind(&model.Proc{ID: 1}, "hello.txt")
file, err := store.FileFind(&model.Step{ID: 1}, "hello.txt")
if err != nil {
t.Error(err)
return
@ -53,8 +53,8 @@ func TestFileFind(t *testing.T) {
if got, want := file.PipelineID, int64(2); got != want {
t.Errorf("Want file pipeline id %d, got %d", want, got)
}
if got, want := file.ProcID, int64(1); got != want {
t.Errorf("Want file proc id %d, got %d", want, got)
if got, want := file.StepID, int64(1); got != want {
t.Errorf("Want file step id %d, got %d", want, got)
}
if got, want := file.Name, "hello.txt"; got != want {
t.Errorf("Want file name %s, got %s", want, got)
@ -66,7 +66,7 @@ func TestFileFind(t *testing.T) {
t.Errorf("Want file size %d, got %d", want, got)
}
rc, err := store.FileRead(&model.Proc{ID: 1}, "hello.txt")
rc, err := store.FileRead(&model.Step{ID: 1}, "hello.txt")
if err != nil {
t.Error(err)
return
@ -84,7 +84,7 @@ func TestFileList(t *testing.T) {
assert.NoError(t, store.FileCreate(
&model.File{
PipelineID: 1,
ProcID: 1,
StepID: 1,
Name: "hello.txt",
Mime: "text/plain",
Size: 11,
@ -94,7 +94,7 @@ func TestFileList(t *testing.T) {
assert.NoError(t, store.FileCreate(
&model.File{
PipelineID: 1,
ProcID: 1,
StepID: 1,
Name: "hola.txt",
Mime: "text/plain",
Size: 11,
@ -120,7 +120,7 @@ func TestFileIndexes(t *testing.T) {
if err := store.FileCreate(
&model.File{
PipelineID: 1,
ProcID: 1,
StepID: 1,
Name: "hello.txt",
Size: 11,
Mime: "text/plain",
@ -135,7 +135,7 @@ func TestFileIndexes(t *testing.T) {
if err := store.FileCreate(
&model.File{
PipelineID: 1,
ProcID: 1,
StepID: 1,
Name: "hello.txt",
Mime: "text/plain",
Size: 11,
@ -147,23 +147,23 @@ func TestFileIndexes(t *testing.T) {
}
func TestFileCascade(t *testing.T) {
store, closer := newTestStore(t, new(model.File), new(model.Proc), new(model.Pipeline))
store, closer := newTestStore(t, new(model.File), new(model.Step), new(model.Pipeline))
defer closer()
procOne := &model.Proc{
stepOne := &model.Step{
PipelineID: 1,
PID: 1,
PGID: 1,
Name: "build",
State: "success",
}
err1 := store.ProcCreate([]*model.Proc{procOne})
assert.EqualValues(t, int64(1), procOne.ID)
err1 := store.StepCreate([]*model.Step{stepOne})
assert.EqualValues(t, int64(1), stepOne.ID)
err2 := store.FileCreate(
&model.File{
PipelineID: 1,
ProcID: 1,
StepID: 1,
Name: "hello.txt",
Mime: "text/plain",
Size: 11,
@ -172,19 +172,19 @@ func TestFileCascade(t *testing.T) {
)
if err1 != nil {
t.Errorf("Unexpected error: cannot insert proc: %s", err1)
t.Errorf("Unexpected error: cannot insert step: %s", err1)
} else if err2 != nil {
t.Errorf("Unexpected error: cannot insert file: %s", err2)
}
if _, err3 := store.ProcFind(&model.Pipeline{ID: 1}, 1); err3 != nil {
t.Errorf("Unexpected error: cannot get inserted proc: %s", err3)
if _, err3 := store.StepFind(&model.Pipeline{ID: 1}, 1); err3 != nil {
t.Errorf("Unexpected error: cannot get inserted step: %s", err3)
}
err := store.ProcClear(&model.Pipeline{ID: 1, Procs: []*model.Proc{procOne}})
err := store.StepClear(&model.Pipeline{ID: 1, Steps: []*model.Step{stepOne}})
assert.NoError(t, err)
file, err4 := store.FileFind(&model.Proc{ID: 1}, "hello.txt")
file, err4 := store.FileFind(&model.Step{ID: 1}, "hello.txt")
if err4 == nil {
t.Errorf("Expected no rows in result set error")
t.Log(file)

View file

@ -21,9 +21,9 @@ import (
"github.com/woodpecker-ci/woodpecker/server/model"
)
func (s storage) LogFind(proc *model.Proc) (io.ReadCloser, error) {
func (s storage) LogFind(step *model.Step) (io.ReadCloser, error) {
logs := &model.Logs{
ProcID: proc.ID,
StepID: step.ID,
}
if err := wrapGet(s.engine.Get(logs)); err != nil {
return nil, err
@ -32,7 +32,7 @@ func (s storage) LogFind(proc *model.Proc) (io.ReadCloser, error) {
return io.NopCloser(buf), nil
}
func (s storage) LogSave(proc *model.Proc, reader io.Reader) error {
func (s storage) LogSave(step *model.Step, reader io.Reader) error {
data, _ := io.ReadAll(reader)
sess := s.engine.NewSession()
@ -42,7 +42,7 @@ func (s storage) LogSave(proc *model.Proc, reader io.Reader) error {
}
logs := new(model.Logs)
exist, err := sess.Where("log_job_id = ?", proc.ID).Get(logs)
exist, err := sess.Where("log_step_id = ?", step.ID).Get(logs)
if err != nil {
return err
}
@ -53,7 +53,7 @@ func (s storage) LogSave(proc *model.Proc, reader io.Reader) error {
}
} else {
if _, err := sess.Insert(&model.Logs{
ProcID: proc.ID,
StepID: step.ID,
Data: data,
}); err != nil {
return err

View file

@ -23,19 +23,19 @@ import (
)
func TestLogCreateFind(t *testing.T) {
store, closer := newTestStore(t, new(model.Proc), new(model.Logs))
store, closer := newTestStore(t, new(model.Step), new(model.Logs))
defer closer()
proc := model.Proc{
step := model.Step{
ID: 1,
}
buf := bytes.NewBufferString("echo hi")
err := store.LogSave(&proc, buf)
err := store.LogSave(&step, buf)
if err != nil {
t.Errorf("Unexpected error: log create: %s", err)
}
rc, err := store.LogFind(&proc)
rc, err := store.LogFind(&step)
if err != nil {
t.Errorf("Unexpected error: log create: %s", err)
}
@ -48,16 +48,16 @@ func TestLogCreateFind(t *testing.T) {
}
func TestLogUpdate(t *testing.T) {
store, closer := newTestStore(t, new(model.Proc), new(model.Logs))
store, closer := newTestStore(t, new(model.Step), new(model.Logs))
defer closer()
proc := model.Proc{
step := model.Step{
ID: 1,
}
buf1 := bytes.NewBufferString("echo hi")
buf2 := bytes.NewBufferString("echo allo?")
err1 := store.LogSave(&proc, buf1)
err2 := store.LogSave(&proc, buf2)
err1 := store.LogSave(&step, buf1)
err2 := store.LogSave(&step, buf2)
if err1 != nil {
t.Errorf("Unexpected error: log create: %s", err1)
}
@ -65,7 +65,7 @@ func TestLogUpdate(t *testing.T) {
t.Errorf("Unexpected error: log update: %s", err2)
}
rc, err := store.LogFind(&proc)
rc, err := store.LogFind(&step)
if err != nil {
t.Errorf("Unexpected error: log create: %s", err)
}

View file

@ -20,7 +20,7 @@ import (
"xorm.io/xorm"
)
type oldBuildColumn struct {
type oldTable struct {
table string
columns []string
}
@ -29,9 +29,9 @@ var renameColumnsBuildsToPipeline = task{
name: "rename-columns-builds-to-pipeline",
required: true,
fn: func(sess *xorm.Session) error {
var oldColumns []*oldBuildColumn
var oldColumns []*oldTable
oldColumns = append(oldColumns, &oldBuildColumn{
oldColumns = append(oldColumns, &oldTable{
table: "pipelines",
columns: []string{
"build_id",
@ -68,17 +68,17 @@ var renameColumnsBuildsToPipeline = task{
},
)
oldColumns = append(oldColumns, &oldBuildColumn{
oldColumns = append(oldColumns, &oldTable{
table: "pipeline_config",
columns: []string{"build_id"},
})
oldColumns = append(oldColumns, &oldBuildColumn{
oldColumns = append(oldColumns, &oldTable{
table: "files",
columns: []string{"file_build_id"},
})
oldColumns = append(oldColumns, &oldBuildColumn{
oldColumns = append(oldColumns, &oldTable{
table: "procs",
columns: []string{"proc_build_id"},
})

View file

@ -0,0 +1,87 @@
// Copyright 2022 Woodpecker Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package migration
import (
"strings"
"xorm.io/xorm"
)
var renameTableProcsToSteps = task{
name: "rename-procs-to-steps",
required: true,
fn: func(sess *xorm.Session) error {
err := renameTable(sess, "procs", "steps")
if err != nil {
return err
}
oldProcColumns := []*oldTable{
{
table: "steps",
columns: []string{
"proc_id",
"proc_pipeline_id",
"proc_pid",
"proc_ppid",
"proc_pgid",
"proc_name",
"proc_state",
"proc_error",
"proc_exit_code",
"proc_started",
"proc_stopped",
"proc_machine",
"proc_platform",
"proc_environ",
},
},
{
table: "files",
columns: []string{"file_proc_id"},
},
}
for _, table := range oldProcColumns {
for _, column := range table.columns {
err := renameColumn(sess, table.table, column, strings.Replace(column, "proc_", "step_", 1))
if err != nil {
return err
}
}
}
oldJobColumns := []*oldTable{
{
table: "logs",
columns: []string{
"log_job_id",
},
},
}
for _, table := range oldJobColumns {
for _, column := range table.columns {
err := renameColumn(sess, table.table, column, strings.Replace(column, "job_", "step_", 1))
if err != nil {
return err
}
}
}
return nil
},
}

View file

@ -38,6 +38,7 @@ var migrationTasks = []*task{
&lowercaseSecretNames,
&renameBuildsToPipeline,
&renameColumnsBuildsToPipeline,
&renameTableProcsToSteps,
}
var allBeans = []interface{}{
@ -48,7 +49,7 @@ var allBeans = []interface{}{
new(model.File),
new(model.Logs),
new(model.Perm),
new(model.Proc),
new(model.Step),
new(model.Registry),
new(model.Repo),
new(model.Secret),

View file

@ -97,7 +97,7 @@ func (s storage) GetPipelineCount() (int64, error) {
return s.engine.Count(new(model.Pipeline))
}
func (s storage) CreatePipeline(pipeline *model.Pipeline, procList ...*model.Proc) error {
func (s storage) CreatePipeline(pipeline *model.Pipeline, stepList ...*model.Step) error {
sess := s.engine.NewSession()
defer sess.Close()
if err := sess.Begin(); err != nil {
@ -127,10 +127,10 @@ func (s storage) CreatePipeline(pipeline *model.Pipeline, procList ...*model.Pro
return err
}
for i := range procList {
procList[i].PipelineID = pipeline.ID
for i := range stepList {
stepList[i].PipelineID = pipeline.ID
// only Insert set auto created ID back to object
if _, err := sess.Insert(procList[i]); err != nil {
if _, err := sess.Insert(stepList[i]); err != nil {
return err
}
}
@ -144,18 +144,18 @@ func (s storage) UpdatePipeline(pipeline *model.Pipeline) error {
}
func deletePipeline(sess *xorm.Session, pipelineID int64) error {
// delete related procs
for startProcs := 0; ; startProcs += perPage {
procIDs := make([]int64, 0, perPage)
if err := sess.Limit(perPage, startProcs).Table("procs").Cols("proc_id").Where("proc_pipeline_id = ?", pipelineID).Find(&procIDs); err != nil {
// delete related steps
for startSteps := 0; ; startSteps += perPage {
stepIDs := make([]int64, 0, perPage)
if err := sess.Limit(perPage, startSteps).Table("steps").Cols("step_id").Where("step_pipeline_id = ?", pipelineID).Find(&stepIDs); err != nil {
return err
}
if len(procIDs) == 0 {
if len(stepIDs) == 0 {
break
}
for i := range procIDs {
if err := deleteProc(sess, procIDs[i]); err != nil {
for i := range stepIDs {
if err := deleteStep(sess, stepIDs[i]); err != nil {
return err
}
}

View file

@ -33,7 +33,7 @@ func TestPipelines(t *testing.T) {
Name: "test",
}
store, closer := newTestStore(t, new(model.Repo), new(model.Proc), new(model.Pipeline))
store, closer := newTestStore(t, new(model.Repo), new(model.Step), new(model.Pipeline))
defer closer()
g := goblin.Goblin(t)
@ -53,7 +53,7 @@ func TestPipelines(t *testing.T) {
g.BeforeEach(func() {
_, err := store.engine.Exec("DELETE FROM pipelines")
g.Assert(err).IsNil()
_, err = store.engine.Exec("DELETE FROM procs")
_, err = store.engine.Exec("DELETE FROM steps")
g.Assert(err).IsNil()
})
@ -114,7 +114,7 @@ func TestPipelines(t *testing.T) {
RepoID: repo.ID,
Status: model.StatusSuccess,
}
err := store.CreatePipeline(&pipeline, []*model.Proc{}...)
err := store.CreatePipeline(&pipeline, []*model.Step{}...)
g.Assert(err).IsNil()
GetPipeline, err := store.GetPipeline(pipeline.ID)
g.Assert(err).IsNil()
@ -132,9 +132,9 @@ func TestPipelines(t *testing.T) {
RepoID: repo.ID,
Status: model.StatusPending,
}
err1 := store.CreatePipeline(pipeline1, []*model.Proc{}...)
err1 := store.CreatePipeline(pipeline1, []*model.Step{}...)
g.Assert(err1).IsNil()
err2 := store.CreatePipeline(pipeline2, []*model.Proc{}...)
err2 := store.CreatePipeline(pipeline2, []*model.Step{}...)
g.Assert(err2).IsNil()
GetPipeline, err3 := store.GetPipelineNumber(&model.Repo{ID: 1}, pipeline2.Number)
g.Assert(err3).IsNil()
@ -154,9 +154,9 @@ func TestPipelines(t *testing.T) {
Status: model.StatusPending,
Ref: "refs/pull/6",
}
err1 := store.CreatePipeline(pipeline1, []*model.Proc{}...)
err1 := store.CreatePipeline(pipeline1, []*model.Step{}...)
g.Assert(err1).IsNil()
err2 := store.CreatePipeline(pipeline2, []*model.Proc{}...)
err2 := store.CreatePipeline(pipeline2, []*model.Step{}...)
g.Assert(err2).IsNil()
GetPipeline, err3 := store.GetPipelineRef(&model.Repo{ID: 1}, "refs/pull/6")
g.Assert(err3).IsNil()
@ -177,9 +177,9 @@ func TestPipelines(t *testing.T) {
Status: model.StatusPending,
Ref: "refs/pull/6",
}
err1 := store.CreatePipeline(pipeline1, []*model.Proc{}...)
err1 := store.CreatePipeline(pipeline1, []*model.Step{}...)
g.Assert(err1).IsNil()
err2 := store.CreatePipeline(pipeline2, []*model.Proc{}...)
err2 := store.CreatePipeline(pipeline2, []*model.Step{}...)
g.Assert(err2).IsNil()
GetPipeline, err3 := store.GetPipelineRef(&model.Repo{ID: 1}, "refs/pull/6")
g.Assert(err3).IsNil()
@ -202,9 +202,9 @@ func TestPipelines(t *testing.T) {
Branch: "dev",
Commit: "85f8c029b902ed9400bc600bac301a0aadb144aa",
}
err1 := store.CreatePipeline(pipeline1, []*model.Proc{}...)
err1 := store.CreatePipeline(pipeline1, []*model.Step{}...)
g.Assert(err1).IsNil()
err2 := store.CreatePipeline(pipeline2, []*model.Proc{}...)
err2 := store.CreatePipeline(pipeline2, []*model.Step{}...)
g.Assert(err2).IsNil()
GetPipeline, err3 := store.GetPipelineCommit(&model.Repo{ID: 1}, pipeline2.Commit, pipeline2.Branch)
g.Assert(err3).IsNil()
@ -230,8 +230,8 @@ func TestPipelines(t *testing.T) {
Commit: "85f8c029b902ed9400bc600bac301a0aadb144aa",
Event: model.EventPush,
}
err1 := store.CreatePipeline(pipeline1, []*model.Proc{}...)
err2 := store.CreatePipeline(pipeline2, []*model.Proc{}...)
err1 := store.CreatePipeline(pipeline1, []*model.Step{}...)
err2 := store.CreatePipeline(pipeline2, []*model.Step{}...)
GetPipeline, err3 := store.GetPipelineLast(&model.Repo{ID: 1}, pipeline2.Branch)
g.Assert(err1).IsNil()
g.Assert(err2).IsNil()
@ -263,11 +263,11 @@ func TestPipelines(t *testing.T) {
Branch: "master",
Commit: "85f8c029b902ed9400bc600bac301a0aadb144aa",
}
err1 := store.CreatePipeline(pipeline1, []*model.Proc{}...)
err1 := store.CreatePipeline(pipeline1, []*model.Step{}...)
g.Assert(err1).IsNil()
err2 := store.CreatePipeline(pipeline2, []*model.Proc{}...)
err2 := store.CreatePipeline(pipeline2, []*model.Step{}...)
g.Assert(err2).IsNil()
err3 := store.CreatePipeline(pipeline3, []*model.Proc{}...)
err3 := store.CreatePipeline(pipeline3, []*model.Step{}...)
g.Assert(err3).IsNil()
GetPipeline, err4 := store.GetPipelineLastBefore(&model.Repo{ID: 1}, pipeline3.Branch, pipeline3.ID)
g.Assert(err4).IsNil()
@ -288,9 +288,9 @@ func TestPipelines(t *testing.T) {
RepoID: repo.ID,
Status: model.StatusSuccess,
}
err1 := store.CreatePipeline(pipeline1, []*model.Proc{}...)
err1 := store.CreatePipeline(pipeline1, []*model.Step{}...)
g.Assert(err1).IsNil()
err2 := store.CreatePipeline(pipeline2, []*model.Proc{}...)
err2 := store.CreatePipeline(pipeline2, []*model.Step{}...)
g.Assert(err2).IsNil()
pipelines, err3 := store.GetPipelineList(&model.Repo{ID: 1}, 1)
g.Assert(err3).IsNil()

View file

@ -383,7 +383,7 @@ func TestRepoCrud(t *testing.T) {
new(model.Pipeline),
new(model.PipelineConfig),
new(model.Logs),
new(model.Proc),
new(model.Step),
new(model.File),
new(model.Secret),
new(model.Registry),
@ -401,10 +401,10 @@ func TestRepoCrud(t *testing.T) {
pipeline := model.Pipeline{
RepoID: repo.ID,
}
proc := model.Proc{
Name: "a proc",
step := model.Step{
Name: "a step",
}
assert.NoError(t, store.CreatePipeline(&pipeline, &proc))
assert.NoError(t, store.CreatePipeline(&pipeline, &step))
// create unrelated
repoUnrelated := model.Repo{
@ -417,10 +417,10 @@ func TestRepoCrud(t *testing.T) {
pipelineUnrelated := model.Pipeline{
RepoID: repoUnrelated.ID,
}
procUnrelated := model.Proc{
Name: "a unrelated proc",
stepUnrelated := model.Step{
Name: "a unrelated step",
}
assert.NoError(t, store.CreatePipeline(&pipelineUnrelated, &procUnrelated))
assert.NoError(t, store.CreatePipeline(&pipelineUnrelated, &stepUnrelated))
_, err := store.GetRepo(repo.ID)
assert.NoError(t, err)
@ -428,9 +428,9 @@ func TestRepoCrud(t *testing.T) {
_, err = store.GetRepo(repo.ID)
assert.Error(t, err)
procCount, err := store.engine.Count(new(model.Proc))
stepCount, err := store.engine.Count(new(model.Step))
assert.NoError(t, err)
assert.EqualValues(t, 1, procCount)
assert.EqualValues(t, 1, stepCount)
pipelineCount, err := store.engine.Count(new(model.Pipeline))
assert.NoError(t, err)
assert.EqualValues(t, 1, pipelineCount)

View file

@ -20,46 +20,46 @@ import (
"github.com/woodpecker-ci/woodpecker/server/model"
)
func (s storage) ProcLoad(id int64) (*model.Proc, error) {
proc := new(model.Proc)
return proc, wrapGet(s.engine.ID(id).Get(proc))
func (s storage) StepLoad(id int64) (*model.Step, error) {
step := new(model.Step)
return step, wrapGet(s.engine.ID(id).Get(step))
}
func (s storage) ProcFind(pipeline *model.Pipeline, pid int) (*model.Proc, error) {
proc := &model.Proc{
func (s storage) StepFind(pipeline *model.Pipeline, pid int) (*model.Step, error) {
step := &model.Step{
PipelineID: pipeline.ID,
PID: pid,
}
return proc, wrapGet(s.engine.Get(proc))
return step, wrapGet(s.engine.Get(step))
}
func (s storage) ProcChild(pipeline *model.Pipeline, ppid int, child string) (*model.Proc, error) {
proc := &model.Proc{
func (s storage) StepChild(pipeline *model.Pipeline, ppid int, child string) (*model.Step, error) {
step := &model.Step{
PipelineID: pipeline.ID,
PPID: ppid,
Name: child,
}
return proc, wrapGet(s.engine.Get(proc))
return step, wrapGet(s.engine.Get(step))
}
func (s storage) ProcList(pipeline *model.Pipeline) ([]*model.Proc, error) {
procList := make([]*model.Proc, 0, perPage)
return procList, s.engine.
Where("proc_pipeline_id = ?", pipeline.ID).
OrderBy("proc_pid").
Find(&procList)
func (s storage) StepList(pipeline *model.Pipeline) ([]*model.Step, error) {
stepList := make([]*model.Step, 0, perPage)
return stepList, s.engine.
Where("step_pipeline_id = ?", pipeline.ID).
OrderBy("step_pid").
Find(&stepList)
}
func (s storage) ProcCreate(procs []*model.Proc) error {
func (s storage) StepCreate(steps []*model.Step) error {
sess := s.engine.NewSession()
defer sess.Close()
if err := sess.Begin(); err != nil {
return err
}
for i := range procs {
for i := range steps {
// only Insert on single object ref set auto created ID back to object
if _, err := sess.Insert(procs[i]); err != nil {
if _, err := sess.Insert(steps[i]); err != nil {
return err
}
}
@ -67,12 +67,12 @@ func (s storage) ProcCreate(procs []*model.Proc) error {
return sess.Commit()
}
func (s storage) ProcUpdate(proc *model.Proc) error {
_, err := s.engine.ID(proc.ID).AllCols().Update(proc)
func (s storage) StepUpdate(step *model.Step) error {
_, err := s.engine.ID(step.ID).AllCols().Update(step)
return err
}
func (s storage) ProcClear(pipeline *model.Pipeline) error {
func (s storage) StepClear(pipeline *model.Pipeline) error {
sess := s.engine.NewSession()
defer sess.Close()
if err := sess.Begin(); err != nil {
@ -83,20 +83,20 @@ func (s storage) ProcClear(pipeline *model.Pipeline) error {
return err
}
if _, err := sess.Where("proc_pipeline_id = ?", pipeline.ID).Delete(new(model.Proc)); err != nil {
if _, err := sess.Where("step_pipeline_id = ?", pipeline.ID).Delete(new(model.Step)); err != nil {
return err
}
return sess.Commit()
}
func deleteProc(sess *xorm.Session, procID int64) error {
if _, err := sess.Where("log_job_id = ?", procID).Delete(new(model.Logs)); err != nil {
func deleteStep(sess *xorm.Session, stepID int64) error {
if _, err := sess.Where("log_step_id = ?", stepID).Delete(new(model.Logs)); err != nil {
return err
}
if _, err := sess.Where("file_proc_id = ?", procID).Delete(new(model.File)); err != nil {
if _, err := sess.Where("file_step_id = ?", stepID).Delete(new(model.File)); err != nil {
return err
}
_, err := sess.ID(procID).Delete(new(model.Proc))
_, err := sess.ID(stepID).Delete(new(model.Step))
return err
}

View file

@ -23,11 +23,11 @@ import (
"github.com/woodpecker-ci/woodpecker/server/model"
)
func TestProcFind(t *testing.T) {
store, closer := newTestStore(t, new(model.Proc), new(model.Pipeline))
func TestStepFind(t *testing.T) {
store, closer := newTestStore(t, new(model.Step), new(model.Pipeline))
defer closer()
procs := []*model.Proc{
steps := []*model.Step{
{
PipelineID: 1000,
PID: 1,
@ -42,22 +42,22 @@ func TestProcFind(t *testing.T) {
Environ: map[string]string{"GOLANG": "tip"},
},
}
assert.NoError(t, store.ProcCreate(procs))
assert.EqualValues(t, 1, procs[0].ID)
assert.Error(t, store.ProcCreate(procs))
assert.NoError(t, store.StepCreate(steps))
assert.EqualValues(t, 1, steps[0].ID)
assert.Error(t, store.StepCreate(steps))
proc, err := store.ProcFind(&model.Pipeline{ID: 1000}, 1)
step, err := store.StepFind(&model.Pipeline{ID: 1000}, 1)
if !assert.NoError(t, err) {
return
}
assert.Equal(t, procs[0], proc)
assert.Equal(t, steps[0], step)
}
func TestProcChild(t *testing.T) {
store, closer := newTestStore(t, new(model.Proc), new(model.Pipeline))
func TestStepChild(t *testing.T) {
store, closer := newTestStore(t, new(model.Step), new(model.Pipeline))
defer closer()
err := store.ProcCreate([]*model.Proc{
err := store.StepCreate([]*model.Step{
{
PipelineID: 1,
PID: 1,
@ -75,28 +75,28 @@ func TestProcChild(t *testing.T) {
},
})
if err != nil {
t.Errorf("Unexpected error: insert procs: %s", err)
t.Errorf("Unexpected error: insert steps: %s", err)
return
}
proc, err := store.ProcChild(&model.Pipeline{ID: 1}, 1, "build")
step, err := store.StepChild(&model.Pipeline{ID: 1}, 1, "build")
if err != nil {
t.Error(err)
return
}
if got, want := proc.PID, 2; got != want {
t.Errorf("Want proc pid %d, got %d", want, got)
if got, want := step.PID, 2; got != want {
t.Errorf("Want step pid %d, got %d", want, got)
}
if got, want := proc.Name, "build"; got != want {
t.Errorf("Want proc name %s, got %s", want, got)
if got, want := step.Name, "build"; got != want {
t.Errorf("Want step name %s, got %s", want, got)
}
}
func TestProcList(t *testing.T) {
store, closer := newTestStore(t, new(model.Proc), new(model.Pipeline))
func TestStepList(t *testing.T) {
store, closer := newTestStore(t, new(model.Step), new(model.Pipeline))
defer closer()
err := store.ProcCreate([]*model.Proc{
err := store.StepCreate([]*model.Step{
{
PipelineID: 2,
PID: 1,
@ -121,24 +121,24 @@ func TestProcList(t *testing.T) {
},
})
if err != nil {
t.Errorf("Unexpected error: insert procs: %s", err)
t.Errorf("Unexpected error: insert steps: %s", err)
return
}
procs, err := store.ProcList(&model.Pipeline{ID: 1})
steps, err := store.StepList(&model.Pipeline{ID: 1})
if err != nil {
t.Error(err)
return
}
if got, want := len(procs), 2; got != want {
t.Errorf("Want %d procs, got %d", want, got)
if got, want := len(steps), 2; got != want {
t.Errorf("Want %d steps, got %d", want, got)
}
}
func TestProcUpdate(t *testing.T) {
store, closer := newTestStore(t, new(model.Proc), new(model.Pipeline))
func TestStepUpdate(t *testing.T) {
store, closer := newTestStore(t, new(model.Step), new(model.Pipeline))
defer closer()
proc := &model.Proc{
step := &model.Step{
PipelineID: 1,
PID: 1,
PPID: 2,
@ -151,30 +151,30 @@ func TestProcUpdate(t *testing.T) {
Platform: "linux/amd64",
Environ: map[string]string{"GOLANG": "tip"},
}
if err := store.ProcCreate([]*model.Proc{proc}); err != nil {
t.Errorf("Unexpected error: insert proc: %s", err)
if err := store.StepCreate([]*model.Step{step}); err != nil {
t.Errorf("Unexpected error: insert step: %s", err)
return
}
proc.State = "running"
if err := store.ProcUpdate(proc); err != nil {
t.Errorf("Unexpected error: update proc: %s", err)
step.State = "running"
if err := store.StepUpdate(step); err != nil {
t.Errorf("Unexpected error: update step: %s", err)
return
}
updated, err := store.ProcFind(&model.Pipeline{ID: 1}, 1)
updated, err := store.StepFind(&model.Pipeline{ID: 1}, 1)
if err != nil {
t.Error(err)
return
}
if got, want := updated.State, model.StatusRunning; got != want {
t.Errorf("Want proc name %s, got %s", want, got)
t.Errorf("Want step name %s, got %s", want, got)
}
}
func TestProcIndexes(t *testing.T) {
store, closer := newTestStore(t, new(model.Proc), new(model.Pipeline))
func TestStepIndexes(t *testing.T) {
store, closer := newTestStore(t, new(model.Step), new(model.Pipeline))
defer closer()
if err := store.ProcCreate([]*model.Proc{
if err := store.StepCreate([]*model.Step{
{
PipelineID: 1,
PID: 1,
@ -184,12 +184,12 @@ func TestProcIndexes(t *testing.T) {
Name: "build",
},
}); err != nil {
t.Errorf("Unexpected error: insert procs: %s", err)
t.Errorf("Unexpected error: insert steps: %s", err)
return
}
// fail due to duplicate pid
if err := store.ProcCreate([]*model.Proc{
if err := store.StepCreate([]*model.Step{
{
PipelineID: 1,
PID: 1,
@ -203,4 +203,4 @@ func TestProcIndexes(t *testing.T) {
}
}
// TODO: func TestProcCascade(t *testing.T) {}
// TODO: func TestStepCascade(t *testing.T) {}

View file

@ -24,7 +24,7 @@ import (
)
func TestUsers(t *testing.T) {
store, closer := newTestStore(t, new(model.User), new(model.Repo), new(model.Pipeline), new(model.Proc), new(model.Perm))
store, closer := newTestStore(t, new(model.User), new(model.Repo), new(model.Pipeline), new(model.Step), new(model.Perm))
defer closer()
g := goblin.Goblin(t)
@ -38,7 +38,7 @@ func TestUsers(t *testing.T) {
g.Assert(err).IsNil()
_, err = store.engine.Exec("DELETE FROM pipelines")
g.Assert(err).IsNil()
_, err = store.engine.Exec("DELETE FROM procs")
_, err = store.engine.Exec("DELETE FROM steps")
g.Assert(err).IsNil()
})

View file

@ -110,7 +110,7 @@ func (_m *Store) ConfigsForPipeline(pipelineID int64) ([]*model.Config, error) {
}
// CreatePipeline provides a mock function with given fields: _a0, _a1
func (_m *Store) CreatePipeline(_a0 *model.Pipeline, _a1 ...*model.Proc) error {
func (_m *Store) CreatePipeline(_a0 *model.Pipeline, _a1 ...*model.Step) error {
_va := make([]interface{}, len(_a1))
for _i := range _a1 {
_va[_i] = _a1[_i]
@ -121,7 +121,7 @@ func (_m *Store) CreatePipeline(_a0 *model.Pipeline, _a1 ...*model.Proc) error {
ret := _m.Called(_ca...)
var r0 error
if rf, ok := ret.Get(0).(func(*model.Pipeline, ...*model.Proc) error); ok {
if rf, ok := ret.Get(0).(func(*model.Pipeline, ...*model.Step) error); ok {
r0 = rf(_a0, _a1...)
} else {
r0 = ret.Error(0)
@ -347,11 +347,11 @@ func (_m *Store) FileCreate(_a0 *model.File, _a1 io.Reader) error {
}
// FileFind provides a mock function with given fields: _a0, _a1
func (_m *Store) FileFind(_a0 *model.Proc, _a1 string) (*model.File, error) {
func (_m *Store) FileFind(_a0 *model.Step, _a1 string) (*model.File, error) {
ret := _m.Called(_a0, _a1)
var r0 *model.File
if rf, ok := ret.Get(0).(func(*model.Proc, string) *model.File); ok {
if rf, ok := ret.Get(0).(func(*model.Step, string) *model.File); ok {
r0 = rf(_a0, _a1)
} else {
if ret.Get(0) != nil {
@ -360,7 +360,7 @@ func (_m *Store) FileFind(_a0 *model.Proc, _a1 string) (*model.File, error) {
}
var r1 error
if rf, ok := ret.Get(1).(func(*model.Proc, string) error); ok {
if rf, ok := ret.Get(1).(func(*model.Step, string) error); ok {
r1 = rf(_a0, _a1)
} else {
r1 = ret.Error(1)
@ -393,11 +393,11 @@ func (_m *Store) FileList(_a0 *model.Pipeline) ([]*model.File, error) {
}
// FileRead provides a mock function with given fields: _a0, _a1
func (_m *Store) FileRead(_a0 *model.Proc, _a1 string) (io.ReadCloser, error) {
func (_m *Store) FileRead(_a0 *model.Step, _a1 string) (io.ReadCloser, error) {
ret := _m.Called(_a0, _a1)
var r0 io.ReadCloser
if rf, ok := ret.Get(0).(func(*model.Proc, string) io.ReadCloser); ok {
if rf, ok := ret.Get(0).(func(*model.Step, string) io.ReadCloser); ok {
r0 = rf(_a0, _a1)
} else {
if ret.Get(0) != nil {
@ -406,7 +406,7 @@ func (_m *Store) FileRead(_a0 *model.Proc, _a1 string) (io.ReadCloser, error) {
}
var r1 error
if rf, ok := ret.Get(1).(func(*model.Proc, string) error); ok {
if rf, ok := ret.Get(1).(func(*model.Step, string) error); ok {
r1 = rf(_a0, _a1)
} else {
r1 = ret.Error(1)
@ -937,11 +937,11 @@ func (_m *Store) HasRedirectionForRepo(_a0 int64, _a1 string) (bool, error) {
}
// LogFind provides a mock function with given fields: _a0
func (_m *Store) LogFind(_a0 *model.Proc) (io.ReadCloser, error) {
func (_m *Store) LogFind(_a0 *model.Step) (io.ReadCloser, error) {
ret := _m.Called(_a0)
var r0 io.ReadCloser
if rf, ok := ret.Get(0).(func(*model.Proc) io.ReadCloser); ok {
if rf, ok := ret.Get(0).(func(*model.Step) io.ReadCloser); ok {
r0 = rf(_a0)
} else {
if ret.Get(0) != nil {
@ -950,7 +950,7 @@ func (_m *Store) LogFind(_a0 *model.Proc) (io.ReadCloser, error) {
}
var r1 error
if rf, ok := ret.Get(1).(func(*model.Proc) error); ok {
if rf, ok := ret.Get(1).(func(*model.Step) error); ok {
r1 = rf(_a0)
} else {
r1 = ret.Error(1)
@ -960,11 +960,11 @@ func (_m *Store) LogFind(_a0 *model.Proc) (io.ReadCloser, error) {
}
// LogSave provides a mock function with given fields: _a0, _a1
func (_m *Store) LogSave(_a0 *model.Proc, _a1 io.Reader) error {
func (_m *Store) LogSave(_a0 *model.Step, _a1 io.Reader) error {
ret := _m.Called(_a0, _a1)
var r0 error
if rf, ok := ret.Get(0).(func(*model.Proc, io.Reader) error); ok {
if rf, ok := ret.Get(0).(func(*model.Step, io.Reader) error); ok {
r0 = rf(_a0, _a1)
} else {
r0 = ret.Error(0)
@ -1126,140 +1126,6 @@ func (_m *Store) PipelineConfigCreate(_a0 *model.PipelineConfig) error {
return r0
}
// ProcChild provides a mock function with given fields: _a0, _a1, _a2
func (_m *Store) ProcChild(_a0 *model.Pipeline, _a1 int, _a2 string) (*model.Proc, error) {
ret := _m.Called(_a0, _a1, _a2)
var r0 *model.Proc
if rf, ok := ret.Get(0).(func(*model.Pipeline, int, string) *model.Proc); ok {
r0 = rf(_a0, _a1, _a2)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.Proc)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(*model.Pipeline, int, string) error); ok {
r1 = rf(_a0, _a1, _a2)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// ProcClear provides a mock function with given fields: _a0
func (_m *Store) ProcClear(_a0 *model.Pipeline) error {
ret := _m.Called(_a0)
var r0 error
if rf, ok := ret.Get(0).(func(*model.Pipeline) error); ok {
r0 = rf(_a0)
} else {
r0 = ret.Error(0)
}
return r0
}
// ProcCreate provides a mock function with given fields: _a0
func (_m *Store) ProcCreate(_a0 []*model.Proc) error {
ret := _m.Called(_a0)
var r0 error
if rf, ok := ret.Get(0).(func([]*model.Proc) error); ok {
r0 = rf(_a0)
} else {
r0 = ret.Error(0)
}
return r0
}
// ProcFind provides a mock function with given fields: _a0, _a1
func (_m *Store) ProcFind(_a0 *model.Pipeline, _a1 int) (*model.Proc, error) {
ret := _m.Called(_a0, _a1)
var r0 *model.Proc
if rf, ok := ret.Get(0).(func(*model.Pipeline, int) *model.Proc); ok {
r0 = rf(_a0, _a1)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.Proc)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(*model.Pipeline, int) error); ok {
r1 = rf(_a0, _a1)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// ProcList provides a mock function with given fields: _a0
func (_m *Store) ProcList(_a0 *model.Pipeline) ([]*model.Proc, error) {
ret := _m.Called(_a0)
var r0 []*model.Proc
if rf, ok := ret.Get(0).(func(*model.Pipeline) []*model.Proc); ok {
r0 = rf(_a0)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]*model.Proc)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(*model.Pipeline) error); ok {
r1 = rf(_a0)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// ProcLoad provides a mock function with given fields: _a0
func (_m *Store) ProcLoad(_a0 int64) (*model.Proc, error) {
ret := _m.Called(_a0)
var r0 *model.Proc
if rf, ok := ret.Get(0).(func(int64) *model.Proc); ok {
r0 = rf(_a0)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.Proc)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(int64) error); ok {
r1 = rf(_a0)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// ProcUpdate provides a mock function with given fields: _a0
func (_m *Store) ProcUpdate(_a0 *model.Proc) error {
ret := _m.Called(_a0)
var r0 error
if rf, ok := ret.Get(0).(func(*model.Proc) error); ok {
r0 = rf(_a0)
} else {
r0 = ret.Error(0)
}
return r0
}
// RegistryCreate provides a mock function with given fields: _a0
func (_m *Store) RegistryCreate(_a0 *model.Registry) error {
ret := _m.Called(_a0)
@ -1531,6 +1397,140 @@ func (_m *Store) ServerConfigSet(_a0 string, _a1 string) error {
return r0
}
// StepChild provides a mock function with given fields: _a0, _a1, _a2
func (_m *Store) StepChild(_a0 *model.Pipeline, _a1 int, _a2 string) (*model.Step, error) {
ret := _m.Called(_a0, _a1, _a2)
var r0 *model.Step
if rf, ok := ret.Get(0).(func(*model.Pipeline, int, string) *model.Step); ok {
r0 = rf(_a0, _a1, _a2)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.Step)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(*model.Pipeline, int, string) error); ok {
r1 = rf(_a0, _a1, _a2)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// StepClear provides a mock function with given fields: _a0
func (_m *Store) StepClear(_a0 *model.Pipeline) error {
ret := _m.Called(_a0)
var r0 error
if rf, ok := ret.Get(0).(func(*model.Pipeline) error); ok {
r0 = rf(_a0)
} else {
r0 = ret.Error(0)
}
return r0
}
// StepCreate provides a mock function with given fields: _a0
func (_m *Store) StepCreate(_a0 []*model.Step) error {
ret := _m.Called(_a0)
var r0 error
if rf, ok := ret.Get(0).(func([]*model.Step) error); ok {
r0 = rf(_a0)
} else {
r0 = ret.Error(0)
}
return r0
}
// StepFind provides a mock function with given fields: _a0, _a1
func (_m *Store) StepFind(_a0 *model.Pipeline, _a1 int) (*model.Step, error) {
ret := _m.Called(_a0, _a1)
var r0 *model.Step
if rf, ok := ret.Get(0).(func(*model.Pipeline, int) *model.Step); ok {
r0 = rf(_a0, _a1)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.Step)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(*model.Pipeline, int) error); ok {
r1 = rf(_a0, _a1)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// StepList provides a mock function with given fields: _a0
func (_m *Store) StepList(_a0 *model.Pipeline) ([]*model.Step, error) {
ret := _m.Called(_a0)
var r0 []*model.Step
if rf, ok := ret.Get(0).(func(*model.Pipeline) []*model.Step); ok {
r0 = rf(_a0)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]*model.Step)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(*model.Pipeline) error); ok {
r1 = rf(_a0)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// StepLoad provides a mock function with given fields: _a0
func (_m *Store) StepLoad(_a0 int64) (*model.Step, error) {
ret := _m.Called(_a0)
var r0 *model.Step
if rf, ok := ret.Get(0).(func(int64) *model.Step); ok {
r0 = rf(_a0)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.Step)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(int64) error); ok {
r1 = rf(_a0)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// StepUpdate provides a mock function with given fields: _a0
func (_m *Store) StepUpdate(_a0 *model.Step) error {
ret := _m.Called(_a0)
var r0 error
if rf, ok := ret.Get(0).(func(*model.Step) error); ok {
r0 = rf(_a0)
} else {
r0 = ret.Error(0)
}
return r0
}
// TaskDelete provides a mock function with given fields: _a0
func (_m *Store) TaskDelete(_a0 string) error {
ret := _m.Called(_a0)

View file

@ -91,8 +91,8 @@ type Store interface {
GetPipelineQueue() ([]*model.Feed, error)
// GetPipelineCount gets a count of all pipelines in the system.
GetPipelineCount() (int64, error)
// CreatePipeline creates a new pipeline and jobs.
CreatePipeline(*model.Pipeline, ...*model.Proc) error
// CreatePipeline creates a new pipeline and steps.
CreatePipeline(*model.Pipeline, ...*model.Step) error
// UpdatePipeline updates a pipeline.
UpdatePipeline(*model.Pipeline) error
@ -137,25 +137,25 @@ type Store interface {
RegistryUpdate(*model.Registry) error
RegistryDelete(repo *model.Repo, addr string) error
// Procs
ProcLoad(int64) (*model.Proc, error)
ProcFind(*model.Pipeline, int) (*model.Proc, error)
ProcChild(*model.Pipeline, int, string) (*model.Proc, error)
ProcList(*model.Pipeline) ([]*model.Proc, error)
ProcCreate([]*model.Proc) error
ProcUpdate(*model.Proc) error
ProcClear(*model.Pipeline) error
// Steps
StepLoad(int64) (*model.Step, error)
StepFind(*model.Pipeline, int) (*model.Step, error)
StepChild(*model.Pipeline, int, string) (*model.Step, error)
StepList(*model.Pipeline) ([]*model.Step, error)
StepCreate([]*model.Step) error
StepUpdate(*model.Step) error
StepClear(*model.Pipeline) error
// Logs
LogFind(*model.Proc) (io.ReadCloser, error)
LogFind(*model.Step) (io.ReadCloser, error)
// TODO: since we do ReadAll in any case a ioReader is not the best idear
// so either find a way to write log in chunks by xorm ...
LogSave(*model.Proc, io.Reader) error
LogSave(*model.Step, io.Reader) error
// Files
FileList(*model.Pipeline) ([]*model.File, error)
FileFind(*model.Proc, string) (*model.File, error)
FileRead(*model.Proc, string) (io.ReadCloser, error)
FileFind(*model.Step, string) (*model.File, error)
FileRead(*model.Step, string) (io.ReadCloser, error)
FileCreate(*model.File, io.Reader) error
// Tasks

4
web/components.d.ts vendored
View file

@ -76,10 +76,10 @@ declare module '@vue/runtime-core' {
PipelineItem: typeof import('./src/components/repo/pipeline/PipelineItem.vue')['default']
PipelineList: typeof import('./src/components/repo/pipeline/PipelineList.vue')['default']
PipelineLog: typeof import('./src/components/repo/pipeline/PipelineLog.vue')['default']
PipelineProcDuration: typeof import('./src/components/repo/pipeline/PipelineProcDuration.vue')['default']
PipelineProcList: typeof import('./src/components/repo/pipeline/PipelineProcList.vue')['default']
PipelineRunningIcon: typeof import('./src/components/repo/pipeline/PipelineRunningIcon.vue')['default']
PipelineStatusIcon: typeof import('./src/components/repo/pipeline/PipelineStatusIcon.vue')['default']
PipelineStepDuration: typeof import('./src/components/repo/pipeline/PipelineStepDuration.vue')['default']
PipelineStepList: typeof import('./src/components/repo/pipeline/PipelineStepList.vue')['default']
Popup: typeof import('./src/components/layout/Popup.vue')['default']
RadioField: typeof import('./src/components/form/RadioField.vue')['default']
RegistriesTab: typeof import('./src/components/repo/settings/RegistriesTab.vue')['default']

View file

@ -2,9 +2,9 @@
<div v-if="pipeline" class="flex flex-col pt-10 md:pt-0">
<div
class="fixed top-0 left-0 w-full md:hidden flex px-4 py-2 bg-gray-600 dark:bg-dark-gray-800 text-gray-50"
@click="$emit('update:proc-id', null)"
@click="$emit('update:step-id', null)"
>
<span>{{ proc?.name }}</span>
<span>{{ step?.name }}</span>
<Icon name="close" class="ml-auto" />
</div>
@ -15,14 +15,14 @@
>
<div v-show="showActions" class="absolute top-0 right-0 z-40 mt-2 mr-4 hidden md:flex">
<Button
v-if="proc?.end_time !== undefined"
v-if="step?.end_time !== undefined"
:is-loading="downloadInProgress"
:title="$t('repo.pipeline.actions.log_download')"
start-icon="download"
@click="download"
/>
<Button
v-if="proc?.end_time === undefined"
v-if="step?.end_time === undefined"
:title="
autoScroll ? $t('repo.pipeline.actions.log_auto_scroll_off') : $t('repo.pipeline.actions.log_auto_scroll')
"
@ -45,20 +45,20 @@
</div>
<div class="m-auto text-xl text-color">
<span v-if="proc?.error" class="text-red-400">{{ proc.error }}</span>
<span v-else-if="proc?.state === 'skipped'" class="text-red-400">{{
<span v-if="step?.error" class="text-red-400">{{ step.error }}</span>
<span v-else-if="step?.state === 'skipped'" class="text-red-400">{{
$t('repo.pipeline.actions.canceled')
}}</span>
<span v-else-if="!proc?.start_time">{{ $t('repo.pipeline.step_not_started') }}</span>
<span v-else-if="!step?.start_time">{{ $t('repo.pipeline.step_not_started') }}</span>
<div v-else-if="!loadedLogs">{{ $t('repo.pipeline.loading') }}</div>
</div>
<div
v-if="proc?.end_time !== undefined"
:class="proc.exit_code == 0 ? 'dark:text-lime-400 text-lime-700' : 'dark:text-red-400 text-red-600'"
v-if="step?.end_time !== undefined"
:class="step.exit_code == 0 ? 'dark:text-lime-400 text-lime-700' : 'dark:text-red-400 text-red-600'"
class="w-full bg-gray-200 dark:bg-dark-gray-800 text-md p-4"
>
{{ $t('repo.pipeline.exit_code', { exitCode: proc.exit_code }) }}
{{ $t('repo.pipeline.exit_code', { exitCode: step.exit_code }) }}
</div>
</div>
</div>
@ -78,7 +78,7 @@ import Icon from '~/components/atomic/Icon.vue';
import useApiClient from '~/compositions/useApiClient';
import useNotifications from '~/compositions/useNotifications';
import { Pipeline, Repo } from '~/lib/api/types';
import { findProc, isProcFinished, isProcRunning } from '~/utils/helpers';
import { findStep, isStepFinished, isStepRunning } from '~/utils/helpers';
type LogLine = {
index: number;
@ -97,7 +97,7 @@ export default defineComponent({
required: true,
},
procId: {
stepId: {
type: Number,
required: true,
},
@ -105,22 +105,22 @@ export default defineComponent({
emits: {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
'update:proc-id': (procId: number | null) => true,
'update:step-id': (stepId: number | null) => true,
},
setup(props) {
const notifications = useNotifications();
const i18n = useI18n();
const pipeline = toRef(props, 'pipeline');
const procId = toRef(props, 'procId');
const stepId = toRef(props, 'stepId');
const repo = inject<Ref<Repo>>('repo');
const apiClient = useApiClient();
const loadedProcSlug = ref<string>();
const procSlug = computed(
() => `${repo?.value.owner} - ${repo?.value.name} - ${pipeline.value.id} - ${procId.value}`,
const loadedStepSlug = ref<string>();
const stepSlug = computed(
() => `${repo?.value.owner} - ${repo?.value.name} - ${pipeline.value.id} - ${stepId.value}`,
);
const proc = computed(() => pipeline.value && findProc(pipeline.value.procs || [], procId.value));
const step = computed(() => pipeline.value && findStep(pipeline.value.steps || [], stepId.value));
const stream = ref<EventSource>();
const log = ref<LogLine[]>();
const consoleElement = ref<Element>();
@ -128,8 +128,8 @@ export default defineComponent({
const loadedLogs = computed(() => !!log.value);
const hasLogs = computed(
() =>
// we do not have logs for skipped jobs
repo?.value && pipeline.value && proc.value && proc.value.state !== 'skipped' && proc.value.state !== 'killed',
// we do not have logs for skipped steps
repo?.value && pipeline.value && step.value && step.value.state !== 'skipped' && step.value.state !== 'killed',
);
const autoScroll = useStorage('log-auto-scroll', false);
const showActions = ref(false);
@ -200,13 +200,13 @@ export default defineComponent({
}, 500);
async function download() {
if (!repo?.value || !pipeline.value || !proc.value) {
throw new Error('The repository, pipeline or proc was undefined');
if (!repo?.value || !pipeline.value || !step.value) {
throw new Error('The repository, pipeline or step was undefined');
}
let logs;
try {
downloadInProgress.value = true;
logs = await apiClient.getLogs(repo.value.owner, repo.value.name, pipeline.value.number, proc.value.pid);
logs = await apiClient.getLogs(repo.value.owner, repo.value.name, pipeline.value.number, step.value.pid);
} catch (e) {
notifications.notifyError(e, i18n.t('repo.pipeline.log_download_error'));
return;
@ -223,7 +223,7 @@ export default defineComponent({
fileLink.href = fileURL;
fileLink.setAttribute(
'download',
`${repo.value.owner}-${repo.value.name}-${pipeline.value.number}-${proc.value.name}.log`,
`${repo.value.owner}-${repo.value.name}-${pipeline.value.number}-${step.value.name}.log`,
);
document.body.appendChild(fileLink);
@ -233,10 +233,10 @@ export default defineComponent({
}
async function loadLogs() {
if (loadedProcSlug.value === procSlug.value) {
if (loadedStepSlug.value === stepSlug.value) {
return;
}
loadedProcSlug.value = procSlug.value;
loadedStepSlug.value = stepSlug.value;
log.value = undefined;
logBuffer.value = [];
ansiUp.value = new AnsiUp();
@ -250,26 +250,26 @@ export default defineComponent({
stream.value.close();
}
if (!hasLogs.value || !proc.value) {
if (!hasLogs.value || !step.value) {
return;
}
if (isProcFinished(proc.value)) {
const logs = await apiClient.getLogs(repo.value.owner, repo.value.name, pipeline.value.number, proc.value.pid);
if (isStepFinished(step.value)) {
const logs = await apiClient.getLogs(repo.value.owner, repo.value.name, pipeline.value.number, step.value.pid);
logs?.forEach((line) => writeLog({ index: line.pos, text: line.out, time: line.time }));
flushLogs(false);
}
if (isProcRunning(proc.value)) {
if (isStepRunning(step.value)) {
// load stream of parent process (which receives all child processes logs)
// TODO: change stream to only send data of single child process
stream.value = apiClient.streamLogs(
repo.value.owner,
repo.value.name,
pipeline.value.number,
proc.value.ppid,
step.value.ppid,
(line) => {
if (line?.proc !== proc.value?.name) {
if (line?.step !== step.value?.name) {
return;
}
writeLog({ index: line.pos, text: line.out, time: line.time });
@ -283,12 +283,12 @@ export default defineComponent({
loadLogs();
});
watch(procSlug, () => {
watch(stepSlug, () => {
loadLogs();
});
watch(proc, (oldProc, newProc) => {
if (oldProc && oldProc.name === newProc?.name && oldProc?.end_time !== newProc?.end_time) {
watch(step, (oldStep, newStep) => {
if (oldStep && oldStep.name === newStep?.name && oldStep?.end_time !== newStep?.end_time) {
if (autoScroll.value) {
scrollDown();
}
@ -297,7 +297,7 @@ export default defineComponent({
return {
consoleElement,
proc,
step,
log,
loadedLogs,
hasLogs,

View file

@ -1,30 +1,30 @@
<template>
<span v-if="proc.start_time !== undefined" class="ml-auto text-sm">{{ duration }}</span>
<span v-if="step.start_time !== undefined" class="ml-auto text-sm">{{ duration }}</span>
</template>
<script lang="ts">
import { computed, defineComponent, PropType, toRef } from 'vue';
import { useElapsedTime } from '~/compositions/useElapsedTime';
import { PipelineProc } from '~/lib/api/types';
import { PipelineStep } from '~/lib/api/types';
import { durationAsNumber } from '~/utils/duration';
export default defineComponent({
name: 'PipelineProcDuration',
name: 'PipelineStepDuration',
props: {
proc: {
type: Object as PropType<PipelineProc>,
step: {
type: Object as PropType<PipelineStep>,
required: true,
},
},
setup(props) {
const proc = toRef(props, 'proc');
const step = toRef(props, 'step');
const durationRaw = computed(() => {
const start = proc.value.start_time || 0;
const end = proc.value.end_time || 0;
const start = step.value.start_time || 0;
const end = step.value.end_time || 0;
if (end === 0 && start === 0) {
return undefined;
@ -37,7 +37,7 @@ export default defineComponent({
return (end - start) * 1000;
});
const running = computed(() => proc.value.state === 'running');
const running = computed(() => step.value.state === 'running');
const { time: durationElapsed } = useElapsedTime(running, durationRaw);
const duration = computed(() => {

View file

@ -38,19 +38,19 @@
</div>
</div>
<div v-if="pipeline.procs === undefined || pipeline.procs.length === 0" class="m-auto mt-4">
<div v-if="pipeline.steps === undefined || pipeline.steps.length === 0" class="m-auto mt-4">
<span>{{ $t('repo.pipeline.no_pipeline_steps') }}</span>
</div>
<div class="flex flex-grow flex-col relative min-h-0 overflow-y-auto gap-2">
<div
v-for="proc in pipeline.procs"
:key="proc.id"
v-for="step in pipeline.steps"
:key="step.id"
class="p-2 md:rounded-md bg-white shadow dark:border-b-dark-gray-600 dark:bg-dark-gray-700"
>
<div class="flex flex-col gap-2">
<div v-if="proc.environ" class="flex flex-wrap gap-x-1 gap-y-2 text-xs justify-end pt-1">
<div v-for="(value, key) in proc.environ" :key="key">
<div v-if="step.environ" class="flex flex-wrap gap-x-1 gap-y-2 text-xs justify-end pt-1">
<div v-for="(value, key) in step.environ" :key="key">
<span
class="pl-2 pr-1 py-0.5 bg-gray-800 text-gray-200 dark:bg-gray-600 border-2 border-gray-800 dark:border-gray-600 rounded-l-full"
>
@ -62,52 +62,54 @@
</div>
</div>
<button
v-if="pipeline.procs && pipeline.procs.length > 1"
v-if="pipeline.steps && pipeline.steps.length > 1"
type="button"
:title="proc.name"
:title="step.name"
class="flex items-center gap-2 py-2 px-1 hover:bg-black hover:bg-opacity-10 dark:hover:bg-white dark:hover:bg-opacity-5 rounded-md"
@click="procsCollapsed[proc.id] = !!!procsCollapsed[proc.id]"
@click="stepsCollapsed[step.id] = !!!stepsCollapsed[step.id]"
>
<Icon
name="chevron-right"
class="transition-transform duration-150 min-w-6 h-6"
:class="{ 'transform rotate-90': !procsCollapsed[proc.id] }"
:class="{ 'transform rotate-90': !stepsCollapsed[step.id] }"
/>
<span class="truncate">{{ proc.name }}</span>
<span class="truncate">{{ step.name }}</span>
</button>
</div>
<div
class="transition-height duration-150 overflow-hidden"
:class="{
'max-h-screen': !procsCollapsed[proc.id],
'max-h-0': procsCollapsed[proc.id],
'ml-6': pipeline.procs && pipeline.procs.length > 1,
'max-h-screen': !stepsCollapsed[step.id],
'max-h-0': stepsCollapsed[step.id],
'ml-6': pipeline.steps && pipeline.steps.length > 1,
}"
>
<button
v-for="job in proc.children"
:key="job.pid"
v-for="subStep in step.children"
:key="subStep.pid"
type="button"
:title="job.name"
:title="subStep.name"
class="flex p-2 gap-2 border-2 border-transparent rounded-md items-center hover:bg-black hover:bg-opacity-10 dark:hover:bg-white dark:hover:bg-opacity-5 w-full"
:class="{
'bg-black bg-opacity-10 dark:bg-white dark:bg-opacity-5': selectedProcId && selectedProcId === job.pid,
'bg-black bg-opacity-10 dark:bg-white dark:bg-opacity-5':
selectedStepId && selectedStepId === subStep.pid,
'mt-1':
(pipeline.procs && pipeline.procs.length > 1) || (proc.children && job.pid !== proc.children[0].pid),
(pipeline.steps && pipeline.steps.length > 1) ||
(step.children && subStep.pid !== step.children[0].pid),
}"
@click="$emit('update:selected-proc-id', job.pid)"
@click="$emit('update:selected-step-id', subStep.pid)"
>
<div
class="min-w-2 h-2 rounded-full"
:class="{
'bg-lime-400': ['success'].includes(job.state),
'bg-gray-400': ['pending', 'skipped'].includes(job.state),
'bg-red-400': ['killed', 'error', 'failure', 'blocked', 'declined'].includes(job.state),
'bg-blue-400': ['started', 'running'].includes(job.state),
'bg-lime-400': ['success'].includes(subStep.state),
'bg-gray-400': ['pending', 'skipped'].includes(subStep.state),
'bg-red-400': ['killed', 'error', 'failure', 'blocked', 'declined'].includes(subStep.state),
'bg-blue-400': ['started', 'running'].includes(subStep.state),
}"
/>
<span class="truncate">{{ job.name }}</span>
<PipelineProcDuration :proc="job" />
<span class="truncate">{{ subStep.name }}</span>
<PipelineStepDuration :step="subStep" />
</button>
</div>
</div>
@ -119,21 +121,21 @@
import { ref, toRef } from 'vue';
import Icon from '~/components/atomic/Icon.vue';
import PipelineProcDuration from '~/components/repo/pipeline/PipelineProcDuration.vue';
import PipelineStepDuration from '~/components/repo/pipeline/PipelineStepDuration.vue';
import usePipeline from '~/compositions/usePipeline';
import { Pipeline, PipelineProc } from '~/lib/api/types';
import { Pipeline, PipelineStep } from '~/lib/api/types';
const props = defineProps<{
pipeline: Pipeline;
selectedProcId?: number | null;
selectedStepId?: number | null;
}>();
defineEmits<{
(event: 'update:selected-proc-id', selectedProcId: number): void;
(event: 'update:selected-step-id', selectedStepId: number): void;
}>();
const pipeline = toRef(props, 'pipeline');
const { prettyRef } = usePipeline(pipeline);
const procsCollapsed = ref<Record<PipelineProc['id'], boolean>>({});
const stepsCollapsed = ref<Record<PipelineStep['id'], boolean>>({});
</script>

View file

@ -32,11 +32,11 @@ export default () => {
pipelineStore.setPipeline(repo.owner, repo.name, pipeline);
pipelineStore.setPipelineFeedItem({ ...pipeline, name: repo.name, owner: repo.owner, full_name: repoSlug(repo) });
// contains proc update
if (!data.proc) {
// contains step update
if (!data.step) {
return;
}
const { proc } = data;
pipelineStore.setProc(repo.owner, repo.name, pipeline.number, proc);
const { step } = data;
pipelineStore.setStep(repo.owner, repo.name, pipeline.number, step);
});
};

View file

@ -5,7 +5,7 @@ import {
PipelineConfig,
PipelineFeed,
PipelineLog,
PipelineProc,
PipelineStep,
Registry,
Repo,
RepoPermissions,
@ -102,12 +102,12 @@ export default class WoodpeckerClient extends ApiClient {
return this._post(`/api/repos/${owner}/${repo}/pipelines/${pipeline}?${query}`);
}
getLogs(owner: string, repo: string, pipeline: number, proc: number): Promise<PipelineLog[]> {
return this._get(`/api/repos/${owner}/${repo}/logs/${pipeline}/${proc}`) as Promise<PipelineLog[]>;
getLogs(owner: string, repo: string, pipeline: number, step: number): Promise<PipelineLog[]> {
return this._get(`/api/repos/${owner}/${repo}/logs/${pipeline}/${step}`) as Promise<PipelineLog[]>;
}
getArtifact(owner: string, repo: string, pipeline: string, proc: string, file: string): Promise<unknown> {
return this._get(`/api/repos/${owner}/${repo}/files/${pipeline}/${proc}/${file}?raw=true`);
getArtifact(owner: string, repo: string, pipeline: string, step: string, file: string): Promise<unknown> {
return this._get(`/api/repos/${owner}/${repo}/files/${pipeline}/${step}/${file}?raw=true`);
}
getArtifactList(owner: string, repo: string, pipeline: string): Promise<unknown> {
@ -211,7 +211,7 @@ export default class WoodpeckerClient extends ApiClient {
}
// eslint-disable-next-line promise/prefer-await-to-callbacks
on(callback: (data: { pipeline?: Pipeline; repo?: Repo; proc?: PipelineProc }) => void): EventSource {
on(callback: (data: { pipeline?: Pipeline; repo?: Repo; step?: PipelineStep }) => void): EventSource {
return this._subscribe('/stream/events', callback, {
reconnect: true,
});
@ -221,11 +221,11 @@ export default class WoodpeckerClient extends ApiClient {
owner: string,
repo: string,
pipeline: number,
proc: number,
step: number,
// eslint-disable-next-line promise/prefer-await-to-callbacks
callback: (data: PipelineLog) => void,
): EventSource {
return this._subscribe(`/stream/logs/${owner}/${repo}/${pipeline}/${proc}`, callback, {
return this._subscribe(`/stream/logs/${owner}/${repo}/${pipeline}/${step}`, callback, {
reconnect: true,
});
}

Some files were not shown because too many files have changed in this diff Show more