Rename build to pipeline in code (#1224)

Ref:  #745

Co-authored-by: Anbraten <anton@ju60.de>
Co-authored-by: 6543 <6543@obermui.de>
This commit is contained in:
qwerty287 2022-10-18 03:24:12 +02:00 committed by GitHub
parent 493ec45be6
commit 849e05bb8b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
224 changed files with 4591 additions and 3831 deletions

View file

@ -1,3 +1,4 @@
// Copyright 2022 Woodpecker Authors
// Copyright 2018 Drone.IO Inc. // Copyright 2018 Drone.IO Inc.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
@ -81,19 +82,19 @@ func (r *Runner) Run(ctx context.Context) error {
} }
repoName := extractRepositoryName(work.Config) // hack repoName := extractRepositoryName(work.Config) // hack
buildNumber := extractBuildNumber(work.Config) // hack pipelineNumber := extractPipelineNumber(work.Config) // hack
r.counter.Add( r.counter.Add(
work.ID, work.ID,
timeout, timeout,
repoName, repoName,
buildNumber, pipelineNumber,
) )
defer r.counter.Done(work.ID) defer r.counter.Done(work.ID)
logger := log.With(). logger := log.With().
Str("repo", repoName). Str("repo", repoName).
Str("build", buildNumber). Str("pipeline", pipelineNumber).
Str("id", work.ID). Str("id", work.ID).
Logger() Logger()
@ -288,6 +289,10 @@ 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 // 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_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)
// DEPRECATED
state.Pipeline.Step.Environment["CI_BUILD_STATUS"] = "success" 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_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_BUILD_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
@ -299,6 +304,8 @@ func (r *Runner) Run(ctx context.Context) error {
state.Pipeline.Step.Environment["CI_SYSTEM_ARCH"] = runtime.GOOS + "/" + runtime.GOARCH state.Pipeline.Step.Environment["CI_SYSTEM_ARCH"] = runtime.GOOS + "/" + runtime.GOARCH
if state.Pipeline.Error != nil { if state.Pipeline.Error != nil {
state.Pipeline.Step.Environment["CI_PIPELINE_STATUS"] = "failure"
// DEPRECATED
state.Pipeline.Step.Environment["CI_BUILD_STATUS"] = "failure" state.Pipeline.Step.Environment["CI_BUILD_STATUS"] = "failure"
state.Pipeline.Step.Environment["CI_JOB_STATUS"] = "failure" state.Pipeline.Step.Environment["CI_JOB_STATUS"] = "failure"
} }
@ -313,7 +320,7 @@ func (r *Runner) Run(ctx context.Context) error {
pipeline.WithDescription(map[string]string{ pipeline.WithDescription(map[string]string{
"ID": work.ID, "ID": work.ID,
"Repo": repoName, "Repo": repoName,
"Build": buildNumber, "Pipeline": pipelineNumber,
}), }),
).Run() ).Run()
@ -363,7 +370,7 @@ func extractRepositoryName(config *backend.Config) string {
return config.Stages[0].Steps[0].Environment["CI_REPO"] return config.Stages[0].Steps[0].Environment["CI_REPO"]
} }
// extract build number from the configuration // extract pipeline number from the configuration
func extractBuildNumber(config *backend.Config) string { func extractPipelineNumber(config *backend.Config) string {
return config.Stages[0].Steps[0].Environment["CI_BUILD_NUMBER"] return config.Stages[0].Steps[0].Environment["CI_PIPELINE_NUMBER"]
} }

View file

@ -1,3 +1,4 @@
// Copyright 2022 Woodpecker Authors
// Copyright 2018 Drone.IO Inc. // Copyright 2018 Drone.IO Inc.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
@ -31,19 +32,19 @@ type State struct {
type Info struct { type Info struct {
ID string `json:"id"` ID string `json:"id"`
Repo string `json:"repository"` Repo string `json:"repository"`
Build string `json:"build_number"` Pipeline string `json:"build_number"`
Started time.Time `json:"build_started"` Started time.Time `json:"build_started"`
Timeout time.Duration `json:"build_timeout"` Timeout time.Duration `json:"build_timeout"`
} }
func (s *State) Add(id string, timeout time.Duration, repo, build string) { func (s *State) Add(id string, timeout time.Duration, repo, pipeline string) {
s.Lock() s.Lock()
s.Polling-- s.Polling--
s.Running++ s.Running++
s.Metadata[id] = Info{ s.Metadata[id] = Info{
ID: id, ID: id,
Repo: repo, Repo: repo,
Build: build, Pipeline: pipeline,
Timeout: timeout, Timeout: timeout,
Started: time.Now().UTC(), Started: time.Now().UTC(),
} }

View file

@ -1,28 +0,0 @@
package build
import (
"github.com/urfave/cli/v2"
"github.com/woodpecker-ci/woodpecker/cli/common"
)
// Command exports the build command set.
var Command = &cli.Command{
Name: "build",
Usage: "manage builds",
Flags: common.GlobalFlags,
Subcommands: []*cli.Command{
buildListCmd,
buildLastCmd,
buildLogsCmd,
buildInfoCmd,
buildStopCmd,
buildStartCmd,
buildApproveCmd,
buildDeclineCmd,
buildQueueCmd,
buildKillCmd,
buildPsCmd,
buildCreateCmd,
},
}

View file

@ -1,44 +0,0 @@
package build
import (
"fmt"
"strconv"
"github.com/urfave/cli/v2"
"github.com/woodpecker-ci/woodpecker/cli/common"
"github.com/woodpecker-ci/woodpecker/cli/internal"
)
var buildApproveCmd = &cli.Command{
Name: "approve",
Usage: "approve a build",
ArgsUsage: "<repo/name> <build>",
Action: buildApprove,
Flags: common.GlobalFlags,
}
func buildApprove(c *cli.Context) (err error) {
repo := c.Args().First()
owner, name, err := internal.ParseRepo(repo)
if err != nil {
return err
}
number, err := strconv.Atoi(c.Args().Get(1))
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
_, err = client.BuildApprove(owner, name, number)
if err != nil {
return err
}
fmt.Printf("Approving build %s/%s#%d\n", owner, name, number)
return nil
}

View file

@ -1,44 +0,0 @@
package build
import (
"fmt"
"strconv"
"github.com/urfave/cli/v2"
"github.com/woodpecker-ci/woodpecker/cli/common"
"github.com/woodpecker-ci/woodpecker/cli/internal"
)
var buildDeclineCmd = &cli.Command{
Name: "decline",
Usage: "decline a build",
ArgsUsage: "<repo/name> <build>",
Action: buildDecline,
Flags: common.GlobalFlags,
}
func buildDecline(c *cli.Context) (err error) {
repo := c.Args().First()
owner, name, err := internal.ParseRepo(repo)
if err != nil {
return err
}
number, err := strconv.Atoi(c.Args().Get(1))
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
_, err = client.BuildDecline(owner, name, number)
if err != nil {
return err
}
fmt.Printf("Declining build %s/%s#%d\n", owner, name, number)
return nil
}

View file

@ -1,73 +0,0 @@
package build
import (
"os"
"strconv"
"text/template"
"github.com/urfave/cli/v2"
"github.com/woodpecker-ci/woodpecker/cli/common"
"github.com/woodpecker-ci/woodpecker/cli/internal"
)
var buildInfoCmd = &cli.Command{
Name: "info",
Usage: "show build details",
ArgsUsage: "<repo/name> [build]",
Action: buildInfo,
Flags: append(common.GlobalFlags,
common.FormatFlag(tmplBuildInfo),
),
}
func buildInfo(c *cli.Context) error {
repo := c.Args().First()
owner, name, err := internal.ParseRepo(repo)
if err != nil {
return err
}
buildArg := c.Args().Get(1)
client, err := internal.NewClient(c)
if err != nil {
return err
}
var number int
if buildArg == "last" || len(buildArg) == 0 {
// Fetch the build number from the last build
build, err := client.BuildLast(owner, name, "")
if err != nil {
return err
}
number = build.Number
} else {
number, err = strconv.Atoi(buildArg)
if err != nil {
return err
}
}
build, err := client.Build(owner, name, number)
if err != nil {
return err
}
tmpl, err := template.New("_").Parse(c.String("format"))
if err != nil {
return err
}
return tmpl.Execute(os.Stdout, build)
}
// template for build information
var tmplBuildInfo = `Number: {{ .Number }}
Status: {{ .Status }}
Event: {{ .Event }}
Commit: {{ .Commit }}
Branch: {{ .Branch }}
Ref: {{ .Ref }}
Message: {{ .Message }}
Author: {{ .Author }}
`

View file

@ -1,45 +0,0 @@
package build
import (
"fmt"
"strconv"
"github.com/urfave/cli/v2"
"github.com/woodpecker-ci/woodpecker/cli/common"
"github.com/woodpecker-ci/woodpecker/cli/internal"
)
var buildKillCmd = &cli.Command{
Name: "kill",
Usage: "force kill a build",
ArgsUsage: "<repo/name> <build>",
Action: buildKill,
Hidden: true,
Flags: common.GlobalFlags,
}
func buildKill(c *cli.Context) (err error) {
repo := c.Args().First()
owner, name, err := internal.ParseRepo(repo)
if err != nil {
return err
}
number, err := strconv.Atoi(c.Args().Get(1))
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
err = client.BuildKill(owner, name, number)
if err != nil {
return err
}
fmt.Printf("Force killing build %s/%s#%d\n", owner, name, number)
return nil
}

View file

@ -1,50 +0,0 @@
package build
import (
"os"
"text/template"
"github.com/urfave/cli/v2"
"github.com/woodpecker-ci/woodpecker/cli/common"
"github.com/woodpecker-ci/woodpecker/cli/internal"
)
var buildLastCmd = &cli.Command{
Name: "last",
Usage: "show latest build details",
ArgsUsage: "<repo/name>",
Action: buildLast,
Flags: append(common.GlobalFlags,
common.FormatFlag(tmplBuildInfo),
&cli.StringFlag{
Name: "branch",
Usage: "branch name",
Value: "master",
},
),
}
func buildLast(c *cli.Context) error {
repo := c.Args().First()
owner, name, err := internal.ParseRepo(repo)
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
build, err := client.BuildLast(owner, name, c.String("branch"))
if err != nil {
return err
}
tmpl, err := template.New("_").Parse(c.String("format"))
if err != nil {
return err
}
return tmpl.Execute(os.Stdout, build)
}

View file

@ -1,53 +0,0 @@
package build
import (
"fmt"
"strconv"
"github.com/woodpecker-ci/woodpecker/cli/common"
"github.com/woodpecker-ci/woodpecker/cli/internal"
"github.com/urfave/cli/v2"
)
var buildLogsCmd = &cli.Command{
Name: "logs",
Usage: "show build logs",
ArgsUsage: "<repo/name> [build] [job]",
Action: buildLogs,
Flags: common.GlobalFlags,
}
func buildLogs(c *cli.Context) error {
repo := c.Args().First()
owner, name, err := internal.ParseRepo(repo)
if err != nil {
return err
}
number, err := strconv.Atoi(c.Args().Get(1))
if err != nil {
return err
}
job, err := strconv.Atoi(c.Args().Get(2))
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
logs, err := client.BuildLogs(owner, name, number, job)
if err != nil {
return err
}
for _, log := range logs {
fmt.Print(log.Output)
}
return nil
}

View file

@ -1,80 +0,0 @@
package build
import (
"os"
"strconv"
"text/template"
"github.com/urfave/cli/v2"
"github.com/woodpecker-ci/woodpecker/cli/common"
"github.com/woodpecker-ci/woodpecker/cli/internal"
)
var buildPsCmd = &cli.Command{
Name: "ps",
Usage: "show build steps",
ArgsUsage: "<repo/name> [build]",
Action: buildPs,
Flags: append(common.GlobalFlags,
common.FormatFlag(tmplBuildPs),
),
}
func buildPs(c *cli.Context) error {
repo := c.Args().First()
owner, name, err := internal.ParseRepo(repo)
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
buildArg := c.Args().Get(1)
var number int
if buildArg == "last" || len(buildArg) == 0 {
// Fetch the build number from the last build
build, err := client.BuildLast(owner, name, "")
if err != nil {
return err
}
number = build.Number
} else {
number, err = strconv.Atoi(buildArg)
if err != nil {
return err
}
}
build, err := client.Build(owner, name, number)
if err != nil {
return err
}
tmpl, err := template.New("_").Parse(c.String("format") + "\n")
if err != nil {
return err
}
for _, proc := range build.Procs {
for _, child := range proc.Children {
if err := tmpl.Execute(os.Stdout, child); err != nil {
return err
}
}
}
return nil
}
// template for build ps information
var tmplBuildPs = "\x1b[33mProc #{{ .PID }} \x1b[0m" + `
Step: {{ .Name }}
State: {{ .State }}
`

View file

@ -1,62 +0,0 @@
package build
import (
"fmt"
"os"
"text/template"
"github.com/urfave/cli/v2"
"github.com/woodpecker-ci/woodpecker/cli/common"
"github.com/woodpecker-ci/woodpecker/cli/internal"
)
var buildQueueCmd = &cli.Command{
Name: "queue",
Usage: "show build queue",
ArgsUsage: " ",
Action: buildQueue,
Flags: append(common.GlobalFlags,
common.FormatFlag(tmplBuildQueue),
),
}
func buildQueue(c *cli.Context) error {
client, err := internal.NewClient(c)
if err != nil {
return err
}
builds, err := client.BuildQueue()
if err != nil {
return err
}
if len(builds) == 0 {
fmt.Println("there are no pending or running builds")
return nil
}
tmpl, err := template.New("_").Parse(c.String("format") + "\n")
if err != nil {
return err
}
for _, build := range builds {
if err := tmpl.Execute(os.Stdout, build); err != nil {
return err
}
}
return nil
}
// template for build list information
var tmplBuildQueue = "\x1b[33m{{ .FullName }} #{{ .Number }} \x1b[0m" + `
Status: {{ .Status }}
Event: {{ .Event }}
Commit: {{ .Commit }}
Branch: {{ .Branch }}
Ref: {{ .Ref }}
Author: {{ .Author }} {{ if .Email }}<{{.Email}}>{{ end }}
Message: {{ .Message }}
`

View file

@ -1,68 +0,0 @@
package build
import (
"errors"
"fmt"
"strconv"
"github.com/urfave/cli/v2"
"github.com/woodpecker-ci/woodpecker/cli/common"
"github.com/woodpecker-ci/woodpecker/cli/internal"
)
var buildStartCmd = &cli.Command{
Name: "start",
Usage: "start a build",
ArgsUsage: "<repo/name> [build]",
Action: buildStart,
Flags: append(common.GlobalFlags,
&cli.StringSliceFlag{
Name: "param",
Aliases: []string{"p"},
Usage: "custom parameters to be injected into the job environment. Format: KEY=value",
},
),
}
func buildStart(c *cli.Context) (err error) {
repo := c.Args().First()
owner, name, err := internal.ParseRepo(repo)
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
buildArg := c.Args().Get(1)
var number int
if buildArg == "last" {
// Fetch the build number from the last build
build, err := client.BuildLast(owner, name, "")
if err != nil {
return err
}
number = build.Number
} else {
if len(buildArg) == 0 {
return errors.New("missing job number")
}
number, err = strconv.Atoi(buildArg)
if err != nil {
return err
}
}
params := internal.ParseKeyPair(c.StringSlice("param"))
build, err := client.BuildStart(owner, name, number, params)
if err != nil {
return err
}
fmt.Printf("Starting build %s/%s#%d\n", owner, name, build.Number)
return nil
}

View file

@ -1,48 +0,0 @@
package build
import (
"fmt"
"strconv"
"github.com/urfave/cli/v2"
"github.com/woodpecker-ci/woodpecker/cli/common"
"github.com/woodpecker-ci/woodpecker/cli/internal"
)
var buildStopCmd = &cli.Command{
Name: "stop",
Usage: "stop a build",
ArgsUsage: "<repo/name> [build] [job]",
Flags: common.GlobalFlags,
Action: buildStop,
}
func buildStop(c *cli.Context) (err error) {
repo := c.Args().First()
owner, name, err := internal.ParseRepo(repo)
if err != nil {
return err
}
number, err := strconv.Atoi(c.Args().Get(1))
if err != nil {
return err
}
job, _ := strconv.Atoi(c.Args().Get(2))
if job == 0 {
job = 1
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
err = client.BuildStop(owner, name, number, job)
if err != nil {
return err
}
fmt.Printf("Stopping build %s/%s#%d.%d\n", owner, name, number, job)
return nil
}

View file

@ -1,3 +1,17 @@
// 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 cron package cron
import ( import (
@ -53,7 +67,7 @@ func cronList(c *cli.Context) error {
return nil return nil
} }
// template for build list information // template for pipeline list information
var tmplCronList = "\x1b[33m{{ .Name }} \x1b[0m" + ` var tmplCronList = "\x1b[33m{{ .Name }} \x1b[0m" + `
ID: {{ .ID }} ID: {{ .ID }}
Branch: {{ .Branch }} Branch: {{ .Branch }}

View file

@ -1,3 +1,17 @@
// 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 deploy package deploy
import ( import (
@ -17,7 +31,7 @@ import (
var Command = &cli.Command{ var Command = &cli.Command{
Name: "deploy", Name: "deploy",
Usage: "deploy code", Usage: "deploy code",
ArgsUsage: "<repo/name> <build> <environment>", ArgsUsage: "<repo/name> <pipeline> <environment>",
Action: deploy, Action: deploy,
Flags: append(common.GlobalFlags, Flags: append(common.GlobalFlags,
common.FormatFlag(tmplDeployInfo), common.FormatFlag(tmplDeployInfo),
@ -60,33 +74,33 @@ func deploy(c *cli.Context) error {
event := c.String("event") event := c.String("event")
status := c.String("status") status := c.String("status")
buildArg := c.Args().Get(1) pipelineArg := c.Args().Get(1)
var number int var number int
if buildArg == "last" { if pipelineArg == "last" {
// Fetch the build number from the last build // Fetch the pipeline number from the last pipeline
builds, berr := client.BuildList(owner, name) pipelines, berr := client.PipelineList(owner, name)
if berr != nil { if berr != nil {
return berr return berr
} }
for _, build := range builds { for _, pipeline := range pipelines {
if branch != "" && build.Branch != branch { if branch != "" && pipeline.Branch != branch {
continue continue
} }
if event != "" && build.Event != event { if event != "" && pipeline.Event != event {
continue continue
} }
if status != "" && build.Status != status { if status != "" && pipeline.Status != status {
continue continue
} }
if build.Number > number { if pipeline.Number > number {
number = build.Number number = pipeline.Number
} }
} }
if number == 0 { if number == 0 {
return fmt.Errorf("Cannot deploy failure build") return fmt.Errorf("Cannot deploy failure pipeline")
} }
} else { } else {
number, err = strconv.Atoi(buildArg) number, err = strconv.Atoi(pipelineArg)
if err != nil { if err != nil {
return err return err
} }

View file

@ -1,3 +1,17 @@
// 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 exec package exec
import ( import (
@ -30,7 +44,7 @@ import (
// Command exports the exec command. // Command exports the exec command.
var Command = &cli.Command{ var Command = &cli.Command{
Name: "exec", Name: "exec",
Usage: "execute a local build", Usage: "execute a local pipeline",
ArgsUsage: "[path/to/.woodpecker.yml]", ArgsUsage: "[path/to/.woodpecker.yml]",
Action: run, Action: run,
Flags: append(common.GlobalFlags, flags...), Flags: append(common.GlobalFlags, flags...),
@ -231,16 +245,16 @@ func metadataFromContext(c *cli.Context, axis matrix.Axis) frontend.Metadata {
Remote: c.String("repo-remote-url"), Remote: c.String("repo-remote-url"),
Private: c.Bool("repo-private"), Private: c.Bool("repo-private"),
}, },
Curr: frontend.Build{ Curr: frontend.Pipeline{
Number: c.Int64("build-number"), Number: c.Int64("pipeline-number"),
Parent: c.Int64("parent-build-number"), Parent: c.Int64("pipeline-parent"),
Created: c.Int64("build-created"), Created: c.Int64("pipeline-created"),
Started: c.Int64("build-started"), Started: c.Int64("pipeline-started"),
Finished: c.Int64("build-finished"), Finished: c.Int64("pipeline-finished"),
Status: c.String("build-status"), Status: c.String("pipeline-status"),
Event: c.String("build-event"), Event: c.String("pipeline-event"),
Link: c.String("build-link"), Link: c.String("pipeline-link"),
Target: c.String("build-target"), Target: c.String("pipeline-target"),
Commit: frontend.Commit{ Commit: frontend.Commit{
Sha: c.String("commit-sha"), Sha: c.String("commit-sha"),
Ref: c.String("commit-ref"), Ref: c.String("commit-ref"),
@ -254,14 +268,14 @@ func metadataFromContext(c *cli.Context, axis matrix.Axis) frontend.Metadata {
}, },
}, },
}, },
Prev: frontend.Build{ Prev: frontend.Pipeline{
Number: c.Int64("prev-build-number"), Number: c.Int64("prev-pipeline-number"),
Created: c.Int64("prev-build-created"), Created: c.Int64("prev-pipeline-created"),
Started: c.Int64("prev-build-started"), Started: c.Int64("prev-pipeline-started"),
Finished: c.Int64("prev-build-finished"), Finished: c.Int64("prev-pipeline-finished"),
Status: c.String("prev-build-status"), Status: c.String("prev-pipeline-status"),
Event: c.String("prev-build-event"), Event: c.String("prev-pipeline-event"),
Link: c.String("prev-build-link"), Link: c.String("prev-pipeline-link"),
Commit: frontend.Commit{ Commit: frontend.Commit{
Sha: c.String("prev-commit-sha"), Sha: c.String("prev-commit-sha"),
Ref: c.String("prev-commit-ref"), Ref: c.String("prev-commit-ref"),

View file

@ -26,19 +26,19 @@ var flags = []cli.Flag{
&cli.BoolFlag{ &cli.BoolFlag{
EnvVars: []string{"WOODPECKER_LOCAL"}, EnvVars: []string{"WOODPECKER_LOCAL"},
Name: "local", Name: "local",
Usage: "build from local directory", Usage: "run from local directory",
Value: true, Value: true,
}, },
&cli.DurationFlag{ &cli.DurationFlag{
EnvVars: []string{"WOODPECKER_TIMEOUT"}, EnvVars: []string{"WOODPECKER_TIMEOUT"},
Name: "timeout", Name: "timeout",
Usage: "build timeout", Usage: "pipeline timeout",
Value: time.Hour, Value: time.Hour,
}, },
&cli.StringSliceFlag{ &cli.StringSliceFlag{
EnvVars: []string{"WOODPECKER_VOLUMES"}, EnvVars: []string{"WOODPECKER_VOLUMES"},
Name: "volumes", Name: "volumes",
Usage: "build volumes", Usage: "pipeline volumes",
}, },
&cli.StringSliceFlag{ &cli.StringSliceFlag{
EnvVars: []string{"WOODPECKER_NETWORKS"}, EnvVars: []string{"WOODPECKER_NETWORKS"},
@ -131,41 +131,41 @@ var flags = []cli.Flag{
Name: "repo-private", Name: "repo-private",
}, },
&cli.IntFlag{ &cli.IntFlag{
EnvVars: []string{"CI_BUILD_NUMBER"}, EnvVars: []string{"CI_PIPELINE_NUMBER"},
Name: "build-number", Name: "pipeline-number",
}, },
&cli.IntFlag{ &cli.IntFlag{
EnvVars: []string{"CI_PARENT_BUILD_NUMBER"}, EnvVars: []string{"CI_PIPELINE_PARENT"},
Name: "parent-build-number", Name: "pipeline-parent",
}, },
&cli.Int64Flag{ &cli.Int64Flag{
EnvVars: []string{"CI_BUILD_CREATED"}, EnvVars: []string{"CI_PIPELINE_CREATED"},
Name: "build-created", Name: "pipeline-created",
}, },
&cli.Int64Flag{ &cli.Int64Flag{
EnvVars: []string{"CI_BUILD_STARTED"}, EnvVars: []string{"CI_PIPELINE_STARTED"},
Name: "build-started", Name: "pipeline-started",
}, },
&cli.Int64Flag{ &cli.Int64Flag{
EnvVars: []string{"CI_BUILD_FINISHED"}, EnvVars: []string{"CI_PIPELINE_FINISHED"},
Name: "build-finished", Name: "pipeline-finished",
}, },
&cli.StringFlag{ &cli.StringFlag{
EnvVars: []string{"CI_BUILD_STATUS"}, EnvVars: []string{"CI_PIPELINE_STATUS"},
Name: "build-status", Name: "pipeline-status",
}, },
&cli.StringFlag{ &cli.StringFlag{
EnvVars: []string{"CI_BUILD_EVENT"}, EnvVars: []string{"CI_PIPELINE_EVENT"},
Name: "build-event", Name: "pipeline-event",
Value: "manual", Value: "manual",
}, },
&cli.StringFlag{ &cli.StringFlag{
EnvVars: []string{"CI_BUILD_LINK"}, EnvVars: []string{"CI_PIPELINE_LINK"},
Name: "build-link", Name: "pipeline-link",
}, },
&cli.StringFlag{ &cli.StringFlag{
EnvVars: []string{"CI_BUILD_TARGET"}, EnvVars: []string{"CI_PIPELINE_TARGET"},
Name: "build-target", Name: "pipeline-target",
}, },
&cli.StringFlag{ &cli.StringFlag{
EnvVars: []string{"CI_COMMIT_SHA"}, EnvVars: []string{"CI_COMMIT_SHA"},
@ -200,32 +200,32 @@ var flags = []cli.Flag{
Name: "commit-author-email", Name: "commit-author-email",
}, },
&cli.IntFlag{ &cli.IntFlag{
EnvVars: []string{"CI_PREV_BUILD_NUMBER"}, EnvVars: []string{"CI_PREV_PIPELINE_NUMBER"},
Name: "prev-build-number", Name: "prev-pipeline-number",
}, },
&cli.Int64Flag{ &cli.Int64Flag{
EnvVars: []string{"CI_PREV_BUILD_CREATED"}, EnvVars: []string{"CI_PREV_PIPELINE_CREATED"},
Name: "prev-build-created", Name: "prev-pipeline-created",
}, },
&cli.Int64Flag{ &cli.Int64Flag{
EnvVars: []string{"CI_PREV_BUILD_STARTED"}, EnvVars: []string{"CI_PREV_PIPELINE_STARTED"},
Name: "prev-build-started", Name: "prev-pipeline-started",
}, },
&cli.Int64Flag{ &cli.Int64Flag{
EnvVars: []string{"CI_PREV_BUILD_FINISHED"}, EnvVars: []string{"CI_PREV_PIPELINE_FINISHED"},
Name: "prev-build-finished", Name: "prev-pipeline-finished",
}, },
&cli.StringFlag{ &cli.StringFlag{
EnvVars: []string{"CI_PREV_BUILD_STATUS"}, EnvVars: []string{"CI_PREV_PIPELINE_STATUS"},
Name: "prev-build-status", Name: "prev-pipeline-status",
}, },
&cli.StringFlag{ &cli.StringFlag{
EnvVars: []string{"CI_PREV_BUILD_EVENT"}, EnvVars: []string{"CI_PREV_PIPELINE_EVENT"},
Name: "prev-build-event", Name: "prev-pipeline-event",
}, },
&cli.StringFlag{ &cli.StringFlag{
EnvVars: []string{"CI_PREV_BUILD_LINK"}, EnvVars: []string{"CI_PREV_PIPELINE_LINK"},
Name: "prev-build-link", Name: "prev-pipeline-link",
}, },
&cli.StringFlag{ &cli.StringFlag{
EnvVars: []string{"CI_PREV_COMMIT_SHA"}, EnvVars: []string{"CI_PREV_COMMIT_SHA"},

View file

@ -1,3 +1,17 @@
// 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 exec package exec
import ( import (

View file

@ -1,3 +1,17 @@
// 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 log package log
import ( import (
@ -6,7 +20,7 @@ import (
"github.com/woodpecker-ci/woodpecker/cli/common" "github.com/woodpecker-ci/woodpecker/cli/common"
) )
// Command exports the build command set. // Command exports the log command set.
var Command = &cli.Command{ var Command = &cli.Command{
Name: "log", Name: "log",
Usage: "manage logs", Usage: "manage logs",

View file

@ -1,3 +1,17 @@
// 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 log package log
import ( import (
@ -13,7 +27,7 @@ import (
var logPurgeCmd = &cli.Command{ var logPurgeCmd = &cli.Command{
Name: "purge", Name: "purge",
Usage: "purge a log", Usage: "purge a log",
ArgsUsage: "<repo/name> <build>", ArgsUsage: "<repo/name> <pipeline>",
Action: logPurge, Action: logPurge,
Flags: common.GlobalFlags, Flags: common.GlobalFlags,
} }
@ -39,6 +53,6 @@ func logPurge(c *cli.Context) (err error) {
return err return err
} }
fmt.Printf("Purging logs for build %s/%s#%d\n", owner, name, number) fmt.Printf("Purging logs for pipeline %s/%s#%d\n", owner, name, number)
return nil return nil
} }

58
cli/pipeline/approve.go Normal file
View file

@ -0,0 +1,58 @@
// 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 pipeline
import (
"fmt"
"strconv"
"github.com/urfave/cli/v2"
"github.com/woodpecker-ci/woodpecker/cli/common"
"github.com/woodpecker-ci/woodpecker/cli/internal"
)
var pipelineApproveCmd = &cli.Command{
Name: "approve",
Usage: "approve a pipeline",
ArgsUsage: "<repo/name> <pipeline>",
Action: pipelineApprove,
Flags: common.GlobalFlags,
}
func pipelineApprove(c *cli.Context) (err error) {
repo := c.Args().First()
owner, name, err := internal.ParseRepo(repo)
if err != nil {
return err
}
number, err := strconv.Atoi(c.Args().Get(1))
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
_, err = client.PipelineApprove(owner, name, number)
if err != nil {
return err
}
fmt.Printf("Approving pipeline %s/%s#%d\n", owner, name, number)
return nil
}

View file

@ -1,4 +1,18 @@
package build // 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 pipeline
import ( import (
"os" "os"
@ -13,16 +27,16 @@ import (
"github.com/woodpecker-ci/woodpecker/cli/internal" "github.com/woodpecker-ci/woodpecker/cli/internal"
) )
var buildCreateCmd = &cli.Command{ var pipelineCreateCmd = &cli.Command{
Name: "create", Name: "create",
Usage: "create new build", Usage: "create new pipeline",
ArgsUsage: "<repo/name>", ArgsUsage: "<repo/name>",
Action: buildCreate, Action: pipelineCreate,
Flags: append(common.GlobalFlags, Flags: append(common.GlobalFlags,
common.FormatFlag(tmplBuildList), common.FormatFlag(tmplPipelineList),
&cli.StringFlag{ &cli.StringFlag{
Name: "branch", Name: "branch",
Usage: "branch to create build from", Usage: "branch to create pipeline from",
Required: true, Required: true,
}, },
&cli.StringSliceFlag{ &cli.StringSliceFlag{
@ -32,7 +46,7 @@ var buildCreateCmd = &cli.Command{
), ),
} }
func buildCreate(c *cli.Context) error { func pipelineCreate(c *cli.Context) error {
repo := c.Args().First() repo := c.Args().First()
owner, name, err := internal.ParseRepo(repo) owner, name, err := internal.ParseRepo(repo)
@ -55,12 +69,12 @@ func buildCreate(c *cli.Context) error {
} }
} }
options := &woodpecker.BuildOptions{ options := &woodpecker.PipelineOptions{
Branch: branch, Branch: branch,
Variables: variables, Variables: variables,
} }
build, err := client.BuildCreate(owner, name, options) pipeline, err := client.PipelineCreate(owner, name, options)
if err != nil { if err != nil {
return err return err
} }
@ -70,7 +84,7 @@ func buildCreate(c *cli.Context) error {
return err return err
} }
if err := tmpl.Execute(os.Stdout, build); err != nil { if err := tmpl.Execute(os.Stdout, pipeline); err != nil {
return err return err
} }

58
cli/pipeline/decline.go Normal file
View file

@ -0,0 +1,58 @@
// 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 pipeline
import (
"fmt"
"strconv"
"github.com/urfave/cli/v2"
"github.com/woodpecker-ci/woodpecker/cli/common"
"github.com/woodpecker-ci/woodpecker/cli/internal"
)
var pipelineDeclineCmd = &cli.Command{
Name: "decline",
Usage: "decline a pipeline",
ArgsUsage: "<repo/name> <pipeline>",
Action: pipelineDecline,
Flags: common.GlobalFlags,
}
func pipelineDecline(c *cli.Context) (err error) {
repo := c.Args().First()
owner, name, err := internal.ParseRepo(repo)
if err != nil {
return err
}
number, err := strconv.Atoi(c.Args().Get(1))
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
_, err = client.PipelineDecline(owner, name, number)
if err != nil {
return err
}
fmt.Printf("Declining pipeline %s/%s#%d\n", owner, name, number)
return nil
}

87
cli/pipeline/info.go Normal file
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 pipeline
import (
"os"
"strconv"
"text/template"
"github.com/urfave/cli/v2"
"github.com/woodpecker-ci/woodpecker/cli/common"
"github.com/woodpecker-ci/woodpecker/cli/internal"
)
var pipelineInfoCmd = &cli.Command{
Name: "info",
Usage: "show pipeline details",
ArgsUsage: "<repo/name> [pipeline]",
Action: pipelineInfo,
Flags: append(common.GlobalFlags,
common.FormatFlag(tmplPipelineInfo),
),
}
func pipelineInfo(c *cli.Context) error {
repo := c.Args().First()
owner, name, err := internal.ParseRepo(repo)
if err != nil {
return err
}
pipelineArg := c.Args().Get(1)
client, err := internal.NewClient(c)
if err != nil {
return err
}
var number int
if pipelineArg == "last" || len(pipelineArg) == 0 {
// Fetch the pipeline number from the last pipeline
pipeline, err := client.PipelineLast(owner, name, "")
if err != nil {
return err
}
number = pipeline.Number
} else {
number, err = strconv.Atoi(pipelineArg)
if err != nil {
return err
}
}
pipeline, err := client.Pipeline(owner, name, number)
if err != nil {
return err
}
tmpl, err := template.New("_").Parse(c.String("format"))
if err != nil {
return err
}
return tmpl.Execute(os.Stdout, pipeline)
}
// template for pipeline information
var tmplPipelineInfo = `Number: {{ .Number }}
Status: {{ .Status }}
Event: {{ .Event }}
Commit: {{ .Commit }}
Branch: {{ .Branch }}
Ref: {{ .Ref }}
Message: {{ .Message }}
Author: {{ .Author }}
`

59
cli/pipeline/kill.go Normal file
View file

@ -0,0 +1,59 @@
// 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 pipeline
import (
"fmt"
"strconv"
"github.com/urfave/cli/v2"
"github.com/woodpecker-ci/woodpecker/cli/common"
"github.com/woodpecker-ci/woodpecker/cli/internal"
)
var pipelineKillCmd = &cli.Command{
Name: "kill",
Usage: "force kill a pipeline",
ArgsUsage: "<repo/name> <pipeline>",
Action: pipelineKill,
Hidden: true,
Flags: common.GlobalFlags,
}
func pipelineKill(c *cli.Context) (err error) {
repo := c.Args().First()
owner, name, err := internal.ParseRepo(repo)
if err != nil {
return err
}
number, err := strconv.Atoi(c.Args().Get(1))
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
err = client.PipelineKill(owner, name, number)
if err != nil {
return err
}
fmt.Printf("Force killing pipeline %s/%s#%d\n", owner, name, number)
return nil
}

64
cli/pipeline/last.go Normal file
View file

@ -0,0 +1,64 @@
// 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 pipeline
import (
"os"
"text/template"
"github.com/urfave/cli/v2"
"github.com/woodpecker-ci/woodpecker/cli/common"
"github.com/woodpecker-ci/woodpecker/cli/internal"
)
var pipelineLastCmd = &cli.Command{
Name: "last",
Usage: "show latest pipeline details",
ArgsUsage: "<repo/name>",
Action: pipelineLast,
Flags: append(common.GlobalFlags,
common.FormatFlag(tmplPipelineInfo),
&cli.StringFlag{
Name: "branch",
Usage: "branch name",
Value: "master",
},
),
}
func pipelineLast(c *cli.Context) error {
repo := c.Args().First()
owner, name, err := internal.ParseRepo(repo)
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
pipeline, err := client.PipelineLast(owner, name, c.String("branch"))
if err != nil {
return err
}
tmpl, err := template.New("_").Parse(c.String("format"))
if err != nil {
return err
}
return tmpl.Execute(os.Stdout, pipeline)
}

View file

@ -1,4 +1,18 @@
package build // 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 pipeline
import ( import (
"os" "os"
@ -10,13 +24,13 @@ import (
"github.com/woodpecker-ci/woodpecker/cli/internal" "github.com/woodpecker-ci/woodpecker/cli/internal"
) )
var buildListCmd = &cli.Command{ var pipelineListCmd = &cli.Command{
Name: "ls", Name: "ls",
Usage: "show build history", Usage: "show pipeline history",
ArgsUsage: "<repo/name>", ArgsUsage: "<repo/name>",
Action: buildList, Action: pipelineList,
Flags: append(common.GlobalFlags, Flags: append(common.GlobalFlags,
common.FormatFlag(tmplBuildList), common.FormatFlag(tmplPipelineList),
&cli.StringFlag{ &cli.StringFlag{
Name: "branch", Name: "branch",
Usage: "branch filter", Usage: "branch filter",
@ -37,7 +51,7 @@ var buildListCmd = &cli.Command{
), ),
} }
func buildList(c *cli.Context) error { func pipelineList(c *cli.Context) error {
repo := c.Args().First() repo := c.Args().First()
owner, name, err := internal.ParseRepo(repo) owner, name, err := internal.ParseRepo(repo)
if err != nil { if err != nil {
@ -49,7 +63,7 @@ func buildList(c *cli.Context) error {
return err return err
} }
builds, err := client.BuildList(owner, name) pipelines, err := client.PipelineList(owner, name)
if err != nil { if err != nil {
return err return err
} }
@ -65,20 +79,20 @@ func buildList(c *cli.Context) error {
limit := c.Int("limit") limit := c.Int("limit")
var count int var count int
for _, build := range builds { for _, pipeline := range pipelines {
if count >= limit { if count >= limit {
break break
} }
if branch != "" && build.Branch != branch { if branch != "" && pipeline.Branch != branch {
continue continue
} }
if event != "" && build.Event != event { if event != "" && pipeline.Event != event {
continue continue
} }
if status != "" && build.Status != status { if status != "" && pipeline.Status != status {
continue continue
} }
if err := tmpl.Execute(os.Stdout, build); err != nil { if err := tmpl.Execute(os.Stdout, pipeline); err != nil {
return err return err
} }
count++ count++
@ -86,8 +100,8 @@ func buildList(c *cli.Context) error {
return nil return nil
} }
// template for build list information // template for pipeline list information
var tmplBuildList = "\x1b[33mBuild #{{ .Number }} \x1b[0m" + ` var tmplPipelineList = "\x1b[33mBuild #{{ .Number }} \x1b[0m" + `
Status: {{ .Status }} Status: {{ .Status }}
Event: {{ .Event }} Event: {{ .Event }}
Commit: {{ .Commit }} Commit: {{ .Commit }}

67
cli/pipeline/logs.go Normal file
View file

@ -0,0 +1,67 @@
// 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 pipeline
import (
"fmt"
"strconv"
"github.com/woodpecker-ci/woodpecker/cli/common"
"github.com/woodpecker-ci/woodpecker/cli/internal"
"github.com/urfave/cli/v2"
)
var pipelineLogsCmd = &cli.Command{
Name: "logs",
Usage: "show pipeline logs",
ArgsUsage: "<repo/name> [pipeline] [job]",
Action: pipelineLogs,
Flags: common.GlobalFlags,
}
func pipelineLogs(c *cli.Context) error {
repo := c.Args().First()
owner, name, err := internal.ParseRepo(repo)
if err != nil {
return err
}
number, err := strconv.Atoi(c.Args().Get(1))
if err != nil {
return err
}
job, err := strconv.Atoi(c.Args().Get(2))
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
logs, err := client.PipelineLogs(owner, name, number, job)
if err != nil {
return err
}
for _, log := range logs {
fmt.Print(log.Output)
}
return nil
}

43
cli/pipeline/pipeline.go Normal file
View file

@ -0,0 +1,43 @@
// 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 pipeline
import (
"github.com/urfave/cli/v2"
"github.com/woodpecker-ci/woodpecker/cli/common"
)
// Command exports the pipeline command set.
var Command = &cli.Command{
Name: "pipeline",
Aliases: []string{"build"},
Usage: "manage pipelines",
Flags: common.GlobalFlags,
Subcommands: []*cli.Command{
pipelineListCmd,
pipelineLastCmd,
pipelineLogsCmd,
pipelineInfoCmd,
pipelineStopCmd,
pipelineStartCmd,
pipelineApproveCmd,
pipelineDeclineCmd,
pipelineQueueCmd,
pipelineKillCmd,
pipelinePsCmd,
pipelineCreateCmd,
},
}

94
cli/pipeline/ps.go Normal file
View file

@ -0,0 +1,94 @@
// 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 pipeline
import (
"os"
"strconv"
"text/template"
"github.com/urfave/cli/v2"
"github.com/woodpecker-ci/woodpecker/cli/common"
"github.com/woodpecker-ci/woodpecker/cli/internal"
)
var pipelinePsCmd = &cli.Command{
Name: "ps",
Usage: "show pipeline steps",
ArgsUsage: "<repo/name> [pipeline]",
Action: pipelinePs,
Flags: append(common.GlobalFlags,
common.FormatFlag(tmplPipelinePs),
),
}
func pipelinePs(c *cli.Context) error {
repo := c.Args().First()
owner, name, err := internal.ParseRepo(repo)
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
pipelineArg := c.Args().Get(1)
var number int
if pipelineArg == "last" || len(pipelineArg) == 0 {
// Fetch the pipeline number from the last pipeline
pipeline, err := client.PipelineLast(owner, name, "")
if err != nil {
return err
}
number = pipeline.Number
} else {
number, err = strconv.Atoi(pipelineArg)
if err != nil {
return err
}
}
pipeline, err := client.Pipeline(owner, name, number)
if err != nil {
return err
}
tmpl, err := template.New("_").Parse(c.String("format") + "\n")
if err != nil {
return err
}
for _, proc := range pipeline.Procs {
for _, child := range proc.Children {
if err := tmpl.Execute(os.Stdout, child); err != nil {
return err
}
}
}
return nil
}
// template for pipeline ps information
var tmplPipelinePs = "\x1b[33mProc #{{ .PID }} \x1b[0m" + `
Step: {{ .Name }}
State: {{ .State }}
`

76
cli/pipeline/queue.go Normal file
View file

@ -0,0 +1,76 @@
// 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 pipeline
import (
"fmt"
"os"
"text/template"
"github.com/urfave/cli/v2"
"github.com/woodpecker-ci/woodpecker/cli/common"
"github.com/woodpecker-ci/woodpecker/cli/internal"
)
var pipelineQueueCmd = &cli.Command{
Name: "queue",
Usage: "show pipeline queue",
ArgsUsage: " ",
Action: pipelineQueue,
Flags: append(common.GlobalFlags,
common.FormatFlag(tmplPipelineQueue),
),
}
func pipelineQueue(c *cli.Context) error {
client, err := internal.NewClient(c)
if err != nil {
return err
}
pipelines, err := client.PipelineQueue()
if err != nil {
return err
}
if len(pipelines) == 0 {
fmt.Println("there are no pending or running pipelines")
return nil
}
tmpl, err := template.New("_").Parse(c.String("format") + "\n")
if err != nil {
return err
}
for _, pipeline := range pipelines {
if err := tmpl.Execute(os.Stdout, pipeline); err != nil {
return err
}
}
return nil
}
// template for pipeline list information
var tmplPipelineQueue = "\x1b[33m{{ .FullName }} #{{ .Number }} \x1b[0m" + `
Status: {{ .Status }}
Event: {{ .Event }}
Commit: {{ .Commit }}
Branch: {{ .Branch }}
Ref: {{ .Ref }}
Author: {{ .Author }} {{ if .Email }}<{{.Email}}>{{ end }}
Message: {{ .Message }}
`

82
cli/pipeline/start.go Normal file
View file

@ -0,0 +1,82 @@
// 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 pipeline
import (
"errors"
"fmt"
"strconv"
"github.com/urfave/cli/v2"
"github.com/woodpecker-ci/woodpecker/cli/common"
"github.com/woodpecker-ci/woodpecker/cli/internal"
)
var pipelineStartCmd = &cli.Command{
Name: "start",
Usage: "start a pipeline",
ArgsUsage: "<repo/name> [pipeline]",
Action: pipelineStart,
Flags: append(common.GlobalFlags,
&cli.StringSliceFlag{
Name: "param",
Aliases: []string{"p"},
Usage: "custom parameters to be injected into the job environment. Format: KEY=value",
},
),
}
func pipelineStart(c *cli.Context) (err error) {
repo := c.Args().First()
owner, name, err := internal.ParseRepo(repo)
if err != nil {
return err
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
pipelineArg := c.Args().Get(1)
var number int
if pipelineArg == "last" {
// Fetch the pipeline number from the last pipeline
pipeline, err := client.PipelineLast(owner, name, "")
if err != nil {
return err
}
number = pipeline.Number
} else {
if len(pipelineArg) == 0 {
return errors.New("missing job number")
}
number, err = strconv.Atoi(pipelineArg)
if err != nil {
return err
}
}
params := internal.ParseKeyPair(c.StringSlice("param"))
pipeline, err := client.PipelineStart(owner, name, number, params)
if err != nil {
return err
}
fmt.Printf("Starting pipeline %s/%s#%d\n", owner, name, pipeline.Number)
return nil
}

62
cli/pipeline/stop.go Normal file
View file

@ -0,0 +1,62 @@
// 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 pipeline
import (
"fmt"
"strconv"
"github.com/urfave/cli/v2"
"github.com/woodpecker-ci/woodpecker/cli/common"
"github.com/woodpecker-ci/woodpecker/cli/internal"
)
var pipelineStopCmd = &cli.Command{
Name: "stop",
Usage: "stop a pipeline",
ArgsUsage: "<repo/name> [pipeline] [job]",
Flags: common.GlobalFlags,
Action: pipelineStop,
}
func pipelineStop(c *cli.Context) (err error) {
repo := c.Args().First()
owner, name, err := internal.ParseRepo(repo)
if err != nil {
return err
}
number, err := strconv.Atoi(c.Args().Get(1))
if err != nil {
return err
}
job, _ := strconv.Atoi(c.Args().Get(2))
if job == 0 {
job = 1
}
client, err := internal.NewClient(c)
if err != nil {
return err
}
err = client.PipelineStop(owner, name, number, job)
if err != nil {
return err
}
fmt.Printf("Stopping pipeline %s/%s#%d.%d\n", owner, name, number, job)
return nil
}

View file

@ -1,3 +1,17 @@
// 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 registry package registry
import ( import (
@ -53,7 +67,7 @@ func registryList(c *cli.Context) error {
return nil return nil
} }
// template for build list information // template for registry list information
var tmplRegistryList = "\x1b[33m{{ .Address }} \x1b[0m" + ` var tmplRegistryList = "\x1b[33m{{ .Address }} \x1b[0m" + `
Username: {{ .Username }} Username: {{ .Username }}
Email: {{ .Email }} Email: {{ .Email }}

View file

@ -1,3 +1,17 @@
// 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 repo package repo
import ( import (
@ -38,12 +52,12 @@ var repoUpdateCmd = &cli.Command{
Usage: "repository configuration path (e.g. .woodpecker.yml)", Usage: "repository configuration path (e.g. .woodpecker.yml)",
}, },
&cli.IntFlag{ &cli.IntFlag{
Name: "build-counter", Name: "pipeline-counter",
Usage: "repository starting build number", Usage: "repository starting pipeline number",
}, },
&cli.BoolFlag{ &cli.BoolFlag{
Name: "unsafe", Name: "unsafe",
Usage: "validate updating the build-counter is unsafe", Usage: "validate updating the pipeline-counter is unsafe",
}, },
), ),
} }
@ -66,7 +80,7 @@ func repoUpdate(c *cli.Context) error {
timeout = c.Duration("timeout") timeout = c.Duration("timeout")
trusted = c.Bool("trusted") trusted = c.Bool("trusted")
gated = c.Bool("gated") gated = c.Bool("gated")
buildCounter = c.Int("build-counter") pipelineCounter = c.Int("pipeline-counter")
unsafe = c.Bool("unsafe") unsafe = c.Bool("unsafe")
) )
@ -90,11 +104,11 @@ func repoUpdate(c *cli.Context) error {
patch.Visibility = &visibility patch.Visibility = &visibility
} }
} }
if c.IsSet("build-counter") && !unsafe { if c.IsSet("pipeline-counter") && !unsafe {
fmt.Printf("Setting the build counter is an unsafe operation that could put your repository in an inconsistent state. Please use --unsafe to proceed") fmt.Printf("Setting the pipeline counter is an unsafe operation that could put your repository in an inconsistent state. Please use --unsafe to proceed")
} }
if c.IsSet("build-counter") && unsafe { if c.IsSet("pipeline-counter") && unsafe {
patch.BuildCounter = &buildCounter patch.PipelineCounter = &pipelineCounter
} }
if _, err := client.RepoPatch(owner, name, patch); err != nil { if _, err := client.RepoPatch(owner, name, patch); err != nil {

View file

@ -1,3 +1,4 @@
// Copyright 2022 Woodpecker Authors
// Copyright 2019 Laszlo Fogas // Copyright 2019 Laszlo Fogas
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
@ -80,7 +81,7 @@ var flags = []cli.Flag{
&cli.IntFlag{ &cli.IntFlag{
EnvVars: []string{"WOODPECKER_MAX_PROCS"}, EnvVars: []string{"WOODPECKER_MAX_PROCS"},
Name: "max-procs", Name: "max-procs",
Usage: "agent parallel builds", Usage: "agent parallel workflows",
Value: 1, Value: 1,
}, },
&cli.BoolFlag{ &cli.BoolFlag{

View file

@ -21,7 +21,6 @@ import (
zlog "github.com/rs/zerolog/log" zlog "github.com/rs/zerolog/log"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"github.com/woodpecker-ci/woodpecker/cli/build"
"github.com/woodpecker-ci/woodpecker/cli/common" "github.com/woodpecker-ci/woodpecker/cli/common"
"github.com/woodpecker-ci/woodpecker/cli/cron" "github.com/woodpecker-ci/woodpecker/cli/cron"
"github.com/woodpecker-ci/woodpecker/cli/deploy" "github.com/woodpecker-ci/woodpecker/cli/deploy"
@ -30,6 +29,7 @@ import (
"github.com/woodpecker-ci/woodpecker/cli/lint" "github.com/woodpecker-ci/woodpecker/cli/lint"
"github.com/woodpecker-ci/woodpecker/cli/log" "github.com/woodpecker-ci/woodpecker/cli/log"
"github.com/woodpecker-ci/woodpecker/cli/loglevel" "github.com/woodpecker-ci/woodpecker/cli/loglevel"
"github.com/woodpecker-ci/woodpecker/cli/pipeline"
"github.com/woodpecker-ci/woodpecker/cli/registry" "github.com/woodpecker-ci/woodpecker/cli/registry"
"github.com/woodpecker-ci/woodpecker/cli/repo" "github.com/woodpecker-ci/woodpecker/cli/repo"
"github.com/woodpecker-ci/woodpecker/cli/secret" "github.com/woodpecker-ci/woodpecker/cli/secret"
@ -46,7 +46,7 @@ func newApp() *cli.App {
app.EnableBashCompletion = true app.EnableBashCompletion = true
app.Flags = common.GlobalFlags app.Flags = common.GlobalFlags
app.Commands = []*cli.Command{ app.Commands = []*cli.Command{
build.Command, pipeline.Command,
log.Command, log.Command,
deploy.Command, deploy.Command,
exec.Command, exec.Command,

View file

@ -1,3 +1,4 @@
// Copyright 2022 Woodpecker Authors
// Copyright 2018 Drone.IO Inc. // Copyright 2018 Drone.IO Inc.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
@ -61,7 +62,7 @@ func setupStore(c *cli.Context) (store.Store, error) {
if datastore.SupportedDriver("sqlite3") { if datastore.SupportedDriver("sqlite3") {
log.Debug().Msgf("server has sqlite3 support") log.Debug().Msgf("server has sqlite3 support")
} else { } else {
log.Debug().Msgf("server was build with no sqlite3 support!") log.Debug().Msgf("server was built without sqlite3 support!")
} }
} }
@ -306,27 +307,27 @@ func setupMetrics(g *errgroup.Group, _store store.Store) {
pendingJobs := promauto.NewGauge(prometheus.GaugeOpts{ pendingJobs := promauto.NewGauge(prometheus.GaugeOpts{
Namespace: "woodpecker", Namespace: "woodpecker",
Name: "pending_jobs", Name: "pending_jobs",
Help: "Total number of pending build processes.", Help: "Total number of pending pipeline processes.",
}) })
waitingJobs := promauto.NewGauge(prometheus.GaugeOpts{ waitingJobs := promauto.NewGauge(prometheus.GaugeOpts{
Namespace: "woodpecker", Namespace: "woodpecker",
Name: "waiting_jobs", Name: "waiting_jobs",
Help: "Total number of builds waiting on deps.", Help: "Total number of pipeline waiting on deps.",
}) })
runningJobs := promauto.NewGauge(prometheus.GaugeOpts{ runningJobs := promauto.NewGauge(prometheus.GaugeOpts{
Namespace: "woodpecker", Namespace: "woodpecker",
Name: "running_jobs", Name: "running_jobs",
Help: "Total number of running build processes.", Help: "Total number of running pipeline processes.",
}) })
workers := promauto.NewGauge(prometheus.GaugeOpts{ workers := promauto.NewGauge(prometheus.GaugeOpts{
Namespace: "woodpecker", Namespace: "woodpecker",
Name: "worker_count", Name: "worker_count",
Help: "Total number of workers.", Help: "Total number of workers.",
}) })
builds := promauto.NewGauge(prometheus.GaugeOpts{ pipelines := promauto.NewGauge(prometheus.GaugeOpts{
Namespace: "woodpecker", Namespace: "woodpecker",
Name: "build_total_count", Name: "pipeline_total_count",
Help: "Total number of builds.", Help: "Total number of pipelines.",
}) })
users := promauto.NewGauge(prometheus.GaugeOpts{ users := promauto.NewGauge(prometheus.GaugeOpts{
Namespace: "woodpecker", Namespace: "woodpecker",
@ -353,8 +354,8 @@ func setupMetrics(g *errgroup.Group, _store store.Store) {
for { for {
repoCount, _ := _store.GetRepoCount() repoCount, _ := _store.GetRepoCount()
userCount, _ := _store.GetUserCount() userCount, _ := _store.GetUserCount()
buildCount, _ := _store.GetBuildCount() pipelineCount, _ := _store.GetPipelineCount()
builds.Set(float64(buildCount)) pipelines.Set(float64(pipelineCount))
users.Set(float64(userCount)) users.Set(float64(userCount))
repos.Set(float64(repoCount)) repos.Set(float64(repoCount))
time.Sleep(10 * time.Second) time.Sleep(10 * time.Second)

View file

@ -23,7 +23,7 @@ pipeline:
- echo "Testing.." - echo "Testing.."
``` ```
### Build steps are containers ### Pipeline steps are containers
- Define any container image as context - Define any container image as context
- either use your own and install the needed tools in custom image or - either use your own and install the needed tools in custom image or

View file

@ -47,7 +47,7 @@ pipeline:
This is the reference list of all environment variables available to your pipeline containers. These are injected into your pipeline step and plugins containers, at runtime. This is the reference list of all environment variables available to your pipeline containers. These are injected into your pipeline step and plugins containers, at runtime.
| NAME | Description | | NAME | Description |
|--------------------------------|----------------------------------------------------------------------------------------------| |----------------------------------|----------------------------------------------------------------------------------------------|
| `CI=woodpecker` | environment is woodpecker | | `CI=woodpecker` | environment is woodpecker |
| | **Repository** | | | **Repository** |
| `CI_REPO` | repository full name `<owner>/<name>` | | `CI_REPO` | repository full name `<owner>/<name>` |
@ -73,16 +73,16 @@ This is the reference list of all environment variables available to your pipeli
| `CI_COMMIT_AUTHOR` | commit author username | | `CI_COMMIT_AUTHOR` | commit author username |
| `CI_COMMIT_AUTHOR_EMAIL` | commit author email address | | `CI_COMMIT_AUTHOR_EMAIL` | commit author email address |
| `CI_COMMIT_AUTHOR_AVATAR` | commit author avatar | | `CI_COMMIT_AUTHOR_AVATAR` | commit author avatar |
| | **Current build** | | | **Current pipeline** |
| `CI_BUILD_NUMBER` | build number | | `CI_PIPELINE_NUMBER` | pipeline number |
| `CI_BUILD_PARENT` | build number of parent build | | `CI_PIPELINE_PARENT` | number of parent pipeline |
| `CI_BUILD_EVENT` | build event (push, pull_request, tag, deployment) | | `CI_PIPELINE_EVENT` | pipeline event (push, pull_request, tag, deployment) |
| `CI_BUILD_LINK` | build link in CI | | `CI_PIPELINE_LINK` | pipeline link in CI |
| `CI_BUILD_DEPLOY_TARGET` | build deploy target for `deployment` events (i.e. production) | | `CI_PIPELINE_DEPLOY_TARGET` | pipeline deploy target for `deployment` events (ie production) |
| `CI_BUILD_STATUS` | build status (success, failure) | | `CI_PIPELINE_STATUS` | pipeline status (success, failure) |
| `CI_BUILD_CREATED` | build created UNIX timestamp | | `CI_PIPELINE_CREATED` | pipeline created UNIX timestamp |
| `CI_BUILD_STARTED` | build started UNIX timestamp | | `CI_PIPELINE_STARTED` | pipeline started UNIX timestamp |
| `CI_BUILD_FINISHED` | build finished UNIX timestamp | | `CI_PIPELINE_FINISHED` | pipeline finished UNIX timestamp |
| | **Current job** | | | **Current job** |
| `CI_JOB_NUMBER` | job number | | `CI_JOB_NUMBER` | job number |
| `CI_JOB_STATUS` | job status (success, failure) | | `CI_JOB_STATUS` | job status (success, failure) |
@ -100,16 +100,16 @@ This is the reference list of all environment variables available to your pipeli
| `CI_PREV_COMMIT_AUTHOR` | previous commit author username | | `CI_PREV_COMMIT_AUTHOR` | previous commit author username |
| `CI_PREV_COMMIT_AUTHOR_EMAIL` | previous commit author email address | | `CI_PREV_COMMIT_AUTHOR_EMAIL` | previous commit author email address |
| `CI_PREV_COMMIT_AUTHOR_AVATAR` | previous commit author avatar | | `CI_PREV_COMMIT_AUTHOR_AVATAR` | previous commit author avatar |
| | **Previous build** | | | **Previous pipeline** |
| `CI_PREV_BUILD_NUMBER` | previous build number | | `CI_PREV_PIPELINE_NUMBER` | previous pipeline number |
| `CI_PREV_BUILD_PARENT` | previous build number of parent build | | `CI_PREV_PIPELINE_PARENT` | previous pipeline number of parent pipeline |
| `CI_PREV_BUILD_EVENT` | previous build event (push, pull_request, tag, deployment) | | `CI_PREV_PIPELINE_EVENT` | previous pipeline event (push, pull_request, tag, deployment) |
| `CI_PREV_BUILD_LINK` | previous build link in CI | | `CI_PREV_PIPELINE_LINK` | previous pipeline link in CI |
| `CI_PREV_BUILD_DEPLOY_TARGET` | previous build deploy target for `deployment` events (i.e. production) | | `CI_PREV_PIPELINE_DEPLOY_TARGET` | previous pipeline deploy target for `deployment` events (ie production) |
| `CI_PREV_BUILD_STATUS` | previous build status (success, failure) | | `CI_PREV_PIPELINE_STATUS` | previous pipeline status (success, failure) |
| `CI_PREV_BUILD_CREATED` | previous build created UNIX timestamp | | `CI_PREV_PIPELINE_CREATED` | previous pipeline created UNIX timestamp |
| `CI_PREV_BUILD_STARTED` | previous build started UNIX timestamp | | `CI_PREV_PIPELINE_STARTED` | previous pipeline started UNIX timestamp |
| `CI_PREV_BUILD_FINISHED` | previous build finished UNIX timestamp | | `CI_PREV_PIPELINE_FINISHED` | previous pipeline finished UNIX timestamp |
| | &emsp; | | | &emsp; |
| `CI_WORKSPACE` | Path of the workspace where source code gets cloned to | | `CI_WORKSPACE` | Path of the workspace where source code gets cloned to |
| | **System** | | | **System** |
@ -125,7 +125,7 @@ This is the reference list of all environment variables available to your pipeli
## Global environment variables ## Global environment variables
If you want specific environment variables to be available in all of your builds use the `WOODPECKER_ENVIRONMENT` setting on the Woodpecker server. Note that these can't overwrite any existing, built-in variables. If you want specific environment variables to be available in all of your pipelines use the `WOODPECKER_ENVIRONMENT` setting on the Woodpecker server. Note that these can't overwrite any existing, built-in variables.
```diff ```diff
services: services:
@ -152,7 +152,7 @@ pipeline:
## String Substitution ## String Substitution
Woodpecker provides the ability to substitute environment variables at runtime. This gives us the ability to use dynamic build or commit details in our pipeline configuration. Woodpecker provides the ability to substitute environment variables at runtime. This gives us the ability to use dynamic settings, commands and filters in our pipeline configuration.
Example commit substitution: Example commit substitution:

View file

@ -35,16 +35,16 @@ scrape_configs:
List of Prometheus metrics specific to Woodpecker: List of Prometheus metrics specific to Woodpecker:
``` ```
# HELP woodpecker_build_count Build count. # HELP woodpecker_pipeline_count Build count.
# TYPE woodpecker_build_count counter # TYPE woodpecker_pipeline_count counter
woodpecker_build_count{branch="master",pipeline="total",repo="woodpecker-ci/woodpecker",status="success"} 3 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 woodpecker_build_count{branch="mkdocs",pipeline="total",repo="woodpecker-ci/woodpecker",status="success"} 3
# HELP woodpecker_build_time Build time. # HELP woodpecker_pipeline_time Build time.
# TYPE woodpecker_build_time gauge # TYPE woodpecker_pipeline_time gauge
woodpecker_build_time{branch="master",pipeline="total",repo="woodpecker-ci/woodpecker",status="success"} 116 woodpecker_build_time{branch="master",pipeline="total",repo="woodpecker-ci/woodpecker",status="success"} 116
woodpecker_build_time{branch="mkdocs",pipeline="total",repo="woodpecker-ci/woodpecker",status="success"} 155 woodpecker_build_time{branch="mkdocs",pipeline="total",repo="woodpecker-ci/woodpecker",status="success"} 155
# HELP woodpecker_build_total_count Total number of builds. # HELP woodpecker_pipeline_total_count Total number of builds.
# TYPE woodpecker_build_total_count gauge # TYPE woodpecker_pipeline_total_count gauge
woodpecker_build_total_count 1025 woodpecker_build_total_count 1025
# HELP woodpecker_pending_jobs Total number of pending build processes. # HELP woodpecker_pending_jobs Total number of pending build processes.
# TYPE woodpecker_pending_jobs gauge # TYPE woodpecker_pending_jobs gauge

View file

@ -7,6 +7,9 @@ Some versions need some changes to the server configuration or the pipeline conf
- The signature used to verify extensions calls (like those used for the [config-extension](./30-administration/100-external-configuration-api.md)) done by the Woodpecker server switched from using a shared-secret HMac to an ed25519 key-pair. Read more about it at the [config-extensions](./30-administration/100-external-configuration-api.md) documentation. - The signature used to verify extensions calls (like those used for the [config-extension](./30-administration/100-external-configuration-api.md)) done by the Woodpecker server switched from using a shared-secret HMac to an ed25519 key-pair. Read more about it at the [config-extensions](./30-administration/100-external-configuration-api.md) documentation.
- Refactored support of old agent filter labels and expression. Learn how to use the new [filter](./20-usage/20-pipeline-syntax.md#labels) - 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 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 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_*`
## 0.15.0 ## 0.15.0

View file

@ -1,3 +1,17 @@
// 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 local package local
import ( import (
@ -99,7 +113,7 @@ func (e *local) Wait(context.Context, *types.Step) (*types.State, error) {
ExitCode := 0 ExitCode := 0
if eerr, ok := err.(*exec.ExitError); ok { if eerr, ok := err.(*exec.ExitError); ok {
ExitCode = eerr.ExitCode() ExitCode = eerr.ExitCode()
// Non-zero exit code is a build failure, but not an agent error. // Non-zero exit code is a pipeline failure, but not an agent error.
err = nil err = nil
} }
return &types.State{ return &types.State{

View file

@ -22,15 +22,15 @@ func (m *Metadata) setDroneEnviron(env map[string]string) {
env["DRONE_TAG"] = env["CI_COMMIT_TAG"] env["DRONE_TAG"] = env["CI_COMMIT_TAG"]
env["DRONE_SOURCE_BRANCH"] = env["CI_COMMIT_SOURCE_BRANCH"] env["DRONE_SOURCE_BRANCH"] = env["CI_COMMIT_SOURCE_BRANCH"]
env["DRONE_TARGET_BRANCH"] = env["CI_COMMIT_TARGET_BRANCH"] env["DRONE_TARGET_BRANCH"] = env["CI_COMMIT_TARGET_BRANCH"]
// build // pipeline
env["DRONE_BUILD_NUMBER"] = env["CI_BUILD_NUMBER"] env["DRONE_BUILD_NUMBER"] = env["CI_PIPELINE_NUMBER"]
env["DRONE_BUILD_PARENT"] = env["CI_BUILD_PARENT"] env["DRONE_BUILD_PARENT"] = env["CI_PIPELINE_PARENT"]
env["DRONE_BUILD_EVENT"] = env["CI_BUILD_EVENT"] env["DRONE_BUILD_EVENT"] = env["CI_PIPELINE_EVENT"]
env["DRONE_BUILD_STATUS"] = env["CI_BUILD_STATUS"] env["DRONE_BUILD_STATUS"] = env["CI_PIPELINE_STATUS"]
env["DRONE_BUILD_LINK"] = env["CI_BUILD_LINK"] env["DRONE_BUILD_LINK"] = env["CI_PIPELINE_LINK"]
env["DRONE_BUILD_CREATED"] = env["CI_BUILD_CREATED"] env["DRONE_BUILD_CREATED"] = env["CI_PIPELINE_CREATED"]
env["DRONE_BUILD_STARTED"] = env["CI_BUILD_STARTED"] env["DRONE_BUILD_STARTED"] = env["CI_PIPELINE_STARTED"]
env["DRONE_BUILD_FINISHED"] = env["CI_BUILD_FINISHED"] env["DRONE_BUILD_FINISHED"] = env["CI_PIPELINE_FINISHED"]
// commit // commit
env["DRONE_COMMIT"] = env["CI_COMMIT_SHA"] env["DRONE_COMMIT"] = env["CI_COMMIT_SHA"]
env["DRONE_COMMIT_BEFORE"] = env["CI_PREV_COMMIT_SHA"] env["DRONE_COMMIT_BEFORE"] = env["CI_PREV_COMMIT_SHA"]

View file

@ -37,8 +37,8 @@ type (
Metadata struct { Metadata struct {
ID string `json:"id,omitempty"` ID string `json:"id,omitempty"`
Repo Repo `json:"repo,omitempty"` Repo Repo `json:"repo,omitempty"`
Curr Build `json:"curr,omitempty"` Curr Pipeline `json:"curr,omitempty"`
Prev Build `json:"prev,omitempty"` Prev Pipeline `json:"prev,omitempty"`
Job Job `json:"job,omitempty"` Job Job `json:"job,omitempty"`
Sys System `json:"sys,omitempty"` Sys System `json:"sys,omitempty"`
} }
@ -53,8 +53,8 @@ type (
Branch string `json:"default_branch,omitempty"` Branch string `json:"default_branch,omitempty"`
} }
// Build defines runtime metadata for a build. // Pipeline defines runtime metadata for a pipeline.
Build struct { Pipeline struct {
Number int64 `json:"number,omitempty"` Number int64 `json:"number,omitempty"`
Created int64 `json:"created,omitempty"` Created int64 `json:"created,omitempty"`
Started int64 `json:"started,omitempty"` Started int64 `json:"started,omitempty"`
@ -161,15 +161,15 @@ func (m *Metadata) Environ() map[string]string {
"CI_COMMIT_TAG": "", // will be set if event is tag "CI_COMMIT_TAG": "", // will be set if event is tag
"CI_COMMIT_PULL_REQUEST": "", // will be set if event is pr "CI_COMMIT_PULL_REQUEST": "", // will be set if event is pr
"CI_BUILD_NUMBER": strconv.FormatInt(m.Curr.Number, 10), "CI_PIPELINE_NUMBER": strconv.FormatInt(m.Curr.Number, 10),
"CI_BUILD_PARENT": strconv.FormatInt(m.Curr.Parent, 10), "CI_PIPELINE_PARENT": strconv.FormatInt(m.Curr.Parent, 10),
"CI_BUILD_EVENT": m.Curr.Event, "CI_PIPELINE_EVENT": m.Curr.Event,
"CI_BUILD_LINK": m.Curr.Link, "CI_PIPELINE_LINK": m.Curr.Link,
"CI_BUILD_DEPLOY_TARGET": m.Curr.Target, "CI_PIPELINE_DEPLOY_TARGET": m.Curr.Target,
"CI_BUILD_STATUS": m.Curr.Status, "CI_PIPELINE_STATUS": m.Curr.Status,
"CI_BUILD_CREATED": strconv.FormatInt(m.Curr.Created, 10), "CI_PIPELINE_CREATED": strconv.FormatInt(m.Curr.Created, 10),
"CI_BUILD_STARTED": strconv.FormatInt(m.Curr.Started, 10), "CI_PIPELINE_STARTED": strconv.FormatInt(m.Curr.Started, 10),
"CI_BUILD_FINISHED": strconv.FormatInt(m.Curr.Finished, 10), "CI_PIPELINE_FINISHED": strconv.FormatInt(m.Curr.Finished, 10),
"CI_JOB_NUMBER": strconv.Itoa(m.Job.Number), "CI_JOB_NUMBER": strconv.Itoa(m.Job.Number),
"CI_JOB_STATUS": "", // will be set by agent "CI_JOB_STATUS": "", // will be set by agent
@ -186,15 +186,15 @@ func (m *Metadata) Environ() map[string]string {
"CI_PREV_COMMIT_AUTHOR_EMAIL": m.Prev.Commit.Author.Email, "CI_PREV_COMMIT_AUTHOR_EMAIL": m.Prev.Commit.Author.Email,
"CI_PREV_COMMIT_AUTHOR_AVATAR": m.Prev.Commit.Author.Avatar, "CI_PREV_COMMIT_AUTHOR_AVATAR": m.Prev.Commit.Author.Avatar,
"CI_PREV_BUILD_NUMBER": strconv.FormatInt(m.Prev.Number, 10), "CI_PREV_PIPELINE_NUMBER": strconv.FormatInt(m.Prev.Number, 10),
"CI_PREV_BUILD_PARENT": strconv.FormatInt(m.Prev.Parent, 10), "CI_PREV_PIPELINE_PARENT": strconv.FormatInt(m.Prev.Parent, 10),
"CI_PREV_BUILD_EVENT": m.Prev.Event, "CI_PREV_PIPELINE_EVENT": m.Prev.Event,
"CI_PREV_BUILD_LINK": m.Prev.Link, "CI_PREV_PIPELINE_LINK": m.Prev.Link,
"CI_PREV_BUILD_DEPLOY_TARGET": m.Prev.Target, "CI_PREV_PIPELINE_DEPLOY_TARGET": m.Prev.Target,
"CI_PREV_BUILD_STATUS": m.Prev.Status, "CI_PREV_PIPELINE_STATUS": m.Prev.Status,
"CI_PREV_BUILD_CREATED": strconv.FormatInt(m.Prev.Created, 10), "CI_PREV_PIPELINE_CREATED": strconv.FormatInt(m.Prev.Created, 10),
"CI_PREV_BUILD_STARTED": strconv.FormatInt(m.Prev.Started, 10), "CI_PREV_PIPELINE_STARTED": strconv.FormatInt(m.Prev.Started, 10),
"CI_PREV_BUILD_FINISHED": strconv.FormatInt(m.Prev.Finished, 10), "CI_PREV_PIPELINE_FINISHED": strconv.FormatInt(m.Prev.Finished, 10),
"CI_SYSTEM_NAME": m.Sys.Name, "CI_SYSTEM_NAME": m.Sys.Name,
"CI_SYSTEM_LINK": m.Sys.Link, "CI_SYSTEM_LINK": m.Sys.Link,
@ -204,6 +204,26 @@ func (m *Metadata) Environ() map[string]string {
// DEPRECATED // DEPRECATED
"CI_SYSTEM_ARCH": m.Sys.Platform, // TODO: remove after v1.0.x version "CI_SYSTEM_ARCH": m.Sys.Platform, // TODO: remove after v1.0.x version
// use CI_PIPELINE_*
"CI_BUILD_NUMBER": strconv.FormatInt(m.Curr.Number, 10),
"CI_BUILD_PARENT": strconv.FormatInt(m.Curr.Parent, 10),
"CI_BUILD_EVENT": m.Curr.Event,
"CI_BUILD_LINK": m.Curr.Link,
"CI_BUILD_DEPLOY_TARGET": m.Curr.Target,
"CI_BUILD_STATUS": m.Curr.Status,
"CI_BUILD_CREATED": strconv.FormatInt(m.Curr.Created, 10),
"CI_BUILD_STARTED": strconv.FormatInt(m.Curr.Started, 10),
"CI_BUILD_FINISHED": strconv.FormatInt(m.Curr.Finished, 10),
// use CI_PREV_PIPELINE_*
"CI_PREV_BUILD_NUMBER": strconv.FormatInt(m.Prev.Number, 10),
"CI_PREV_BUILD_PARENT": strconv.FormatInt(m.Prev.Parent, 10),
"CI_PREV_BUILD_EVENT": m.Prev.Event,
"CI_PREV_BUILD_LINK": m.Prev.Link,
"CI_PREV_BUILD_DEPLOY_TARGET": m.Prev.Target,
"CI_PREV_BUILD_STATUS": m.Prev.Status,
"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),
} }
if m.Curr.Event == EventTag { if m.Curr.Event == EventTag {
params["CI_COMMIT_TAG"] = strings.TrimPrefix(m.Curr.Commit.Ref, "refs/tags/") params["CI_COMMIT_TAG"] = strings.TrimPrefix(m.Curr.Commit.Ref, "refs/tags/")

View file

@ -1,3 +1,17 @@
// 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 compiler package compiler
import ( import (
@ -49,7 +63,7 @@ func WithSecret(secrets ...Secret) Option {
} }
} }
// WithMetadata configures the compiler with the repository, build // WithMetadata configures the compiler with the repository, pipeline
// and system metadata. The metadata is used to remove steps from // and system metadata. The metadata is used to remove steps from
// the compiled pipeline configuration that should be skipped. The // the compiled pipeline configuration that should be skipped. The
// metadata is also added to each container as environment variables. // metadata is also added to each container as environment variables.
@ -76,7 +90,7 @@ func WithNetrc(username, password, machine string) Option {
// WithWorkspace configures the compiler with the workspace base // WithWorkspace configures the compiler with the workspace base
// and path. The workspace base is a volume created at runtime and // and path. The workspace base is a volume created at runtime and
// mounted into all containers in the pipeline. The base and path // mounted into all containers in the pipeline. The base and path
// are joined to provide the working directory for all build and // are joined to provide the working directory for all pipeline and
// plugin steps in the pipeline. // plugin steps in the pipeline.
func WithWorkspace(base, path string) Option { func WithWorkspace(base, path string) Option {
return func(compiler *Compiler) { return func(compiler *Compiler) {
@ -177,7 +191,7 @@ func WithProxy() Option {
} }
// WithNetworks configures the compiler with additional networks // WithNetworks configures the compiler with additional networks
// to be connected to build containers // to be connected to pipeline containers
func WithNetworks(networks ...string) Option { func WithNetworks(networks ...string) Option {
return func(compiler *Compiler) { return func(compiler *Compiler) {
compiler.networks = networks compiler.networks = networks

View file

@ -1,3 +1,17 @@
// 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 compiler package compiler
import ( import (
@ -7,7 +21,7 @@ import (
"strings" "strings"
) )
// generateScriptPosix is a helper function that generates a build script // generateScriptPosix is a helper function that generates a step script
// for a linux container using the given // for a linux container using the given
func generateScriptPosix(commands []string) string { func generateScriptPosix(commands []string) string {
var buf bytes.Buffer var buf bytes.Buffer
@ -27,7 +41,7 @@ func generateScriptPosix(commands []string) string {
return base64.StdEncoding.EncodeToString([]byte(script)) return base64.StdEncoding.EncodeToString([]byte(script))
} }
// setupScript is a helper script this is added to the build to ensure // setupScript is a helper script this is added to the step script to ensure
// a minimum set of environment variables are set correctly. // a minimum set of environment variables are set correctly.
const setupScript = ` const setupScript = `
if [ -n "$CI_NETRC_MACHINE" ]; then if [ -n "$CI_NETRC_MACHINE" ]; then
@ -44,7 +58,7 @@ unset CI_SCRIPT
%s %s
` `
// traceScript is a helper script that is added to the build script // traceScript is a helper script that is added to the step script
// to trace a command. // to trace a command.
const traceScript = ` const traceScript = `
echo + %s echo + %s

View file

@ -1,3 +1,17 @@
// 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 compiler package compiler
import ( import (
@ -39,7 +53,7 @@ $netrc=[string]::Format("{0}\_netrc",$Env:HOME);
%s %s
` `
// traceScript is a helper script that is added to the build script // traceScript is a helper script that is added to the step script
// to trace a command. // to trace a command.
const traceScriptWin = ` const traceScriptWin = `
Write-Output ('+ %s'); Write-Output ('+ %s');

View file

@ -80,7 +80,7 @@ func TestParse(t *testing.T) {
g.It("Should match event tester", func() { g.It("Should match event tester", func() {
match, err := matchConfig.When.Match(frontend.Metadata{ match, err := matchConfig.When.Match(frontend.Metadata{
Curr: frontend.Build{ Curr: frontend.Pipeline{
Event: "tester", Event: "tester",
}, },
}, false) }, false)
@ -90,7 +90,7 @@ func TestParse(t *testing.T) {
g.It("Should match event tester2", func() { g.It("Should match event tester2", func() {
match, err := matchConfig.When.Match(frontend.Metadata{ match, err := matchConfig.When.Match(frontend.Metadata{
Curr: frontend.Build{ Curr: frontend.Pipeline{
Event: "tester2", Event: "tester2",
}, },
}, false) }, false)
@ -100,7 +100,7 @@ func TestParse(t *testing.T) {
g.It("Should match branch tester", func() { g.It("Should match branch tester", func() {
match, err := matchConfig.When.Match(frontend.Metadata{ match, err := matchConfig.When.Match(frontend.Metadata{
Curr: frontend.Build{ Curr: frontend.Pipeline{
Commit: frontend.Commit{ Commit: frontend.Commit{
Branch: "tester", Branch: "tester",
}, },
@ -112,7 +112,7 @@ func TestParse(t *testing.T) {
g.It("Should not match event push", func() { g.It("Should not match event push", func() {
match, err := matchConfig.When.Match(frontend.Metadata{ match, err := matchConfig.When.Match(frontend.Metadata{
Curr: frontend.Build{ Curr: frontend.Pipeline{
Event: "push", Event: "push",
}, },
}, false) }, false)

View file

@ -392,7 +392,7 @@ func TestConstraints(t *testing.T) {
desc: "no constraints, must match on default events", desc: "no constraints, must match on default events",
conf: "", conf: "",
with: frontend.Metadata{ with: frontend.Metadata{
Curr: frontend.Build{ Curr: frontend.Pipeline{
Event: frontend.EventPush, Event: frontend.EventPush,
}, },
}, },
@ -401,99 +401,99 @@ func TestConstraints(t *testing.T) {
{ {
desc: "global branch filter", desc: "global branch filter",
conf: "{ branch: develop }", conf: "{ branch: develop }",
with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventPush, Commit: frontend.Commit{Branch: "master"}}}, with: frontend.Metadata{Curr: frontend.Pipeline{Event: frontend.EventPush, Commit: frontend.Commit{Branch: "master"}}},
want: false, want: false,
}, },
{ {
desc: "global branch filter", desc: "global branch filter",
conf: "{ branch: master }", conf: "{ branch: master }",
with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventPush, Commit: frontend.Commit{Branch: "master"}}}, with: frontend.Metadata{Curr: frontend.Pipeline{Event: frontend.EventPush, Commit: frontend.Commit{Branch: "master"}}},
want: true, want: true,
}, },
{ {
desc: "repo constraint", desc: "repo constraint",
conf: "{ repo: owner/* }", conf: "{ repo: owner/* }",
with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventPush}, Repo: frontend.Repo{Name: "owner/repo"}}, with: frontend.Metadata{Curr: frontend.Pipeline{Event: frontend.EventPush}, Repo: frontend.Repo{Name: "owner/repo"}},
want: true, want: true,
}, },
{ {
desc: "repo constraint", desc: "repo constraint",
conf: "{ repo: octocat/* }", conf: "{ repo: octocat/* }",
with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventPush}, Repo: frontend.Repo{Name: "owner/repo"}}, with: frontend.Metadata{Curr: frontend.Pipeline{Event: frontend.EventPush}, Repo: frontend.Repo{Name: "owner/repo"}},
want: false, want: false,
}, },
{ {
desc: "ref constraint", desc: "ref constraint",
conf: "{ ref: refs/tags/* }", conf: "{ ref: refs/tags/* }",
with: frontend.Metadata{Curr: frontend.Build{Commit: frontend.Commit{Ref: "refs/tags/v1.0.0"}, Event: frontend.EventPush}}, with: frontend.Metadata{Curr: frontend.Pipeline{Commit: frontend.Commit{Ref: "refs/tags/v1.0.0"}, Event: frontend.EventPush}},
want: true, want: true,
}, },
{ {
desc: "ref constraint", desc: "ref constraint",
conf: "{ ref: refs/tags/* }", conf: "{ ref: refs/tags/* }",
with: frontend.Metadata{Curr: frontend.Build{Commit: frontend.Commit{Ref: "refs/heads/master"}, Event: frontend.EventPush}}, with: frontend.Metadata{Curr: frontend.Pipeline{Commit: frontend.Commit{Ref: "refs/heads/master"}, Event: frontend.EventPush}},
want: false, want: false,
}, },
{ {
desc: "platform constraint", desc: "platform constraint",
conf: "{ platform: linux/amd64 }", conf: "{ platform: linux/amd64 }",
with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventPush}, Sys: frontend.System{Platform: "linux/amd64"}}, with: frontend.Metadata{Curr: frontend.Pipeline{Event: frontend.EventPush}, Sys: frontend.System{Platform: "linux/amd64"}},
want: true, want: true,
}, },
{ {
desc: "platform constraint", desc: "platform constraint",
conf: "{ repo: linux/amd64 }", conf: "{ repo: linux/amd64 }",
with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventPush}, Sys: frontend.System{Platform: "windows/amd64"}}, with: frontend.Metadata{Curr: frontend.Pipeline{Event: frontend.EventPush}, Sys: frontend.System{Platform: "windows/amd64"}},
want: false, want: false,
}, },
{ {
desc: "instance constraint", desc: "instance constraint",
conf: "{ instance: agent.tld }", conf: "{ instance: agent.tld }",
with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventPush}, Sys: frontend.System{Host: "agent.tld"}}, with: frontend.Metadata{Curr: frontend.Pipeline{Event: frontend.EventPush}, Sys: frontend.System{Host: "agent.tld"}},
want: true, want: true,
}, },
{ {
desc: "instance constraint", desc: "instance constraint",
conf: "{ instance: agent.tld }", conf: "{ instance: agent.tld }",
with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventPush}, Sys: frontend.System{Host: "beta.agent.tld"}}, with: frontend.Metadata{Curr: frontend.Pipeline{Event: frontend.EventPush}, Sys: frontend.System{Host: "beta.agent.tld"}},
want: false, want: false,
}, },
{ {
desc: "filter cron by default constraint", desc: "filter cron by default constraint",
conf: "{}", conf: "{}",
with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventCron}}, with: frontend.Metadata{Curr: frontend.Pipeline{Event: frontend.EventCron}},
want: false, want: false,
}, },
{ {
desc: "filter cron by matching name", desc: "filter cron by matching name",
conf: "{ event: cron, cron: job1 }", conf: "{ event: cron, cron: job1 }",
with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventCron, Cron: "job1"}}, with: frontend.Metadata{Curr: frontend.Pipeline{Event: frontend.EventCron, Cron: "job1"}},
want: true, want: true,
}, },
{ {
desc: "filter cron by name", desc: "filter cron by name",
conf: "{ event: cron, cron: job2 }", conf: "{ event: cron, cron: job2 }",
with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventCron, Cron: "job1"}}, with: frontend.Metadata{Curr: frontend.Pipeline{Event: frontend.EventCron, Cron: "job1"}},
want: false, want: false,
}, },
{ {
desc: "no constraints, event gets filtered by default event filter", desc: "no constraints, event gets filtered by default event filter",
conf: "", conf: "",
with: frontend.Metadata{ with: frontend.Metadata{
Curr: frontend.Build{Event: "non-default"}, Curr: frontend.Pipeline{Event: "non-default"},
}, },
want: false, want: false,
}, },
{ {
desc: "filter by eval based on event", desc: "filter by eval based on event",
conf: `{ evaluate: 'CI_BUILD_EVENT == "push"' }`, conf: `{ evaluate: 'CI_PIPELINE_EVENT == "push"' }`,
with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventPush}}, with: frontend.Metadata{Curr: frontend.Pipeline{Event: frontend.EventPush}},
want: true, want: true,
}, },
{ {
desc: "filter by eval based on event and repo", desc: "filter by eval based on event and repo",
conf: `{ evaluate: 'CI_BUILD_EVENT == "push" && CI_REPO == "owner/repo"' }`, conf: `{ evaluate: 'CI_PIPELINE_EVENT == "push" && CI_REPO == "owner/repo"' }`,
with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventPush}, Repo: frontend.Repo{Name: "owner/repo"}}, with: frontend.Metadata{Curr: frontend.Pipeline{Event: frontend.EventPush}, Repo: frontend.Repo{Name: "owner/repo"}},
want: true, want: true,
}, },
} }

View file

@ -1,3 +1,17 @@
// 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 matrix package matrix
import ( import (
@ -13,10 +27,10 @@ const (
limitAxis = 25 limitAxis = 25
) )
// Matrix represents the build matrix. // Matrix represents the pipeline matrix.
type Matrix map[string][]string type Matrix map[string][]string
// Axis represents a single permutation of entries from the build matrix. // Axis represents a single permutation of entries from the pipeline matrix.
type Axis map[string]string type Axis map[string]string
// String returns a string representation of an Axis as a comma-separated list // String returns a string representation of an Axis as a comma-separated list
@ -79,7 +93,7 @@ func calc(matrix Matrix) []Axis {
elem := p / decr % len(elems) elem := p / decr % len(elems)
axis[tag] = elems[elem] axis[tag] = elems[elem]
// enforce a maximum number of tags in the build matrix. // enforce a maximum number of tags in the pipeline matrix.
if i > limitTags { if i > limitTags {
break break
} }

View file

@ -1,6 +1,6 @@
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // versions:
// protoc-gen-go v1.28.0 // protoc-gen-go v1.28.1
// protoc v3.12.4 // protoc v3.12.4
// source: woodpecker.proto // source: woodpecker.proto

View file

@ -29,6 +29,10 @@ var DefaultTracer = TraceFunc(func(state *State) error {
if state.Pipeline.Step.Environment == nil { if state.Pipeline.Step.Environment == nil {
return nil return nil
} }
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)
// DEPRECATED
state.Pipeline.Step.Environment["CI_BUILD_STATUS"] = "success" 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_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_BUILD_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
@ -38,7 +42,10 @@ var DefaultTracer = TraceFunc(func(state *State) error {
state.Pipeline.Step.Environment["CI_JOB_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10) state.Pipeline.Step.Environment["CI_JOB_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
if state.Pipeline.Error != nil { if state.Pipeline.Error != nil {
state.Pipeline.Step.Environment["CI_PIPELINE_STATUS"] = "failure"
// DEPRECATED
state.Pipeline.Step.Environment["CI_BUILD_STATUS"] = "failure" state.Pipeline.Step.Environment["CI_BUILD_STATUS"] = "failure"
state.Pipeline.Step.Environment["CI_JOB_STATUS"] = "failure" state.Pipeline.Step.Environment["CI_JOB_STATUS"] = "failure"
} }
return nil return nil

View file

@ -1,5 +1,6 @@
// Copyright 2018 Drone.IO Inc. // Copyright 2022 Woodpecker Authors
// Copyright 2021 Informatyka Boguslawski sp. z o.o. sp.k., http://www.ib.pl/ // Copyright 2021 Informatyka Boguslawski sp. z o.o. sp.k., http://www.ib.pl/
// Copyright 2018 Drone.IO Inc.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@ -47,15 +48,15 @@ func GetBadge(c *gin.Context) {
branch = repo.Branch branch = repo.Branch
} }
build, err := _store.GetBuildLast(repo, branch) pipeline, err := _store.GetPipelineLast(repo, branch)
if err != nil { if err != nil {
log.Warn().Err(err).Msg("") log.Warn().Err(err).Msg("")
build = nil pipeline = nil
} }
// we serve an SVG, so set content type appropriately. // we serve an SVG, so set content type appropriately.
c.Writer.Header().Set("Content-Type", "image/svg+xml") c.Writer.Header().Set("Content-Type", "image/svg+xml")
c.String(http.StatusOK, badges.Generate(build)) c.String(http.StatusOK, badges.Generate(pipeline))
} }
func GetCC(c *gin.Context) { func GetCC(c *gin.Context) {
@ -66,13 +67,13 @@ func GetCC(c *gin.Context) {
return return
} }
builds, err := _store.GetBuildList(repo, 1) pipelines, err := _store.GetPipelineList(repo, 1)
if err != nil || len(builds) == 0 { if err != nil || len(pipelines) == 0 {
c.AbortWithStatus(404) c.AbortWithStatus(404)
return return
} }
url := fmt.Sprintf("%s/%s/%d", server.Config.Server.Host, repo.FullName, builds[0].Number) url := fmt.Sprintf("%s/%s/%d", server.Config.Server.Host, repo.FullName, pipelines[0].Number)
cc := ccmenu.New(repo, builds[0], url) cc := ccmenu.New(repo, pipelines[0], url)
c.XML(200, cc) c.XML(200, cc)
} }

View file

@ -1,3 +1,4 @@
// Copyright 2022 Woodpecker Authors
// Copyright 2018 Drone.IO Inc. // Copyright 2018 Drone.IO Inc.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
@ -27,7 +28,7 @@ import (
"github.com/woodpecker-ci/woodpecker/server/store" "github.com/woodpecker-ci/woodpecker/server/store"
) )
// FileList gets a list file by build. // FileList gets a list file by pipeline.
func FileList(c *gin.Context) { func FileList(c *gin.Context) {
_store := store.FromContext(c) _store := store.FromContext(c)
num, err := strconv.ParseInt(c.Param("number"), 10, 64) num, err := strconv.ParseInt(c.Param("number"), 10, 64)
@ -37,13 +38,13 @@ func FileList(c *gin.Context) {
} }
repo := session.Repo(c) repo := session.Repo(c)
build, err := _store.GetBuildNumber(repo, num) pipeline, err := _store.GetPipelineNumber(repo, num)
if err != nil { if err != nil {
_ = c.AbortWithError(http.StatusInternalServerError, err) _ = c.AbortWithError(http.StatusInternalServerError, err)
return return
} }
files, err := _store.FileList(build) files, err := _store.FileList(pipeline)
if err != nil { if err != nil {
_ = c.AbortWithError(http.StatusInternalServerError, err) _ = c.AbortWithError(http.StatusInternalServerError, err)
return return
@ -76,13 +77,13 @@ func FileGet(c *gin.Context) {
return return
} }
build, err := _store.GetBuildNumber(repo, num) pipeline, err := _store.GetPipelineNumber(repo, num)
if err != nil { if err != nil {
_ = c.AbortWithError(http.StatusInternalServerError, err) _ = c.AbortWithError(http.StatusInternalServerError, err)
return return
} }
proc, err := _store.ProcFind(build, pid) proc, err := _store.ProcFind(pipeline, pid)
if err != nil { if err != nil {
_ = c.AbortWithError(http.StatusInternalServerError, err) _ = c.AbortWithError(http.StatusInternalServerError, err)
return return

View file

@ -1,5 +1,6 @@
// Copyright 2018 Drone.IO Inc. // Copyright 2022 Woodpecker Authors
// Copyright 2021 Informatyka Boguslawski sp. z o.o. sp.k., http://www.ib.pl/ // Copyright 2021 Informatyka Boguslawski sp. z o.o. sp.k., http://www.ib.pl/
// Copyright 2018 Drone.IO Inc.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@ -79,7 +80,7 @@ func PostHook(c *gin.Context) {
return return
} }
if tmpBuild == nil { if tmpBuild == nil {
msg := "ignoring hook: hook parsing resulted in empty build" msg := "ignoring hook: hook parsing resulted in empty pipeline"
log.Debug().Msg(msg) log.Debug().Msg(msg)
c.String(http.StatusOK, msg) c.String(http.StatusOK, msg)
return return
@ -174,10 +175,10 @@ func PostHook(c *gin.Context) {
return return
} }
build, err := pipeline.Create(c, _store, repo, tmpBuild) pl, err := pipeline.Create(c, _store, repo, tmpBuild)
if err != nil { if err != nil {
handlePipelineErr(c, err) handlePipelineErr(c, err)
} else { } else {
c.JSON(200, build) c.JSON(200, pl)
} }
} }

View file

@ -1,5 +1,6 @@
// Copyright 2018 Drone.IO Inc. // Copyright 2022 Woodpecker Authors
// Copyright 2021 Informatyka Boguslawski sp. z o.o. sp.k., http://www.ib.pl/ // Copyright 2021 Informatyka Boguslawski sp. z o.o. sp.k., http://www.ib.pl/
// Copyright 2018 Drone.IO Inc.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@ -37,11 +38,11 @@ import (
"github.com/woodpecker-ci/woodpecker/server/store" "github.com/woodpecker-ci/woodpecker/server/store"
) )
func CreateBuild(c *gin.Context) { func CreatePipeline(c *gin.Context) {
_store := store.FromContext(c) _store := store.FromContext(c)
repo := session.Repo(c) repo := session.Repo(c)
var p model.BuildOptions var p model.PipelineOptions
err := json.NewDecoder(c.Request.Body).Decode(&p) err := json.NewDecoder(c.Request.Body).Decode(&p)
if err != nil { if err != nil {
@ -53,25 +54,25 @@ func CreateBuild(c *gin.Context) {
lastCommit, _ := server.Config.Services.Remote.BranchHead(c, user, repo, p.Branch) lastCommit, _ := server.Config.Services.Remote.BranchHead(c, user, repo, p.Branch)
tmpBuild := createTmpBuild(model.EventManual, lastCommit, repo, user, &p) tmpBuild := createTmpPipeline(model.EventManual, lastCommit, repo, user, &p)
build, err := pipeline.Create(c, _store, repo, tmpBuild) pl, err := pipeline.Create(c, _store, repo, tmpBuild)
if err != nil { if err != nil {
handlePipelineErr(c, err) handlePipelineErr(c, err)
} else { } else {
c.JSON(http.StatusOK, build) c.JSON(http.StatusOK, pl)
} }
} }
func createTmpBuild(event model.WebhookEvent, commitSHA string, repo *model.Repo, user *model.User, opts *model.BuildOptions) *model.Build { func createTmpPipeline(event model.WebhookEvent, commitSHA string, repo *model.Repo, user *model.User, opts *model.PipelineOptions) *model.Pipeline {
return &model.Build{ return &model.Pipeline{
Event: event, Event: event,
Commit: commitSHA, Commit: commitSHA,
Branch: opts.Branch, Branch: opts.Branch,
Timestamp: time.Now().UTC().Unix(), Timestamp: time.Now().UTC().Unix(),
Avatar: user.Avatar, Avatar: user.Avatar,
Message: "MANUAL BUILD @ " + opts.Branch, Message: "MANUAL PIPELINE @ " + opts.Branch,
Ref: opts.Branch, Ref: opts.Branch,
AdditionalVariables: opts.Variables, AdditionalVariables: opts.Variables,
@ -84,7 +85,7 @@ func createTmpBuild(event model.WebhookEvent, commitSHA string, repo *model.Repo
} }
} }
func GetBuilds(c *gin.Context) { func GetPipelines(c *gin.Context) {
repo := session.Repo(c) repo := session.Repo(c)
page, err := strconv.Atoi(c.DefaultQuery("page", "1")) page, err := strconv.Atoi(c.DefaultQuery("page", "1"))
if err != nil { if err != nil {
@ -92,18 +93,18 @@ func GetBuilds(c *gin.Context) {
return return
} }
builds, err := store.FromContext(c).GetBuildList(repo, page) pipelines, err := store.FromContext(c).GetPipelineList(repo, page)
if err != nil { if err != nil {
c.AbortWithStatus(http.StatusInternalServerError) c.AbortWithStatus(http.StatusInternalServerError)
return return
} }
c.JSON(http.StatusOK, builds) c.JSON(http.StatusOK, pipelines)
} }
func GetBuild(c *gin.Context) { func GetPipeline(c *gin.Context) {
_store := store.FromContext(c) _store := store.FromContext(c)
if c.Param("number") == "latest" { if c.Param("number") == "latest" {
GetBuildLast(c) GetPipelineLast(c)
return return
} }
@ -114,62 +115,62 @@ func GetBuild(c *gin.Context) {
return return
} }
build, err := _store.GetBuildNumber(repo, num) pl, err := _store.GetPipelineNumber(repo, num)
if err != nil { if err != nil {
_ = c.AbortWithError(http.StatusInternalServerError, err) _ = c.AbortWithError(http.StatusInternalServerError, err)
return return
} }
files, _ := _store.FileList(build) files, _ := _store.FileList(pl)
procs, _ := _store.ProcList(build) procs, _ := _store.ProcList(pl)
if build.Procs, err = model.Tree(procs); err != nil { if pl.Procs, err = model.Tree(procs); err != nil {
_ = c.AbortWithError(http.StatusInternalServerError, err) _ = c.AbortWithError(http.StatusInternalServerError, err)
return return
} }
build.Files = files pl.Files = files
c.JSON(http.StatusOK, build) c.JSON(http.StatusOK, pl)
} }
func GetBuildLast(c *gin.Context) { func GetPipelineLast(c *gin.Context) {
_store := store.FromContext(c) _store := store.FromContext(c)
repo := session.Repo(c) repo := session.Repo(c)
branch := c.DefaultQuery("branch", repo.Branch) branch := c.DefaultQuery("branch", repo.Branch)
build, err := _store.GetBuildLast(repo, branch) pl, err := _store.GetPipelineLast(repo, branch)
if err != nil { if err != nil {
c.String(http.StatusInternalServerError, err.Error()) c.String(http.StatusInternalServerError, err.Error())
return return
} }
procs, err := _store.ProcList(build) procs, err := _store.ProcList(pl)
if err != nil { if err != nil {
_ = c.AbortWithError(http.StatusInternalServerError, err) _ = c.AbortWithError(http.StatusInternalServerError, err)
return return
} }
if build.Procs, err = model.Tree(procs); err != nil { if pl.Procs, err = model.Tree(procs); err != nil {
_ = c.AbortWithError(http.StatusInternalServerError, err) _ = c.AbortWithError(http.StatusInternalServerError, err)
return return
} }
c.JSON(http.StatusOK, build) c.JSON(http.StatusOK, pl)
} }
func GetBuildLogs(c *gin.Context) { func GetPipelineLogs(c *gin.Context) {
_store := store.FromContext(c) _store := store.FromContext(c)
repo := session.Repo(c) repo := session.Repo(c)
// parse the build number and job sequence number from // parse the pipeline number and job sequence number from
// the request parameter. // the request parameter.
num, _ := strconv.ParseInt(c.Params.ByName("number"), 10, 64) num, _ := strconv.ParseInt(c.Params.ByName("number"), 10, 64)
ppid, _ := strconv.Atoi(c.Params.ByName("pid")) ppid, _ := strconv.Atoi(c.Params.ByName("pid"))
name := c.Params.ByName("proc") name := c.Params.ByName("proc")
build, err := _store.GetBuildNumber(repo, num) pl, err := _store.GetPipelineNumber(repo, num)
if err != nil { if err != nil {
_ = c.AbortWithError(404, err) _ = c.AbortWithError(404, err)
return return
} }
proc, err := _store.ProcChild(build, ppid, name) proc, err := _store.ProcChild(pl, ppid, name)
if err != nil { if err != nil {
_ = c.AbortWithError(404, err) _ = c.AbortWithError(404, err)
return return
@ -193,18 +194,18 @@ func GetProcLogs(c *gin.Context) {
_store := store.FromContext(c) _store := store.FromContext(c)
repo := session.Repo(c) repo := session.Repo(c)
// parse the build number and job sequence number from // parse the pipeline number and job sequence number from
// the request parameter. // the request parameter.
num, _ := strconv.ParseInt(c.Params.ByName("number"), 10, 64) num, _ := strconv.ParseInt(c.Params.ByName("number"), 10, 64)
pid, _ := strconv.Atoi(c.Params.ByName("pid")) pid, _ := strconv.Atoi(c.Params.ByName("pid"))
build, err := _store.GetBuildNumber(repo, num) pl, err := _store.GetPipelineNumber(repo, num)
if err != nil { if err != nil {
_ = c.AbortWithError(http.StatusNotFound, err) _ = c.AbortWithError(http.StatusNotFound, err)
return return
} }
proc, err := _store.ProcFind(build, pid) proc, err := _store.ProcFind(pl, pid)
if err != nil { if err != nil {
_ = c.AbortWithError(http.StatusNotFound, err) _ = c.AbortWithError(http.StatusNotFound, err)
return return
@ -224,7 +225,7 @@ func GetProcLogs(c *gin.Context) {
} }
} }
func GetBuildConfig(c *gin.Context) { func GetPipelineConfig(c *gin.Context) {
_store := store.FromContext(c) _store := store.FromContext(c)
repo := session.Repo(c) repo := session.Repo(c)
num, err := strconv.ParseInt(c.Param("number"), 10, 64) num, err := strconv.ParseInt(c.Param("number"), 10, 64)
@ -233,13 +234,13 @@ func GetBuildConfig(c *gin.Context) {
return return
} }
build, err := _store.GetBuildNumber(repo, num) pl, err := _store.GetPipelineNumber(repo, num)
if err != nil { if err != nil {
_ = c.AbortWithError(http.StatusInternalServerError, err) _ = c.AbortWithError(http.StatusInternalServerError, err)
return return
} }
configs, err := _store.ConfigsForBuild(build.ID) configs, err := _store.ConfigsForPipeline(pl.ID)
if err != nil { if err != nil {
c.String(http.StatusInternalServerError, err.Error()) c.String(http.StatusInternalServerError, err.Error())
return return
@ -248,19 +249,19 @@ func GetBuildConfig(c *gin.Context) {
c.JSON(http.StatusOK, configs) c.JSON(http.StatusOK, configs)
} }
// DeleteBuild cancels a build // DeletePipeline cancels a pipeline
func DeleteBuild(c *gin.Context) { func DeletePipeline(c *gin.Context) {
_store := store.FromContext(c) _store := store.FromContext(c)
repo := session.Repo(c) repo := session.Repo(c)
num, _ := strconv.ParseInt(c.Params.ByName("number"), 10, 64) num, _ := strconv.ParseInt(c.Params.ByName("number"), 10, 64)
build, err := _store.GetBuildNumber(repo, num) pl, err := _store.GetPipelineNumber(repo, num)
if err != nil { if err != nil {
_ = c.AbortWithError(http.StatusNotFound, err) _ = c.AbortWithError(http.StatusNotFound, err)
return return
} }
if err := pipeline.Cancel(c, _store, repo, build); err != nil { if err := pipeline.Cancel(c, _store, repo, pl); err != nil {
handlePipelineErr(c, err) handlePipelineErr(c, err)
} else { } else {
c.Status(http.StatusNoContent) c.Status(http.StatusNoContent)
@ -276,17 +277,17 @@ func PostApproval(c *gin.Context) {
num, _ = strconv.ParseInt(c.Params.ByName("number"), 10, 64) num, _ = strconv.ParseInt(c.Params.ByName("number"), 10, 64)
) )
build, err := _store.GetBuildNumber(repo, num) pl, err := _store.GetPipelineNumber(repo, num)
if err != nil { if err != nil {
_ = c.AbortWithError(404, err) _ = c.AbortWithError(404, err)
return return
} }
newBuild, err := pipeline.Approve(c, _store, build, user, repo) newpipeline, err := pipeline.Approve(c, _store, pl, user, repo)
if err != nil { if err != nil {
handlePipelineErr(c, err) handlePipelineErr(c, err)
} else { } else {
c.JSON(200, newBuild) c.JSON(200, newpipeline)
} }
} }
@ -299,31 +300,31 @@ func PostDecline(c *gin.Context) {
num, _ = strconv.ParseInt(c.Params.ByName("number"), 10, 64) num, _ = strconv.ParseInt(c.Params.ByName("number"), 10, 64)
) )
build, err := _store.GetBuildNumber(repo, num) pl, err := _store.GetPipelineNumber(repo, num)
if err != nil { if err != nil {
c.String(http.StatusNotFound, "%v", err) c.String(http.StatusNotFound, "%v", err)
return return
} }
build, err = pipeline.Decline(c, _store, build, user, repo) pl, err = pipeline.Decline(c, _store, pl, user, repo)
if err != nil { if err != nil {
handlePipelineErr(c, err) handlePipelineErr(c, err)
} else { } else {
c.JSON(200, build) c.JSON(200, pl)
} }
} }
func GetBuildQueue(c *gin.Context) { func GetPipelineQueue(c *gin.Context) {
out, err := store.FromContext(c).GetBuildQueue() out, err := store.FromContext(c).GetPipelineQueue()
if err != nil { if err != nil {
c.String(500, "Error getting build queue. %s", err) c.String(500, "Error getting pipeline queue. %s", err)
return return
} }
c.JSON(200, out) c.JSON(200, out)
} }
// PostBuild restarts a build optional with altered event, deploy or environment // PostPipeline restarts a pipeline optional with altered event, deploy or environment
func PostBuild(c *gin.Context) { func PostPipeline(c *gin.Context) {
_store := store.FromContext(c) _store := store.FromContext(c)
repo := session.Repo(c) repo := session.Repo(c)
@ -340,9 +341,9 @@ func PostBuild(c *gin.Context) {
return return
} }
build, err := _store.GetBuildNumber(repo, num) pl, err := _store.GetPipelineNumber(repo, num)
if err != nil { if err != nil {
log.Error().Msgf("failure to get build %d. %s", num, err) log.Error().Msgf("failure to get pipeline %d. %s", num, err)
_ = c.AbortWithError(404, err) _ = c.AbortWithError(404, err)
return return
} }
@ -351,20 +352,20 @@ func PostBuild(c *gin.Context) {
refreshUserToken(c, user) refreshUserToken(c, user)
// make Deploy overridable // make Deploy overridable
build.Deploy = c.DefaultQuery("deploy_to", build.Deploy) pl.Deploy = c.DefaultQuery("deploy_to", pl.Deploy)
// make Event overridable // make Event overridable
if event, ok := c.GetQuery("event"); ok { if event, ok := c.GetQuery("event"); ok {
build.Event = model.WebhookEvent(event) pl.Event = model.WebhookEvent(event)
if !model.ValidateWebhookEvent(build.Event) { if !model.ValidateWebhookEvent(pl.Event) {
msg := fmt.Sprintf("build event '%s' is invalid", event) msg := fmt.Sprintf("pipeline event '%s' is invalid", event)
c.String(http.StatusBadRequest, msg) c.String(http.StatusBadRequest, msg)
return return
} }
} }
// Read query string parameters into buildParams, exclude reserved params // Read query string parameters into pipelineParams, exclude reserved params
envs := map[string]string{} envs := map[string]string{}
for key, val := range c.Request.URL.Query() { for key, val := range c.Request.URL.Query() {
switch key { switch key {
@ -372,43 +373,43 @@ func PostBuild(c *gin.Context) {
case "fork", "event", "deploy_to": case "fork", "event", "deploy_to":
continue continue
default: default:
// We only accept string literals, because build parameters will be // We only accept string literals, because pipeline parameters will be
// injected as environment variables // injected as environment variables
// TODO: sanitize the value // TODO: sanitize the value
envs[key] = val[0] envs[key] = val[0]
} }
} }
newBuild, err := pipeline.Restart(c, _store, build, user, repo, envs) newpipeline, err := pipeline.Restart(c, _store, pl, user, repo, envs)
if err != nil { if err != nil {
handlePipelineErr(c, err) handlePipelineErr(c, err)
} else { } else {
c.JSON(200, newBuild) c.JSON(200, newpipeline)
} }
} }
func DeleteBuildLogs(c *gin.Context) { func DeletePipelineLogs(c *gin.Context) {
_store := store.FromContext(c) _store := store.FromContext(c)
repo := session.Repo(c) repo := session.Repo(c)
user := session.User(c) user := session.User(c)
num, _ := strconv.ParseInt(c.Params.ByName("number"), 10, 64) num, _ := strconv.ParseInt(c.Params.ByName("number"), 10, 64)
build, err := _store.GetBuildNumber(repo, num) pl, err := _store.GetPipelineNumber(repo, num)
if err != nil { if err != nil {
_ = c.AbortWithError(404, err) _ = c.AbortWithError(404, err)
return return
} }
procs, err := _store.ProcList(build) procs, err := _store.ProcList(pl)
if err != nil { if err != nil {
_ = c.AbortWithError(404, err) _ = c.AbortWithError(404, err)
return return
} }
switch build.Status { switch pl.Status {
case model.StatusRunning, model.StatusPending: case model.StatusRunning, model.StatusPending:
c.String(400, "Cannot delete logs for a pending or running build") c.String(400, "Cannot delete logs for a pending or running pipeline")
return return
} }

View file

@ -1,3 +1,4 @@
// Copyright 2022 Woodpecker Authors
// Copyright 2018 Drone.IO Inc. // Copyright 2018 Drone.IO Inc.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
@ -33,7 +34,7 @@ import (
// TODO: make it set system wide via environment variables // TODO: make it set system wide via environment variables
const ( const (
defaultTimeout int64 = 60 // 1 hour default build time defaultTimeout int64 = 60 // 1 hour default pipeline time
maxTimeout int64 = defaultTimeout * 2 maxTimeout int64 = defaultTimeout * 2
) )

View file

@ -1,3 +1,4 @@
// Copyright 2022 Woodpecker Authors
// Copyright 2018 Drone.IO Inc. // Copyright 2018 Drone.IO Inc.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
@ -140,18 +141,18 @@ func LogStreamSSE(c *gin.Context) {
repo := session.Repo(c) repo := session.Repo(c)
_store := store.FromContext(c) _store := store.FromContext(c)
// // parse the build number and job sequence number from // // parse the pipeline number and job sequence number from
// // the repquest parameter. // // the repquest parameter.
buildn, _ := strconv.ParseInt(c.Param("build"), 10, 64) pipelinen, _ := strconv.ParseInt(c.Param("pipeline"), 10, 64)
jobn, _ := strconv.Atoi(c.Param("number")) jobn, _ := strconv.Atoi(c.Param("number"))
build, err := _store.GetBuildNumber(repo, buildn) pipeline, err := _store.GetPipelineNumber(repo, pipelinen)
if err != nil { if err != nil {
log.Debug().Msgf("stream cannot get build number: %v", err) log.Debug().Msgf("stream cannot get pipeline number: %v", err)
logWriteStringErr(io.WriteString(rw, "event: error\ndata: build not found\n\n")) logWriteStringErr(io.WriteString(rw, "event: error\ndata: pipeline not found\n\n"))
return return
} }
proc, err := _store.ProcFind(build, jobn) proc, err := _store.ProcFind(pipeline, jobn)
if err != nil { if err != nil {
log.Debug().Msgf("stream cannot get proc number: %v", err) log.Debug().Msgf("stream cannot get proc number: %v", err)
logWriteStringErr(io.WriteString(rw, "event: error\ndata: process not found\n\n")) logWriteStringErr(io.WriteString(rw, "event: error\ndata: process not found\n\n"))

View file

@ -25,7 +25,7 @@ var (
) )
// Generate an SVG badge based on a pipeline // Generate an SVG badge based on a pipeline
func Generate(pipeline *model.Build) string { func Generate(pipeline *model.Pipeline) string {
if pipeline == nil { if pipeline == nil {
return badgeNone return badgeNone
} }

View file

@ -23,7 +23,7 @@ import (
"github.com/woodpecker-ci/woodpecker/server/model" "github.com/woodpecker-ci/woodpecker/server/model"
) )
// CCMenu displays the build status of projects on a ci server as an item in the Mac's menu bar. // CCMenu displays the pipeline status of projects on a ci server as an item in the Mac's menu bar.
// It started as part of the CruiseControl project that built the first continuous integration server. // It started as part of the CruiseControl project that built the first continuous integration server.
// //
// http://ccmenu.org/ // http://ccmenu.org/
@ -43,7 +43,7 @@ type CCProject struct {
WebURL string `xml:"webUrl,attr"` WebURL string `xml:"webUrl,attr"`
} }
func New(r *model.Repo, b *model.Build, link string) *CCProjects { func New(r *model.Repo, b *model.Pipeline, link string) *CCProjects {
proj := &CCProject{ proj := &CCProject{
Name: r.FullName, Name: r.FullName,
WebURL: link, WebURL: link,
@ -52,8 +52,8 @@ func New(r *model.Repo, b *model.Build, link string) *CCProjects {
LastBuildLabel: "Unknown", LastBuildLabel: "Unknown",
} }
// if the build is not currently running then // if the pipeline is not currently running then
// we can return the latest build status. // we can return the latest pipeline status.
if b.Status != model.StatusPending && if b.Status != model.StatusPending &&
b.Status != model.StatusRunning { b.Status != model.StatusRunning {
proj.Activity = "Sleeping" proj.Activity = "Sleeping"
@ -61,7 +61,7 @@ func New(r *model.Repo, b *model.Build, link string) *CCProjects {
proj.LastBuildLabel = strconv.FormatInt(b.Number, 10) proj.LastBuildLabel = strconv.FormatInt(b.Number, 10)
} }
// ensure the last build Status accepts a valid // ensure the last pipeline status accepts a valid
// ccmenu enumeration // ccmenu enumeration
switch b.Status { switch b.Status {
case model.StatusError, model.StatusKilled: case model.StatusError, model.StatusKilled:

View file

@ -1,3 +1,4 @@
// Copyright 2022 Woodpecker Authors
// Copyright 2018 Drone.IO Inc. // Copyright 2018 Drone.IO Inc.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
@ -32,7 +33,7 @@ func TestCC(t *testing.T) {
r := &model.Repo{ r := &model.Repo{
FullName: "foo/bar", FullName: "foo/bar",
} }
b := &model.Build{ b := &model.Pipeline{
Status: model.StatusSuccess, Status: model.StatusSuccess,
Number: 1, Number: 1,
Started: now, Started: now,
@ -49,7 +50,7 @@ func TestCC(t *testing.T) {
g.It("Should properly label exceptions", func() { g.It("Should properly label exceptions", func() {
r := &model.Repo{FullName: "foo/bar"} r := &model.Repo{FullName: "foo/bar"}
b := &model.Build{ b := &model.Pipeline{
Status: model.StatusError, Status: model.StatusError,
Number: 1, Number: 1,
Started: 1257894000, Started: 1257894000,
@ -61,7 +62,7 @@ func TestCC(t *testing.T) {
g.It("Should properly label success", func() { g.It("Should properly label success", func() {
r := &model.Repo{FullName: "foo/bar"} r := &model.Repo{FullName: "foo/bar"}
b := &model.Build{ b := &model.Pipeline{
Status: model.StatusSuccess, Status: model.StatusSuccess,
Number: 1, Number: 1,
Started: 1257894000, Started: 1257894000,
@ -73,7 +74,7 @@ func TestCC(t *testing.T) {
g.It("Should properly label failure", func() { g.It("Should properly label failure", func() {
r := &model.Repo{FullName: "foo/bar"} r := &model.Repo{FullName: "foo/bar"}
b := &model.Build{ b := &model.Pipeline{
Status: model.StatusFailure, Status: model.StatusFailure,
Number: 1, Number: 1,
Started: 1257894000, Started: 1257894000,
@ -85,7 +86,7 @@ func TestCC(t *testing.T) {
g.It("Should properly label running", func() { g.It("Should properly label running", func() {
r := &model.Repo{FullName: "foo/bar"} r := &model.Repo{FullName: "foo/bar"}
b := &model.Build{ b := &model.Pipeline{
Status: model.StatusRunning, Status: model.StatusRunning,
Number: 1, Number: 1,
Started: 1257894000, Started: 1257894000,

View file

@ -105,7 +105,7 @@ func runCron(store store.Store, remote remote.Remote, cron *model.Cron, now time
return err return err
} }
func createBuild(ctx context.Context, store store.Store, remote remote.Remote, cron *model.Cron) (*model.Repo, *model.Build, error) { func createBuild(ctx context.Context, store store.Store, remote remote.Remote, cron *model.Cron) (*model.Repo, *model.Pipeline, error) {
repo, err := store.GetRepo(cron.RepoID) repo, err := store.GetRepo(cron.RepoID)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
@ -126,7 +126,7 @@ func createBuild(ctx context.Context, store store.Store, remote remote.Remote, c
return nil, nil, err return nil, nil, err
} }
return repo, &model.Build{ return repo, &model.Pipeline{
Event: model.EventCron, Event: model.EventCron,
Commit: commit, Commit: commit,
Ref: "refs/heads/" + cron.Branch, Ref: "refs/heads/" + cron.Branch,

View file

@ -49,18 +49,18 @@ func TestCreateBuild(t *testing.T) {
store.On("GetUser", mock.Anything).Return(creator, nil) store.On("GetUser", mock.Anything).Return(creator, nil)
remote.On("BranchHead", mock.Anything, creator, repo1, "default").Return("sha1", nil) remote.On("BranchHead", mock.Anything, creator, repo1, "default").Return("sha1", nil)
_, build, err := createBuild(ctx, store, remote, &model.Cron{ _, pipeline, err := createBuild(ctx, store, remote, &model.Cron{
Name: "test", Name: "test",
}) })
assert.NoError(t, err) assert.NoError(t, err)
assert.EqualValues(t, &model.Build{ assert.EqualValues(t, &model.Pipeline{
Event: "cron", Event: "cron",
Commit: "sha1", Commit: "sha1",
Branch: "default", Branch: "default",
Ref: "refs/heads/default", Ref: "refs/heads/default",
Message: "test", Message: "test",
Sender: "test", Sender: "test",
}, build) }, pipeline)
} }
func TestCalcNewNext(t *testing.T) { func TestCalcNewNext(t *testing.T) {

View file

@ -1,5 +1,6 @@
// Copyright 2018 Drone.IO Inc. // Copyright 2022 Woodpecker Authors
// Copyright 2021 Informatyka Boguslawski sp. z o.o. sp.k., http://www.ib.pl/ // Copyright 2021 Informatyka Boguslawski sp. z o.o. sp.k., http://www.ib.pl/
// Copyright 2018 Drone.IO Inc.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@ -47,8 +48,8 @@ type RPC struct {
logger logging.Log logger logging.Log
store store.Store store store.Store
host string host string
buildTime *prometheus.GaugeVec pipelineTime *prometheus.GaugeVec
buildCount *prometheus.CounterVec pipelineCount *prometheus.CounterVec
} }
// Next implements the rpc.Next function // Next implements the rpc.Next function
@ -107,13 +108,13 @@ func (s *RPC) Update(c context.Context, id string, state rpc.State) error {
return err return err
} }
build, err := s.store.GetBuild(pproc.BuildID) pipeline, err := s.store.GetPipeline(pproc.PipelineID)
if err != nil { if err != nil {
log.Error().Msgf("error: cannot find build with id %d: %s", pproc.BuildID, err) log.Error().Msgf("error: cannot find pipeline with id %d: %s", pproc.PipelineID, err)
return err return err
} }
proc, err := s.store.ProcChild(build, pproc.PID, state.Proc) proc, err := s.store.ProcChild(pipeline, pproc.PID, state.Proc)
if err != nil { if err != nil {
log.Error().Msgf("error: cannot find proc with name %s: %s", state.Proc, err) log.Error().Msgf("error: cannot find proc with name %s: %s", state.Proc, err)
return err return err
@ -127,20 +128,20 @@ func (s *RPC) Update(c context.Context, id string, state rpc.State) error {
} }
} }
repo, err := s.store.GetRepo(build.RepoID) repo, err := s.store.GetRepo(pipeline.RepoID)
if err != nil { if err != nil {
log.Error().Msgf("error: cannot find repo with id %d: %s", build.RepoID, err) log.Error().Msgf("error: cannot find repo with id %d: %s", pipeline.RepoID, err)
return err return err
} }
if _, err = shared.UpdateProcStatus(s.store, *proc, state, build.Started); err != nil { if _, err = shared.UpdateProcStatus(s.store, *proc, state, pipeline.Started); err != nil {
log.Error().Err(err).Msg("rpc.update: cannot update proc") log.Error().Err(err).Msg("rpc.update: cannot update proc")
} }
if build.Procs, err = s.store.ProcList(build); err != nil { if pipeline.Procs, err = s.store.ProcList(pipeline); err != nil {
log.Error().Err(err).Msg("can not get proc list from store") log.Error().Err(err).Msg("can not get proc list from store")
} }
if build.Procs, err = model.Tree(build.Procs); err != nil { if pipeline.Procs, err = model.Tree(pipeline.Procs); err != nil {
log.Error().Err(err).Msg("can not build tree from proc list") log.Error().Err(err).Msg("can not build tree from proc list")
return err return err
} }
@ -152,7 +153,7 @@ func (s *RPC) Update(c context.Context, id string, state rpc.State) error {
} }
message.Data, _ = json.Marshal(model.Event{ message.Data, _ = json.Marshal(model.Event{
Repo: *repo, Repo: *repo,
Build: *build, Pipeline: *pipeline,
}) })
if err := s.pubsub.Publish(c, "topic/events", message); err != nil { 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 proc list to")
@ -174,13 +175,13 @@ func (s *RPC) Upload(c context.Context, id string, file *rpc.File) error {
return err return err
} }
build, err := s.store.GetBuild(pproc.BuildID) pipeline, err := s.store.GetPipeline(pproc.PipelineID)
if err != nil { if err != nil {
log.Error().Msgf("error: cannot find build with id %d: %s", pproc.BuildID, err) log.Error().Msgf("error: cannot find pipeline with id %d: %s", pproc.PipelineID, err)
return err return err
} }
proc, err := s.store.ProcChild(build, pproc.PID, file.Proc) proc, err := s.store.ProcChild(pipeline, pproc.PID, file.Proc)
if err != nil { 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 proc with name %s: %s", file.Proc, err)
return err return err
@ -194,7 +195,7 @@ func (s *RPC) Upload(c context.Context, id string, file *rpc.File) error {
} }
report := &model.File{ report := &model.File{
BuildID: proc.BuildID, PipelineID: proc.PipelineID,
ProcID: proc.ID, ProcID: proc.ID,
PID: proc.PID, PID: proc.PID,
Mime: file.Mime, Mime: file.Mime,
@ -254,26 +255,26 @@ func (s *RPC) Init(c context.Context, id string, state rpc.State) error {
} }
} }
build, err := s.store.GetBuild(proc.BuildID) pipeline, err := s.store.GetPipeline(proc.PipelineID)
if err != nil { if err != nil {
log.Error().Msgf("error: cannot find build with id %d: %s", proc.BuildID, err) log.Error().Msgf("error: cannot find pipeline with id %d: %s", proc.PipelineID, err)
return err return err
} }
repo, err := s.store.GetRepo(build.RepoID) repo, err := s.store.GetRepo(pipeline.RepoID)
if err != nil { if err != nil {
log.Error().Msgf("error: cannot find repo with id %d: %s", build.RepoID, err) log.Error().Msgf("error: cannot find repo with id %d: %s", pipeline.RepoID, err)
return err return err
} }
if build.Status == model.StatusPending { if pipeline.Status == model.StatusPending {
if build, err = shared.UpdateToStatusRunning(s.store, *build, state.Started); err != nil { if pipeline, err = shared.UpdateToStatusRunning(s.store, *pipeline, state.Started); err != nil {
log.Error().Msgf("error: init: cannot update build_id %d state: %s", build.ID, err) log.Error().Msgf("error: init: cannot update build_id %d state: %s", pipeline.ID, err)
} }
} }
defer func() { defer func() {
build.Procs, _ = s.store.ProcList(build) pipeline.Procs, _ = s.store.ProcList(pipeline)
message := pubsub.Message{ message := pubsub.Message{
Labels: map[string]string{ Labels: map[string]string{
"repo": repo.FullName, "repo": repo.FullName,
@ -282,7 +283,7 @@ func (s *RPC) Init(c context.Context, id string, state rpc.State) error {
} }
message.Data, _ = json.Marshal(model.Event{ message.Data, _ = json.Marshal(model.Event{
Repo: *repo, Repo: *repo,
Build: *build, Pipeline: *pipeline,
}) })
if err := s.pubsub.Publish(c, "topic/events", message); err != nil { 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 proc list to")
@ -306,21 +307,21 @@ func (s *RPC) Done(c context.Context, id string, state rpc.State) error {
return err return err
} }
build, err := s.store.GetBuild(proc.BuildID) pipeline, err := s.store.GetPipeline(proc.PipelineID)
if err != nil { if err != nil {
log.Error().Msgf("error: cannot find build with id %d: %s", proc.BuildID, err) log.Error().Msgf("error: cannot find pipeline with id %d: %s", proc.PipelineID, err)
return err return err
} }
repo, err := s.store.GetRepo(build.RepoID) repo, err := s.store.GetRepo(pipeline.RepoID)
if err != nil { if err != nil {
log.Error().Msgf("error: cannot find repo with id %d: %s", build.RepoID, err) log.Error().Msgf("error: cannot find repo with id %d: %s", pipeline.RepoID, err)
return err return err
} }
log.Trace(). log.Trace().
Str("repo_id", fmt.Sprint(repo.ID)). Str("repo_id", fmt.Sprint(repo.ID)).
Str("build_id", fmt.Sprint(build.ID)). Str("build_id", fmt.Sprint(pipeline.ID)).
Str("proc_id", id). Str("proc_id", id).
Msgf("gRPC Done with state: %#v", state) Msgf("gRPC Done with state: %#v", state)
@ -338,34 +339,34 @@ func (s *RPC) Done(c context.Context, id string, state rpc.State) error {
log.Error().Msgf("error: done: cannot ack proc_id %d: %s", procID, err) log.Error().Msgf("error: done: cannot ack proc_id %d: %s", procID, err)
} }
procs, err := s.store.ProcList(build) procs, err := s.store.ProcList(pipeline)
if err != nil { if err != nil {
return err return err
} }
s.completeChildrenIfParentCompleted(procs, proc) s.completeChildrenIfParentCompleted(procs, proc)
if !model.IsThereRunningStage(procs) { if !model.IsThereRunningStage(procs) {
if build, err = shared.UpdateStatusToDone(s.store, *build, model.BuildStatus(procs), proc.Stopped); err != nil { if pipeline, err = shared.UpdateStatusToDone(s.store, *pipeline, model.PipelineStatus(procs), proc.Stopped); err != nil {
log.Error().Err(err).Msgf("error: done: cannot update build_id %d final state", build.ID) log.Error().Err(err).Msgf("error: done: cannot update build_id %d final state", pipeline.ID)
} }
} }
s.updateRemoteStatus(c, repo, build, proc) s.updateRemoteStatus(c, repo, pipeline, proc)
if err := s.logger.Close(c, id); err != nil { 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", proc.ID)
} }
if err := s.notify(c, repo, build, procs); err != nil { if err := s.notify(c, repo, pipeline, procs); err != nil {
return err return err
} }
if build.Status == model.StatusSuccess || build.Status == model.StatusFailure { if pipeline.Status == model.StatusSuccess || pipeline.Status == model.StatusFailure {
s.buildCount.WithLabelValues(repo.FullName, build.Branch, string(build.Status), "total").Inc() s.pipelineCount.WithLabelValues(repo.FullName, pipeline.Branch, string(pipeline.Status), "total").Inc()
s.buildTime.WithLabelValues(repo.FullName, build.Branch, string(build.Status), "total").Set(float64(build.Finished - build.Started)) s.pipelineTime.WithLabelValues(repo.FullName, pipeline.Branch, string(pipeline.Status), "total").Set(float64(pipeline.Finished - pipeline.Started))
} }
if model.IsMultiPipeline(procs) { if model.IsMultiPipeline(procs) {
s.buildTime.WithLabelValues(repo.FullName, build.Branch, string(proc.State), proc.Name).Set(float64(proc.Stopped - proc.Started)) s.pipelineTime.WithLabelValues(repo.FullName, pipeline.Branch, string(proc.State), proc.Name).Set(float64(proc.Stopped - proc.Started))
} }
return nil return nil
@ -391,7 +392,7 @@ func (s *RPC) completeChildrenIfParentCompleted(procs []*model.Proc, completedPr
} }
} }
func (s *RPC) updateRemoteStatus(ctx context.Context, repo *model.Repo, build *model.Build, proc *model.Proc) { func (s *RPC) updateRemoteStatus(ctx context.Context, repo *model.Repo, pipeline *model.Pipeline, proc *model.Proc) {
user, err := s.store.GetUser(repo.UserID) user, err := s.store.GetUser(repo.UserID)
if err != nil { if err != nil {
log.Error().Err(err).Msgf("can not get user with id '%d'", repo.UserID) log.Error().Err(err).Msgf("can not get user with id '%d'", repo.UserID)
@ -411,15 +412,15 @@ func (s *RPC) updateRemoteStatus(ctx context.Context, repo *model.Repo, build *m
// only do status updates for parent procs // only do status updates for parent procs
if proc != nil && proc.IsParent() { if proc != nil && proc.IsParent() {
err = s.remote.Status(ctx, user, repo, build, proc) err = s.remote.Status(ctx, user, repo, pipeline, proc)
if err != nil { if err != nil {
log.Error().Err(err).Msgf("error setting commit status for %s/%d", repo.FullName, build.Number) 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, build *model.Build, procs []*model.Proc) (err error) { func (s *RPC) notify(c context.Context, repo *model.Repo, pipeline *model.Pipeline, procs []*model.Proc) (err error) {
if build.Procs, err = model.Tree(procs); err != nil { if pipeline.Procs, err = model.Tree(procs); err != nil {
return err return err
} }
message := pubsub.Message{ message := pubsub.Message{
@ -430,7 +431,7 @@ func (s *RPC) notify(c context.Context, repo *model.Repo, build *model.Build, pr
} }
message.Data, _ = json.Marshal(model.Event{ message.Data, _ = json.Marshal(model.Event{
Repo: *repo, Repo: *repo,
Build: *build, Pipeline: *pipeline,
}) })
if err := s.pubsub.Publish(c, "topic/events", message); err != nil { if err := s.pubsub.Publish(c, "topic/events", message); err != nil {
log.Error().Err(err).Msgf("grpc could not notify event: '%v'", message) log.Error().Err(err).Msgf("grpc could not notify event: '%v'", message)

View file

@ -37,15 +37,15 @@ type WoodpeckerServer struct {
} }
func NewWoodpeckerServer(remote remote.Remote, queue queue.Queue, logger logging.Log, pubsub pubsub.Publisher, store store.Store, host string) *WoodpeckerServer { func NewWoodpeckerServer(remote remote.Remote, queue queue.Queue, logger logging.Log, pubsub pubsub.Publisher, store store.Store, host string) *WoodpeckerServer {
buildTime := promauto.NewGaugeVec(prometheus.GaugeOpts{ pipelineTime := promauto.NewGaugeVec(prometheus.GaugeOpts{
Namespace: "woodpecker", Namespace: "woodpecker",
Name: "build_time", Name: "pipeline_time",
Help: "Build time.", Help: "Pipeline time.",
}, []string{"repo", "branch", "status", "pipeline"}) }, []string{"repo", "branch", "status", "pipeline"})
buildCount := promauto.NewCounterVec(prometheus.CounterOpts{ pipelineCount := promauto.NewCounterVec(prometheus.CounterOpts{
Namespace: "woodpecker", Namespace: "woodpecker",
Name: "build_count", Name: "pipeline_count",
Help: "Build count.", Help: "Pipeline count.",
}, []string{"repo", "branch", "status", "pipeline"}) }, []string{"repo", "branch", "status", "pipeline"})
peer := RPC{ peer := RPC{
remote: remote, remote: remote,
@ -54,8 +54,8 @@ func NewWoodpeckerServer(remote remote.Remote, queue queue.Queue, logger logging
pubsub: pubsub, pubsub: pubsub,
logger: logger, logger: logger,
host: host, host: host,
buildTime: buildTime, pipelineTime: pipelineTime,
buildCount: buildCount, pipelineCount: pipelineCount,
} }
return &WoodpeckerServer{peer: peer} return &WoodpeckerServer{peer: peer}
} }

View file

@ -17,11 +17,11 @@ package model
// ConfigStore persists pipeline configuration to storage. // ConfigStore persists pipeline configuration to storage.
type ConfigStore interface { type ConfigStore interface {
ConfigsForBuild(buildID int64) ([]*Config, error) ConfigsForPipeline(pipelineID int64) ([]*Config, error)
ConfigFindIdentical(repoID int64, hash string) (*Config, error) ConfigFindIdentical(repoID int64, hash string) (*Config, error)
ConfigFindApproved(*Config) (bool, error) ConfigFindApproved(*Config) (bool, error)
ConfigCreate(*Config) error ConfigCreate(*Config) error
BuildConfigCreate(*BuildConfig) error PipelineConfigCreate(*PipelineConfig) error
} }
// Config represents a pipeline configuration. // Config represents a pipeline configuration.
@ -33,8 +33,8 @@ type Config struct {
Data []byte `json:"data" xorm:"config_data"` Data []byte `json:"data" xorm:"config_data"`
} }
// BuildConfig is the n:n relation between Build and Config // PipelineConfig is the n:n relation between Pipeline and Config
type BuildConfig struct { type PipelineConfig struct {
ConfigID int64 `json:"-" xorm:"UNIQUE(s) NOT NULL 'config_id'"` ConfigID int64 `json:"-" xorm:"UNIQUE(s) NOT NULL 'config_id'"`
BuildID int64 `json:"-" xorm:"UNIQUE(s) NOT NULL 'build_id'"` PipelineID int64 `json:"-" xorm:"UNIQUE(s) NOT NULL 'build_id'"`
} }

View file

@ -1,3 +1,4 @@
// Copyright 2022 Woodpecker Authors
// Copyright 2018 Drone.IO Inc. // Copyright 2018 Drone.IO Inc.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");

View file

@ -1,3 +1,4 @@
// Copyright 2022 Woodpecker Authors
// Copyright 2018 Drone.IO Inc. // Copyright 2018 Drone.IO Inc.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
@ -14,11 +15,11 @@
package model package model
// EventType defines the possible types of build events. // EventType defines the possible types of pipeline events.
type EventType string type EventType string
// Event represents a build event. // Event represents a pipeline event.
type Event struct { type Event struct {
Repo Repo `json:"repo"` Repo Repo `json:"repo"`
Build Build `json:"build"` Pipeline Pipeline `json:"build"`
} }

View file

@ -19,7 +19,7 @@ import "io"
// FileStore persists pipeline artifacts to storage. // FileStore persists pipeline artifacts to storage.
type FileStore interface { type FileStore interface {
FileList(*Build) ([]*File, error) FileList(*Pipeline) ([]*File, error)
FileFind(*Proc, string) (*File, error) FileFind(*Proc, string) (*File, error)
FileRead(*Proc, string) (io.ReadCloser, error) FileRead(*Proc, string) (io.ReadCloser, error)
FileCreate(*File, io.Reader) error FileCreate(*File, io.Reader) error
@ -28,7 +28,7 @@ type FileStore interface {
// File represents a pipeline artifact. // File represents a pipeline artifact.
type File struct { type File struct {
ID int64 `json:"id" xorm:"pk autoincr 'file_id'"` ID int64 `json:"id" xorm:"pk autoincr 'file_id'"`
BuildID int64 `json:"-" xorm:"INDEX 'file_build_id'"` PipelineID int64 `json:"-" xorm:"INDEX 'file_build_id'"`
ProcID int64 `json:"proc_id" xorm:"UNIQUE(s) INDEX 'file_proc_id'"` ProcID int64 `json:"proc_id" xorm:"UNIQUE(s) INDEX 'file_proc_id'"`
PID int `json:"pid" xorm:"file_pid"` PID int `json:"pid" xorm:"file_pid"`
Name string `json:"name" xorm:"UNIQUE(s) file_name"` Name string `json:"name" xorm:"UNIQUE(s) file_name"`
@ -38,7 +38,7 @@ type File struct {
Passed int `json:"passed" xorm:"file_meta_passed"` Passed int `json:"passed" xorm:"file_meta_passed"`
Failed int `json:"failed" xorm:"file_meta_failed"` Failed int `json:"failed" xorm:"file_meta_failed"`
Skipped int `json:"skipped" xorm:"file_meta_skipped"` Skipped int `json:"skipped" xorm:"file_meta_skipped"`
Data []byte `json:"-" xorm:"file_data"` // TODO: dont store in db but object storage? Data []byte `json:"-" xorm:"file_data"` // TODO: don't store in db but object storage?
} }
// TableName return database table name for xorm // TableName return database table name for xorm

View file

@ -15,8 +15,8 @@
package model package model
// swagger:model build // swagger:model pipeline
type Build struct { type Pipeline struct {
ID int64 `json:"id" xorm:"pk autoincr 'build_id'"` ID int64 `json:"id" xorm:"pk autoincr 'build_id'"`
RepoID int64 `json:"-" xorm:"UNIQUE(s) INDEX 'build_repo_id'"` RepoID int64 `json:"-" xorm:"UNIQUE(s) INDEX 'build_repo_id'"`
Number int64 `json:"number" xorm:"UNIQUE(s) 'build_number'"` Number int64 `json:"number" xorm:"UNIQUE(s) 'build_number'"`
@ -55,15 +55,15 @@ type Build struct {
} }
// TableName return database table name for xorm // TableName return database table name for xorm
func (Build) TableName() string { func (Pipeline) TableName() string {
return "builds" return "pipelines"
} }
type UpdateBuildStore interface { type UpdatePipelineStore interface {
UpdateBuild(*Build) error UpdatePipeline(*Pipeline) error
} }
type BuildOptions struct { type PipelineOptions struct {
Branch string `json:"branch"` Branch string `json:"branch"`
Variables map[string]string `json:"variables"` Variables map[string]string `json:"variables"`
} }

View file

@ -20,19 +20,19 @@ import "fmt"
// ProcStore persists process information to storage. // ProcStore persists process information to storage.
type ProcStore interface { type ProcStore interface {
ProcLoad(int64) (*Proc, error) ProcLoad(int64) (*Proc, error)
ProcFind(*Build, int) (*Proc, error) ProcFind(*Pipeline, int) (*Proc, error)
ProcChild(*Build, int, string) (*Proc, error) ProcChild(*Pipeline, int, string) (*Proc, error)
ProcList(*Build) ([]*Proc, error) ProcList(*Pipeline) ([]*Proc, error)
ProcCreate([]*Proc) error ProcCreate([]*Proc) error
ProcUpdate(*Proc) error ProcUpdate(*Proc) error
ProcClear(*Build) error ProcClear(*Pipeline) error
} }
// Proc represents a process in the build pipeline. // Proc represents a process in the pipeline.
// swagger:model proc // swagger:model proc
type Proc struct { type Proc struct {
ID int64 `json:"id" xorm:"pk autoincr 'proc_id'"` ID int64 `json:"id" xorm:"pk autoincr 'proc_id'"`
BuildID int64 `json:"build_id" xorm:"UNIQUE(s) INDEX 'proc_build_id'"` PipelineID int64 `json:"build_id" xorm:"UNIQUE(s) INDEX 'proc_build_id'"`
PID int `json:"pid" xorm:"UNIQUE(s) 'proc_pid'"` PID int `json:"pid" xorm:"UNIQUE(s) 'proc_pid'"`
PPID int `json:"ppid" xorm:"proc_ppid"` PPID int `json:"ppid" xorm:"proc_ppid"`
PGID int `json:"pgid" xorm:"proc_pgid"` PGID int `json:"pgid" xorm:"proc_pgid"`
@ -111,8 +111,8 @@ func Tree(procs []*Proc) ([]*Proc, error) {
return nodes, nil return nodes, nil
} }
// BuildStatus determine build status based on corresponding proc list // PipelineStatus determine pipeline status based on corresponding proc list
func BuildStatus(procs []*Proc) StatusValue { func PipelineStatus(procs []*Proc) StatusValue {
status := StatusSuccess status := StatusSuccess
for _, p := range procs { for _, p := range procs {

View file

@ -24,7 +24,7 @@ func TestTree(t *testing.T) {
procs := []*Proc{{ procs := []*Proc{{
ID: 25, ID: 25,
PID: 2, PID: 2,
BuildID: 6, PipelineID: 6,
PPID: 1, PPID: 1,
PGID: 2, PGID: 2,
Name: "clone", Name: "clone",
@ -32,7 +32,7 @@ func TestTree(t *testing.T) {
Error: "0", Error: "0",
}, { }, {
ID: 24, ID: 24,
BuildID: 6, PipelineID: 6,
PID: 1, PID: 1,
PPID: 0, PPID: 0,
PGID: 1, PGID: 1,
@ -41,7 +41,7 @@ func TestTree(t *testing.T) {
Error: "1", Error: "1",
}, { }, {
ID: 26, ID: 26,
BuildID: 6, PipelineID: 6,
PID: 3, PID: 3,
PPID: 1, PPID: 1,
PGID: 3, PGID: 3,
@ -57,7 +57,7 @@ func TestTree(t *testing.T) {
procs = []*Proc{{ procs = []*Proc{{
ID: 25, ID: 25,
PID: 2, PID: 2,
BuildID: 6, PipelineID: 6,
PPID: 1, PPID: 1,
PGID: 2, PGID: 2,
Name: "clone", Name: "clone",

View file

@ -1,3 +1,17 @@
// 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 model package model
type Redirection struct { type Redirection struct {

View file

@ -31,7 +31,7 @@ var (
// SecretService defines a service for managing secrets. // SecretService defines a service for managing secrets.
type SecretService interface { type SecretService interface {
SecretListBuild(*Repo, *Build) ([]*Secret, error) SecretListPipeline(*Repo, *Pipeline) ([]*Secret, error)
// Repository secrets // Repository secrets
SecretFind(*Repo, string) (*Secret, error) SecretFind(*Repo, string) (*Secret, error)
SecretList(*Repo) ([]*Secret, error) SecretList(*Repo) ([]*Secret, error)

View file

@ -26,23 +26,23 @@ import (
"github.com/woodpecker-ci/woodpecker/server/store" "github.com/woodpecker-ci/woodpecker/server/store"
) )
// Approve update the status to pending for blocked build because of a gated repo // Approve update the status to pending for blocked pipeline because of a gated repo
// and start them afterwards // and start them afterwards
func Approve(ctx context.Context, store store.Store, build *model.Build, user *model.User, repo *model.Repo) (*model.Build, error) { func Approve(ctx context.Context, store store.Store, pipeline *model.Pipeline, user *model.User, repo *model.Repo) (*model.Pipeline, error) {
if build.Status != model.StatusBlocked { if pipeline.Status != model.StatusBlocked {
return nil, ErrBadRequest{Msg: fmt.Sprintf("cannot decline a build with status %s", build.Status)} return nil, ErrBadRequest{Msg: fmt.Sprintf("cannot decline a pipeline with status %s", pipeline.Status)}
} }
// fetch the build file from the database // fetch the pipeline file from the database
configs, err := store.ConfigsForBuild(build.ID) configs, err := store.ConfigsForPipeline(pipeline.ID)
if err != nil { if err != nil {
msg := fmt.Sprintf("failure to get build config for %s. %s", repo.FullName, err) msg := fmt.Sprintf("failure to get pipeline config for %s. %s", repo.FullName, err)
log.Error().Msg(msg) log.Error().Msg(msg)
return nil, ErrNotFound{Msg: msg} return nil, ErrNotFound{Msg: msg}
} }
if build, err = shared.UpdateToStatusPending(store, *build, user.Login); err != nil { if pipeline, err = shared.UpdateToStatusPending(store, *pipeline, user.Login); err != nil {
return nil, fmt.Errorf("error updating build. %s", err) return nil, fmt.Errorf("error updating pipeline. %s", err)
} }
var yamls []*remote.FileMeta var yamls []*remote.FileMeta
@ -50,19 +50,19 @@ func Approve(ctx context.Context, store store.Store, build *model.Build, user *m
yamls = append(yamls, &remote.FileMeta{Data: y.Data, Name: y.Name}) yamls = append(yamls, &remote.FileMeta{Data: y.Data, Name: y.Name})
} }
build, buildItems, err := createBuildItems(ctx, store, build, user, repo, yamls, nil) pipeline, pipelineItems, err := createPipelineItems(ctx, store, pipeline, user, repo, yamls, nil)
if err != nil { if err != nil {
msg := fmt.Sprintf("failure to createBuildItems for %s", repo.FullName) msg := fmt.Sprintf("failure to createBuildItems for %s", repo.FullName)
log.Error().Err(err).Msg(msg) log.Error().Err(err).Msg(msg)
return nil, err return nil, err
} }
build, err = start(ctx, store, build, user, repo, buildItems) pipeline, err = start(ctx, store, pipeline, user, repo, pipelineItems)
if err != nil { if err != nil {
msg := fmt.Sprintf("failure to start build for %s: %v", repo.FullName, err) msg := fmt.Sprintf("failure to start pipeline for %s: %v", repo.FullName, err)
log.Error().Err(err).Msg(msg) log.Error().Err(err).Msg(msg)
return nil, fmt.Errorf(msg) return nil, fmt.Errorf(msg)
} }
return build, nil return pipeline, nil
} }

View file

@ -27,13 +27,13 @@ import (
"github.com/woodpecker-ci/woodpecker/server/store" "github.com/woodpecker-ci/woodpecker/server/store"
) )
// Cancel the build and returns the status. // Cancel the pipeline and returns the status.
func Cancel(ctx context.Context, store store.Store, repo *model.Repo, build *model.Build) error { func Cancel(ctx context.Context, store store.Store, repo *model.Repo, pipeline *model.Pipeline) error {
if build.Status != model.StatusRunning && build.Status != model.StatusPending && build.Status != model.StatusBlocked { if pipeline.Status != model.StatusRunning && pipeline.Status != model.StatusPending && pipeline.Status != model.StatusBlocked {
return ErrBadRequest{Msg: "Cannot cancel a non-running or non-pending or non-blocked build"} return ErrBadRequest{Msg: "Cannot cancel a non-running or non-pending or non-blocked pipeline"}
} }
procs, err := store.ProcList(build) procs, err := store.ProcList(pipeline)
if err != nil { if err != nil {
return ErrNotFound{Msg: err.Error()} return ErrNotFound{Msg: err.Error()}
} }
@ -69,7 +69,7 @@ func Cancel(ctx context.Context, store store.Store, repo *model.Repo, build *mod
} }
} }
// Then update the DB status for pending builds // Then update the DB status for pending pipelines
// Running ones will be set when the agents stop on the cancel signal // Running ones will be set when the agents stop on the cancel signal
for _, proc := range procs { for _, proc := range procs {
if proc.State == model.StatusPending { if proc.State == model.StatusPending {
@ -85,9 +85,9 @@ func Cancel(ctx context.Context, store store.Store, repo *model.Repo, build *mod
} }
} }
killedBuild, err := shared.UpdateToStatusKilled(store, *build) killedBuild, err := shared.UpdateToStatusKilled(store, *pipeline)
if err != nil { if err != nil {
log.Error().Err(err).Msgf("UpdateToStatusKilled: %v", build) log.Error().Err(err).Msgf("UpdateToStatusKilled: %v", pipeline)
return err return err
} }
@ -108,13 +108,13 @@ func Cancel(ctx context.Context, store store.Store, repo *model.Repo, build *mod
func cancelPreviousPipelines( func cancelPreviousPipelines(
ctx context.Context, ctx context.Context,
_store store.Store, _store store.Store,
build *model.Build, pipeline *model.Pipeline,
repo *model.Repo, repo *model.Repo,
) error { ) error {
// check this event should cancel previous pipelines // check this event should cancel previous pipelines
eventIncluded := false eventIncluded := false
for _, ev := range repo.CancelPreviousPipelineEvents { for _, ev := range repo.CancelPreviousPipelineEvents {
if ev == build.Event { if ev == pipeline.Event {
eventIncluded = true eventIncluded = true
break break
} }
@ -124,38 +124,38 @@ func cancelPreviousPipelines(
} }
// get all active activeBuilds // get all active activeBuilds
activeBuilds, err := _store.GetActiveBuildList(repo, -1) activeBuilds, err := _store.GetActivePipelineList(repo, -1)
if err != nil { if err != nil {
return err return err
} }
buildNeedsCancel := func(active *model.Build) (bool, error) { pipelineNeedsCancel := func(active *model.Pipeline) (bool, error) {
// always filter on same event // always filter on same event
if active.Event != build.Event { if active.Event != pipeline.Event {
return false, nil return false, nil
} }
// find events for the same context // find events for the same context
switch build.Event { switch pipeline.Event {
case model.EventPush: case model.EventPush:
return build.Branch == active.Branch, nil return pipeline.Branch == active.Branch, nil
default: default:
return build.Refspec == active.Refspec, nil return pipeline.Refspec == active.Refspec, nil
} }
} }
for _, active := range activeBuilds { for _, active := range activeBuilds {
if active.ID == build.ID { if active.ID == pipeline.ID {
// same build. e.g. self // same pipeline. e.g. self
continue continue
} }
cancel, err := buildNeedsCancel(active) cancel, err := pipelineNeedsCancel(active)
if err != nil { if err != nil {
log.Error(). log.Error().
Err(err). Err(err).
Str("Ref", active.Ref). Str("Ref", active.Ref).
Msg("Error while trying to cancel build, skipping") Msg("Error while trying to cancel pipeline, skipping")
continue continue
} }
@ -168,7 +168,7 @@ func cancelPreviousPipelines(
Err(err). Err(err).
Str("Ref", active.Ref). Str("Ref", active.Ref).
Int64("ID", active.ID). Int64("ID", active.ID).
Msg("Failed to cancel build") Msg("Failed to cancel pipeline")
} }
} }

View file

@ -24,12 +24,12 @@ import (
"github.com/woodpecker-ci/woodpecker/server/store" "github.com/woodpecker-ci/woodpecker/server/store"
) )
func findOrPersistPipelineConfig(store store.Store, build *model.Build, remoteYamlConfig *remote.FileMeta) (*model.Config, error) { func findOrPersistPipelineConfig(store store.Store, pipeline *model.Pipeline, remoteYamlConfig *remote.FileMeta) (*model.Config, error) {
sha := fmt.Sprintf("%x", sha256.Sum256(remoteYamlConfig.Data)) sha := fmt.Sprintf("%x", sha256.Sum256(remoteYamlConfig.Data))
conf, err := store.ConfigFindIdentical(build.RepoID, sha) conf, err := store.ConfigFindIdentical(pipeline.RepoID, sha)
if err != nil { if err != nil {
conf = &model.Config{ conf = &model.Config{
RepoID: build.RepoID, RepoID: pipeline.RepoID,
Data: remoteYamlConfig.Data, Data: remoteYamlConfig.Data,
Hash: sha, Hash: sha,
Name: shared.SanitizePath(remoteYamlConfig.Name), Name: shared.SanitizePath(remoteYamlConfig.Name),
@ -37,18 +37,18 @@ func findOrPersistPipelineConfig(store store.Store, build *model.Build, remoteYa
err = store.ConfigCreate(conf) err = store.ConfigCreate(conf)
if err != nil { if err != nil {
// retry in case we receive two hooks at the same time // retry in case we receive two hooks at the same time
conf, err = store.ConfigFindIdentical(build.RepoID, sha) conf, err = store.ConfigFindIdentical(pipeline.RepoID, sha)
if err != nil { if err != nil {
return nil, err return nil, err
} }
} }
} }
buildConfig := &model.BuildConfig{ pipelineConfig := &model.PipelineConfig{
ConfigID: conf.ID, ConfigID: conf.ID,
BuildID: build.ID, PipelineID: pipeline.ID,
} }
if err := store.BuildConfigCreate(buildConfig); err != nil { if err := store.PipelineConfigCreate(pipelineConfig); err != nil {
return nil, err return nil, err
} }

View file

@ -28,8 +28,8 @@ import (
"github.com/woodpecker-ci/woodpecker/server/store" "github.com/woodpecker-ci/woodpecker/server/store"
) )
// Create a new build and start it // Create a new pipeline and start it
func Create(ctx context.Context, _store store.Store, repo *model.Repo, build *model.Build) (*model.Build, error) { func Create(ctx context.Context, _store store.Store, repo *model.Repo, pipeline *model.Pipeline) (*model.Pipeline, error) {
repoUser, err := _store.GetUser(repo.UserID) repoUser, err := _store.GetUser(repo.UserID)
if err != nil { if err != nil {
msg := fmt.Sprintf("failure to find repo owner via id '%d'", repo.UserID) msg := fmt.Sprintf("failure to find repo owner via id '%d'", repo.UserID)
@ -39,7 +39,7 @@ func Create(ctx context.Context, _store store.Store, repo *model.Repo, build *mo
// if the remote has a refresh token, the current access token // if the remote has a refresh token, the current access token
// may be stale. Therefore, we should refresh prior to dispatching // may be stale. Therefore, we should refresh prior to dispatching
// the build. // the pipeline.
if refresher, ok := server.Config.Services.Remote.(remote.Refresher); ok { if refresher, ok := server.Config.Services.Remote.(remote.Refresher); ok {
refreshed, err := refresher.Refresh(ctx, repoUser) refreshed, err := refresher.Refresh(ctx, repoUser)
if err != nil { if err != nil {
@ -59,11 +59,11 @@ func Create(ctx context.Context, _store store.Store, repo *model.Repo, build *mo
parseErr error parseErr error
) )
// fetch the build file from the remote // fetch the pipeline file from the remote
configFetcher := shared.NewConfigFetcher(server.Config.Services.Remote, server.Config.Services.ConfigService, repoUser, repo, build) configFetcher := shared.NewConfigFetcher(server.Config.Services.Remote, server.Config.Services.ConfigService, repoUser, repo, pipeline)
remoteYamlConfigs, configFetchErr = configFetcher.Fetch(ctx) remoteYamlConfigs, configFetchErr = configFetcher.Fetch(ctx)
if configFetchErr == nil { if configFetchErr == nil {
filtered, parseErr = checkIfFiltered(build, remoteYamlConfigs) filtered, parseErr = checkIfFiltered(pipeline, remoteYamlConfigs)
if parseErr == nil { if parseErr == nil {
if filtered { if filtered {
err := ErrFiltered{Msg: "branch does not match restrictions defined in yaml"} err := ErrFiltered{Msg: "branch does not match restrictions defined in yaml"}
@ -71,7 +71,7 @@ func Create(ctx context.Context, _store store.Store, repo *model.Repo, build *mo
return nil, err return nil, err
} }
if zeroSteps(build, remoteYamlConfigs) { if zeroSteps(pipeline, remoteYamlConfigs) {
err := ErrFiltered{Msg: "step conditions yield zero runnable steps"} err := ErrFiltered{Msg: "step conditions yield zero runnable steps"}
log.Debug().Str("repo", repo.FullName).Msgf("%v", err) log.Debug().Str("repo", repo.FullName).Msgf("%v", err)
return nil, err return nil, err
@ -79,38 +79,38 @@ func Create(ctx context.Context, _store store.Store, repo *model.Repo, build *mo
} }
} }
// update some build fields // update some pipeline fields
build.RepoID = repo.ID pipeline.RepoID = repo.ID
build.Verified = true pipeline.Verified = true
build.Status = model.StatusPending pipeline.Status = model.StatusPending
if configFetchErr != nil { if configFetchErr != nil {
log.Debug().Str("repo", repo.FullName).Err(configFetchErr).Msgf("cannot find config '%s' in '%s' with user: '%s'", repo.Config, build.Ref, repoUser.Login) log.Debug().Str("repo", repo.FullName).Err(configFetchErr).Msgf("cannot find config '%s' in '%s' with user: '%s'", repo.Config, pipeline.Ref, repoUser.Login)
build.Started = time.Now().Unix() pipeline.Started = time.Now().Unix()
build.Finished = build.Started pipeline.Finished = pipeline.Started
build.Status = model.StatusError pipeline.Status = model.StatusError
build.Error = fmt.Sprintf("pipeline definition not found in %s", repo.FullName) pipeline.Error = fmt.Sprintf("pipeline definition not found in %s", repo.FullName)
} else if parseErr != nil { } else if parseErr != nil {
log.Debug().Str("repo", repo.FullName).Err(parseErr).Msg("failed to parse yaml") log.Debug().Str("repo", repo.FullName).Err(parseErr).Msg("failed to parse yaml")
build.Started = time.Now().Unix() pipeline.Started = time.Now().Unix()
build.Finished = build.Started pipeline.Finished = pipeline.Started
build.Status = model.StatusError pipeline.Status = model.StatusError
build.Error = fmt.Sprintf("failed to parse pipeline: %s", parseErr.Error()) pipeline.Error = fmt.Sprintf("failed to parse pipeline: %s", parseErr.Error())
} else if repo.IsGated { } else if repo.IsGated {
// TODO(336) extend gated feature with an allow/block List // TODO(336) extend gated feature with an allow/block List
build.Status = model.StatusBlocked pipeline.Status = model.StatusBlocked
} }
err = _store.CreateBuild(build, build.Procs...) err = _store.CreatePipeline(pipeline, pipeline.Procs...)
if err != nil { if err != nil {
msg := fmt.Sprintf("failure to save build for %s", repo.FullName) msg := fmt.Sprintf("failure to save pipeline for %s", repo.FullName)
log.Error().Err(err).Msg(msg) log.Error().Err(err).Msg(msg)
return nil, fmt.Errorf(msg) return nil, fmt.Errorf(msg)
} }
// persist the build config for historical correctness, restarts, etc // persist the pipeline config for historical correctness, restarts, etc
for _, remoteYamlConfig := range remoteYamlConfigs { for _, remoteYamlConfig := range remoteYamlConfigs {
_, err := findOrPersistPipelineConfig(_store, build, remoteYamlConfig) _, err := findOrPersistPipelineConfig(_store, pipeline, remoteYamlConfig)
if err != nil { if err != nil {
msg := fmt.Sprintf("failure to find or persist pipeline config for %s", repo.FullName) msg := fmt.Sprintf("failure to find or persist pipeline config for %s", repo.FullName)
log.Error().Err(err).Msg(msg) log.Error().Err(err).Msg(msg)
@ -118,43 +118,43 @@ func Create(ctx context.Context, _store store.Store, repo *model.Repo, build *mo
} }
} }
if build.Status == model.StatusError { if pipeline.Status == model.StatusError {
if err := publishToTopic(ctx, build, repo); err != nil { if err := publishToTopic(ctx, pipeline, repo); err != nil {
log.Error().Err(err).Msg("publishToTopic") log.Error().Err(err).Msg("publishToTopic")
} }
if err := updateBuildStatus(ctx, build, repo, repoUser); err != nil { if err := updatePipelineStatus(ctx, pipeline, repo, repoUser); err != nil {
log.Error().Err(err).Msg("updateBuildStatus") log.Error().Err(err).Msg("updatePipelineStatus")
} }
return build, nil return pipeline, nil
} }
build, buildItems, err := createBuildItems(ctx, _store, build, repoUser, repo, remoteYamlConfigs, nil) pipeline, pipelineItems, err := createPipelineItems(ctx, _store, pipeline, repoUser, repo, remoteYamlConfigs, nil)
if err != nil { if err != nil {
msg := fmt.Sprintf("failure to createBuildItems for %s", repo.FullName) msg := fmt.Sprintf("failure to createPipelineItems for %s", repo.FullName)
log.Error().Err(err).Msg(msg) log.Error().Err(err).Msg(msg)
return nil, fmt.Errorf(msg) return nil, fmt.Errorf(msg)
} }
if build.Status == model.StatusBlocked { if pipeline.Status == model.StatusBlocked {
if err := publishToTopic(ctx, build, repo); err != nil { if err := publishToTopic(ctx, pipeline, repo); err != nil {
log.Error().Err(err).Msg("publishToTopic") log.Error().Err(err).Msg("publishToTopic")
} }
if err := updateBuildStatus(ctx, build, repo, repoUser); err != nil { if err := updatePipelineStatus(ctx, pipeline, repo, repoUser); err != nil {
log.Error().Err(err).Msg("updateBuildStatus") log.Error().Err(err).Msg("updatePipelineStatus")
} }
return build, nil return pipeline, nil
} }
build, err = start(ctx, _store, build, repoUser, repo, buildItems) pipeline, err = start(ctx, _store, pipeline, repoUser, repo, pipelineItems)
if err != nil { if err != nil {
msg := fmt.Sprintf("failure to start build for %s", repo.FullName) msg := fmt.Sprintf("failure to start pipeline for %s", repo.FullName)
log.Error().Err(err).Msg(msg) log.Error().Err(err).Msg(msg)
return nil, fmt.Errorf(msg) return nil, fmt.Errorf(msg)
} }
return build, nil return pipeline, nil
} }

View file

@ -24,31 +24,31 @@ import (
"github.com/woodpecker-ci/woodpecker/server/store" "github.com/woodpecker-ci/woodpecker/server/store"
) )
// Decline update the status to declined for blocked build because of a gated repo // Decline update the status to declined for blocked pipeline because of a gated repo
func Decline(ctx context.Context, store store.Store, build *model.Build, user *model.User, repo *model.Repo) (*model.Build, error) { func Decline(ctx context.Context, store store.Store, pipeline *model.Pipeline, user *model.User, repo *model.Repo) (*model.Pipeline, error) {
if build.Status != model.StatusBlocked { if pipeline.Status != model.StatusBlocked {
return nil, fmt.Errorf("cannot decline a build with status %s", build.Status) return nil, fmt.Errorf("cannot decline a pipeline with status %s", pipeline.Status)
} }
_, err := shared.UpdateToStatusDeclined(store, *build, user.Login) _, err := shared.UpdateToStatusDeclined(store, *pipeline, user.Login)
if err != nil { if err != nil {
return nil, fmt.Errorf("error updating build. %s", err) return nil, fmt.Errorf("error updating pipeline. %s", err)
} }
if build.Procs, err = store.ProcList(build); err != nil { if pipeline.Procs, err = store.ProcList(pipeline); err != nil {
log.Error().Err(err).Msg("can not get proc list from store") log.Error().Err(err).Msg("can not get proc list from store")
} }
if build.Procs, err = model.Tree(build.Procs); err != nil { if pipeline.Procs, err = model.Tree(pipeline.Procs); err != nil {
log.Error().Err(err).Msg("can not build tree from proc list") log.Error().Err(err).Msg("can not build tree from proc list")
} }
if err := updateBuildStatus(ctx, build, repo, user); err != nil { if err := updatePipelineStatus(ctx, pipeline, repo, user); err != nil {
log.Error().Err(err).Msg("updateBuildStatus") log.Error().Err(err).Msg("updateBuildStatus")
} }
if err := publishToTopic(ctx, build, repo); err != nil { if err := publishToTopic(ctx, pipeline, repo); err != nil {
log.Error().Err(err).Msg("publishToTopic") log.Error().Err(err).Msg("publishToTopic")
} }
return build, nil return pipeline, nil
} }

View file

@ -26,11 +26,11 @@ import (
"github.com/woodpecker-ci/woodpecker/server/shared" "github.com/woodpecker-ci/woodpecker/server/shared"
) )
func zeroSteps(build *model.Build, remoteYamlConfigs []*remote.FileMeta) bool { func zeroSteps(pipeline *model.Pipeline, remoteYamlConfigs []*remote.FileMeta) bool {
b := shared.ProcBuilder{ b := shared.ProcBuilder{
Repo: &model.Repo{}, Repo: &model.Repo{},
Curr: build, Curr: pipeline,
Last: &model.Build{}, Last: &model.Pipeline{},
Netrc: &model.Netrc{}, Netrc: &model.Netrc{},
Secs: []*model.Secret{}, Secs: []*model.Secret{},
Regs: []*model.Registry{}, Regs: []*model.Registry{},
@ -38,11 +38,11 @@ func zeroSteps(build *model.Build, remoteYamlConfigs []*remote.FileMeta) bool {
Yamls: remoteYamlConfigs, Yamls: remoteYamlConfigs,
} }
buildItems, err := b.Build() pipelineItems, err := b.Build()
if err != nil { if err != nil {
return false return false
} }
if len(buildItems) == 0 { if len(pipelineItems) == 0 {
return true return true
} }
@ -51,14 +51,14 @@ func zeroSteps(build *model.Build, remoteYamlConfigs []*remote.FileMeta) bool {
// TODO: parse yaml once and not for each filter function // TODO: parse yaml once and not for each filter function
// Check if at least one pipeline step will be execute otherwise we will just ignore this webhook // Check if at least one pipeline step will be execute otherwise we will just ignore this webhook
func checkIfFiltered(build *model.Build, remoteYamlConfigs []*remote.FileMeta) (bool, error) { func checkIfFiltered(pipeline *model.Pipeline, remoteYamlConfigs []*remote.FileMeta) (bool, error) {
log.Trace().Msgf("hook.branchFiltered(): build branch: '%s' build event: '%s' config count: %d", build.Branch, build.Event, len(remoteYamlConfigs)) log.Trace().Msgf("hook.branchFiltered(): pipeline branch: '%s' pipeline event: '%s' config count: %d", pipeline.Branch, pipeline.Event, len(remoteYamlConfigs))
matchMetadata := frontend.Metadata{ matchMetadata := frontend.Metadata{
Curr: frontend.Build{ Curr: frontend.Pipeline{
Event: string(build.Event), Event: string(pipeline.Event),
Commit: frontend.Commit{ Commit: frontend.Commit{
Branch: build.Branch, Branch: pipeline.Branch,
}, },
}, },
} }
@ -79,7 +79,7 @@ func checkIfFiltered(build *model.Build, remoteYamlConfigs []*remote.FileMeta) (
} }
// ignore if the pipeline was filtered by the branch (legacy) // ignore if the pipeline was filtered by the branch (legacy)
if !parsedPipelineConfig.Branches.Match(build.Branch) { if !parsedPipelineConfig.Branches.Match(pipeline.Branch) {
continue continue
} }

View file

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

View file

@ -28,26 +28,26 @@ import (
"github.com/woodpecker-ci/woodpecker/server/store" "github.com/woodpecker-ci/woodpecker/server/store"
) )
func createBuildItems(ctx context.Context, store store.Store, build *model.Build, user *model.User, repo *model.Repo, yamls []*remote.FileMeta, envs map[string]string) (*model.Build, []*shared.BuildItem, error) { func createPipelineItems(ctx context.Context, store store.Store, pipeline *model.Pipeline, user *model.User, repo *model.Repo, yamls []*remote.FileMeta, envs map[string]string) (*model.Pipeline, []*shared.PipelineItem, error) {
netrc, err := server.Config.Services.Remote.Netrc(user, repo) netrc, err := server.Config.Services.Remote.Netrc(user, repo)
if err != nil { if err != nil {
log.Error().Err(err).Msg("Failed to generate netrc file") log.Error().Err(err).Msg("Failed to generate netrc file")
} }
// get the previous build so that we can send status change notifications // get the previous pipeline so that we can send status change notifications
last, err := store.GetBuildLastBefore(repo, build.Branch, build.ID) last, err := store.GetPipelineLastBefore(repo, pipeline.Branch, pipeline.ID)
if err != nil && !errors.Is(err, sql.ErrNoRows) { if err != nil && !errors.Is(err, sql.ErrNoRows) {
log.Error().Err(err).Str("repo", repo.FullName).Msgf("Error getting last build before build number '%d'", build.Number) log.Error().Err(err).Str("repo", repo.FullName).Msgf("Error getting last pipeline before pipeline number '%d'", pipeline.Number)
} }
secs, err := server.Config.Services.Secrets.SecretListBuild(repo, build) secs, err := server.Config.Services.Secrets.SecretListPipeline(repo, pipeline)
if err != nil { if err != nil {
log.Error().Err(err).Msgf("Error getting secrets for %s#%d", repo.FullName, build.Number) log.Error().Err(err).Msgf("Error getting secrets for %s#%d", repo.FullName, pipeline.Number)
} }
regs, err := server.Config.Services.Registries.RegistryList(repo) regs, err := server.Config.Services.Registries.RegistryList(repo)
if err != nil { if err != nil {
log.Error().Err(err).Msgf("Error getting registry credentials for %s#%d", repo.FullName, build.Number) log.Error().Err(err).Msgf("Error getting registry credentials for %s#%d", repo.FullName, pipeline.Number)
} }
if envs == nil { if envs == nil {
@ -60,13 +60,13 @@ func createBuildItems(ctx context.Context, store store.Store, build *model.Build
} }
} }
for k, v := range build.AdditionalVariables { for k, v := range pipeline.AdditionalVariables {
envs[k] = v envs[k] = v
} }
b := shared.ProcBuilder{ b := shared.ProcBuilder{
Repo: repo, Repo: repo,
Curr: build, Curr: pipeline,
Last: last, Last: last,
Netrc: netrc, Netrc: netrc,
Secs: secs, Secs: secs,
@ -75,16 +75,16 @@ func createBuildItems(ctx context.Context, store store.Store, build *model.Build
Link: server.Config.Server.Host, Link: server.Config.Server.Host,
Yamls: yamls, Yamls: yamls,
} }
buildItems, err := b.Build() pipelineItems, err := b.Build()
if err != nil { if err != nil {
build, uerr := shared.UpdateToStatusError(store, *build, err) pipeline, uerr := shared.UpdateToStatusError(store, *pipeline, err)
if uerr != nil { if uerr != nil {
log.Error().Err(err).Msgf("Error setting error status of build for %s#%d", repo.FullName, build.Number) log.Error().Err(err).Msgf("Error setting error status of pipeline for %s#%d", repo.FullName, pipeline.Number)
} }
return build, nil, err return pipeline, nil, err
} }
build = shared.SetBuildStepsOnBuild(b.Curr, buildItems) pipeline = shared.SetPipelineStepsOnPipeline(b.Curr, pipelineItems)
return build, buildItems, nil return pipeline, pipelineItems, nil
} }

View file

@ -26,9 +26,9 @@ import (
"github.com/woodpecker-ci/woodpecker/server/shared" "github.com/woodpecker-ci/woodpecker/server/shared"
) )
func queueBuild(build *model.Build, repo *model.Repo, buildItems []*shared.BuildItem) error { func queueBuild(pipeline *model.Pipeline, repo *model.Repo, pipelineItems []*shared.PipelineItem) error {
var tasks []*queue.Task var tasks []*queue.Task
for _, item := range buildItems { for _, item := range pipelineItems {
if item.Proc.State == model.StatusSkipped { if item.Proc.State == model.StatusSkipped {
continue continue
} }
@ -40,7 +40,7 @@ func queueBuild(build *model.Build, repo *model.Repo, buildItems []*shared.Build
} }
task.Labels["platform"] = item.Platform task.Labels["platform"] = item.Platform
task.Labels["repo"] = repo.FullName task.Labels["repo"] = repo.FullName
task.Dependencies = taskIds(item.DependsOn, buildItems) task.Dependencies = taskIds(item.DependsOn, pipelineItems)
task.RunOn = item.RunsOn task.RunOn = item.RunsOn
task.DepStatus = make(map[string]string) task.DepStatus = make(map[string]string)
@ -58,11 +58,11 @@ func queueBuild(build *model.Build, repo *model.Repo, buildItems []*shared.Build
return server.Config.Services.Queue.PushAtOnce(context.Background(), tasks) return server.Config.Services.Queue.PushAtOnce(context.Background(), tasks)
} }
func taskIds(dependsOn []string, buildItems []*shared.BuildItem) (taskIds []string) { func taskIds(dependsOn []string, pipelineItems []*shared.PipelineItem) (taskIds []string) {
for _, dep := range dependsOn { for _, dep := range dependsOn {
for _, buildItem := range buildItems { for _, pipelineItem := range pipelineItems {
if buildItem.Proc.Name == dep { if pipelineItem.Proc.Name == dep {
taskIds = append(taskIds, fmt.Sprint(buildItem.Proc.ID)) taskIds = append(taskIds, fmt.Sprint(pipelineItem.Proc.ID))
} }
} }
} }

View file

@ -30,20 +30,20 @@ import (
"github.com/woodpecker-ci/woodpecker/server/store" "github.com/woodpecker-ci/woodpecker/server/store"
) )
// Restart a build by creating a new one out of the old and start it // Restart a pipeline by creating a new one out of the old and start it
func Restart(ctx context.Context, store store.Store, lastBuild *model.Build, user *model.User, repo *model.Repo, envs map[string]string) (*model.Build, error) { func Restart(ctx context.Context, store store.Store, lastBuild *model.Pipeline, user *model.User, repo *model.Repo, envs map[string]string) (*model.Pipeline, error) {
switch lastBuild.Status { switch lastBuild.Status {
case model.StatusDeclined, case model.StatusDeclined,
model.StatusBlocked: model.StatusBlocked:
return nil, ErrBadRequest{Msg: fmt.Sprintf("cannot restart a build with status %s", lastBuild.Status)} return nil, ErrBadRequest{Msg: fmt.Sprintf("cannot restart a pipeline with status %s", lastBuild.Status)}
} }
var pipelineFiles []*remote.FileMeta var pipelineFiles []*remote.FileMeta
// fetch the old pipeline config from database // fetch the old pipeline config from database
configs, err := store.ConfigsForBuild(lastBuild.ID) configs, err := store.ConfigsForPipeline(lastBuild.ID)
if err != nil { if err != nil {
msg := fmt.Sprintf("failure to get build config for %s. %s", repo.FullName, err) msg := fmt.Sprintf("failure to get pipeline config for %s. %s", repo.FullName, err)
log.Error().Msgf(msg) log.Error().Msgf(msg)
return nil, ErrNotFound{Msg: msg} return nil, ErrNotFound{Msg: msg}
} }
@ -62,7 +62,7 @@ func Restart(ctx context.Context, store store.Store, lastBuild *model.Build, use
newConfig, useOld, err := server.Config.Services.ConfigService.FetchConfig(ctx, repo, lastBuild, currentFileMeta) newConfig, useOld, err := server.Config.Services.ConfigService.FetchConfig(ctx, repo, lastBuild, currentFileMeta)
if err != nil { if err != nil {
return nil, ErrBadRequest{ return nil, ErrBadRequest{
Msg: fmt.Sprintf("On fetching external build config: %s", err), Msg: fmt.Sprintf("On fetching external pipeline config: %s", err),
} }
} }
if !useOld { if !useOld {
@ -70,12 +70,12 @@ func Restart(ctx context.Context, store store.Store, lastBuild *model.Build, use
} }
} }
newBuild := createNewBuildOutOfOld(lastBuild) newBuild := createNewOutOfOld(lastBuild)
newBuild.Parent = lastBuild.ID newBuild.Parent = lastBuild.ID
err = store.CreateBuild(newBuild) err = store.CreatePipeline(newBuild)
if err != nil { if err != nil {
msg := fmt.Sprintf("failure to save build for %s", repo.FullName) msg := fmt.Sprintf("failure to save pipeline for %s", repo.FullName)
log.Error().Err(err).Msg(msg) log.Error().Err(err).Msg(msg)
return nil, fmt.Errorf(msg) return nil, fmt.Errorf(msg)
} }
@ -87,13 +87,13 @@ func Restart(ctx context.Context, store store.Store, lastBuild *model.Build, use
} }
return newBuild, nil return newBuild, nil
} }
if err := persistBuildConfigs(store, configs, newBuild.ID); err != nil { if err := persistPipelineConfigs(store, configs, newBuild.ID); err != nil {
msg := fmt.Sprintf("failure to persist build config for %s.", repo.FullName) msg := fmt.Sprintf("failure to persist pipeline config for %s.", repo.FullName)
log.Error().Err(err).Msg(msg) log.Error().Err(err).Msg(msg)
return nil, fmt.Errorf(msg) return nil, fmt.Errorf(msg)
} }
newBuild, buildItems, err := createBuildItems(ctx, store, newBuild, user, repo, pipelineFiles, envs) newBuild, pipelineItems, err := createPipelineItems(ctx, store, newBuild, user, repo, pipelineFiles, envs)
if err != nil { if err != nil {
if errors.Is(err, &yaml.PipelineParseError{}) { if errors.Is(err, &yaml.PipelineParseError{}) {
return newBuild, nil return newBuild, nil
@ -103,9 +103,9 @@ func Restart(ctx context.Context, store store.Store, lastBuild *model.Build, use
return nil, fmt.Errorf(msg) return nil, fmt.Errorf(msg)
} }
newBuild, err = start(ctx, store, newBuild, user, repo, buildItems) newBuild, err = start(ctx, store, newBuild, user, repo, pipelineItems)
if err != nil { if err != nil {
msg := fmt.Sprintf("failure to start build for %s", repo.FullName) msg := fmt.Sprintf("failure to start pipeline for %s", repo.FullName)
log.Error().Err(err).Msg(msg) log.Error().Err(err).Msg(msg)
return nil, fmt.Errorf(msg) return nil, fmt.Errorf(msg)
} }
@ -114,13 +114,13 @@ func Restart(ctx context.Context, store store.Store, lastBuild *model.Build, use
} }
// TODO: reuse at create.go too // TODO: reuse at create.go too
func persistBuildConfigs(store store.Store, configs []*model.Config, buildID int64) error { func persistPipelineConfigs(store store.Store, configs []*model.Config, pipelineID int64) error {
for _, conf := range configs { for _, conf := range configs {
buildConfig := &model.BuildConfig{ pipelineConfig := &model.PipelineConfig{
ConfigID: conf.ID, ConfigID: conf.ID,
BuildID: buildID, PipelineID: pipelineID,
} }
err := store.BuildConfigCreate(buildConfig) err := store.PipelineConfigCreate(pipelineConfig)
if err != nil { if err != nil {
return err return err
} }
@ -128,7 +128,7 @@ func persistBuildConfigs(store store.Store, configs []*model.Config, buildID int
return nil return nil
} }
func createNewBuildOutOfOld(old *model.Build) *model.Build { func createNewOutOfOld(old *model.Pipeline) *model.Pipeline {
new := *old new := *old
new.ID = 0 new.ID = 0
new.Number = 0 new.Number = 0

View file

@ -24,31 +24,31 @@ import (
"github.com/woodpecker-ci/woodpecker/server/store" "github.com/woodpecker-ci/woodpecker/server/store"
) )
// start a build, make sure it was stored persistent in the store before // start a pipeline, make sure it was stored persistent in the store before
func start(ctx context.Context, store store.Store, activeBuild *model.Build, user *model.User, repo *model.Repo, buildItems []*shared.BuildItem) (*model.Build, error) { func start(ctx context.Context, store store.Store, activePipeline *model.Pipeline, user *model.User, repo *model.Repo, pipelineItems []*shared.PipelineItem) (*model.Pipeline, error) {
// call to cancel previous builds if needed // call to cancel previous pipelines if needed
if err := cancelPreviousPipelines(ctx, store, activeBuild, repo); err != nil { if err := cancelPreviousPipelines(ctx, store, activePipeline, repo); err != nil {
// should be not breaking // should be not breaking
log.Error().Err(err).Msg("Failed to cancel previous builds") log.Error().Err(err).Msg("Failed to cancel previous pipelines")
} }
if err := store.ProcCreate(activeBuild.Procs); err != nil { 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, activeBuild.Number) log.Error().Err(err).Str("repo", repo.FullName).Msgf("error persisting procs for %s#%d", repo.FullName, activePipeline.Number)
return nil, err return nil, err
} }
if err := publishToTopic(ctx, activeBuild, repo); err != nil { if err := publishToTopic(ctx, activePipeline, repo); err != nil {
log.Error().Err(err).Msg("publishToTopic") log.Error().Err(err).Msg("publishToTopic")
} }
if err := queueBuild(activeBuild, repo, buildItems); err != nil { if err := queueBuild(activePipeline, repo, pipelineItems); err != nil {
log.Error().Err(err).Msg("queueBuild") log.Error().Err(err).Msg("queueBuild")
return nil, err return nil, err
} }
if err := updateBuildStatus(ctx, activeBuild, repo, user); err != nil { if err := updatePipelineStatus(ctx, activePipeline, repo, user); err != nil {
log.Error().Err(err).Msg("updateBuildStatus") log.Error().Err(err).Msg("updateBuildStatus")
} }
return activeBuild, nil return activePipeline, nil
} }

View file

@ -25,21 +25,21 @@ import (
) )
// publishToTopic publishes message to UI clients // publishToTopic publishes message to UI clients
func publishToTopic(c context.Context, build *model.Build, repo *model.Repo) (err error) { func publishToTopic(c context.Context, pipeline *model.Pipeline, repo *model.Repo) (err error) {
message := pubsub.Message{ message := pubsub.Message{
Labels: map[string]string{ Labels: map[string]string{
"repo": repo.FullName, "repo": repo.FullName,
"private": strconv.FormatBool(repo.IsSCMPrivate), "private": strconv.FormatBool(repo.IsSCMPrivate),
}, },
} }
buildCopy := *build pipelineCopy := *pipeline
if buildCopy.Procs, err = model.Tree(buildCopy.Procs); err != nil { if pipelineCopy.Procs, err = model.Tree(pipelineCopy.Procs); err != nil {
return err return err
} }
message.Data, _ = json.Marshal(model.Event{ message.Data, _ = json.Marshal(model.Event{
Repo: *repo, Repo: *repo,
Build: buildCopy, Pipeline: pipelineCopy,
}) })
return server.Config.Services.Pubsub.Publish(c, "topic/events", message) return server.Config.Services.Pubsub.Publish(c, "topic/events", message)
} }

View file

@ -1,3 +1,17 @@
// 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 config package config
import ( import (
@ -9,5 +23,5 @@ import (
type Extension interface { type Extension interface {
IsConfigured() bool IsConfigured() bool
FetchConfig(ctx context.Context, repo *model.Repo, build *model.Build, currentFileMeta []*remote.FileMeta) (configData []*remote.FileMeta, useOld bool, err error) FetchConfig(ctx context.Context, repo *model.Repo, pipeline *model.Pipeline, currentFileMeta []*remote.FileMeta) (configData []*remote.FileMeta, useOld bool, err error)
} }

View file

@ -1,3 +1,17 @@
// 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 config package config
import ( import (
@ -23,7 +37,7 @@ type config struct {
type requestStructure struct { type requestStructure struct {
Repo *model.Repo `json:"repo"` Repo *model.Repo `json:"repo"`
Build *model.Build `json:"build"` Pipeline *model.Pipeline `json:"build"`
Configuration []*config `json:"configs"` Configuration []*config `json:"configs"`
} }
@ -39,14 +53,14 @@ func (cp *http) IsConfigured() bool {
return cp.endpoint != "" return cp.endpoint != ""
} }
func (cp *http) FetchConfig(ctx context.Context, repo *model.Repo, build *model.Build, currentFileMeta []*remote.FileMeta) (configData []*remote.FileMeta, useOld bool, err error) { func (cp *http) FetchConfig(ctx context.Context, repo *model.Repo, pipeline *model.Pipeline, currentFileMeta []*remote.FileMeta) (configData []*remote.FileMeta, useOld bool, err error) {
currentConfigs := make([]*config, len(currentFileMeta)) currentConfigs := make([]*config, len(currentFileMeta))
for i, pipe := range currentFileMeta { for i, pipe := range currentFileMeta {
currentConfigs[i] = &config{Name: pipe.Name, Data: string(pipe.Data)} currentConfigs[i] = &config{Name: pipe.Name, Data: string(pipe.Data)}
} }
response := new(responseStructure) response := new(responseStructure)
body := requestStructure{Repo: repo, Build: build, Configuration: currentConfigs} body := requestStructure{Repo: repo, Pipeline: pipeline, Configuration: currentConfigs}
status, err := utils.Send(ctx, "POST", cp.endpoint, cp.privateKey, body, response) status, err := utils.Send(ctx, "POST", cp.endpoint, cp.privateKey, body, response)
if err != nil && status != 204 { if err != nil && status != 204 {
return nil, false, fmt.Errorf("Failed to fetch config via http (%d) %w", status, err) return nil, false, fmt.Errorf("Failed to fetch config via http (%d) %w", status, err)

View file

@ -1,3 +1,17 @@
// 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 secrets package secrets
import ( import (
@ -24,7 +38,7 @@ func (b *builtin) SecretList(repo *model.Repo) ([]*model.Secret, error) {
return b.store.SecretList(repo, false) return b.store.SecretList(repo, false)
} }
func (b *builtin) SecretListBuild(repo *model.Repo, build *model.Build) ([]*model.Secret, error) { func (b *builtin) SecretListPipeline(repo *model.Repo, pipeline *model.Pipeline) ([]*model.Secret, error) {
s, err := b.store.SecretList(repo, true) s, err := b.store.SecretList(repo, true)
if err != nil { if err != nil {
return nil, err return nil, err

View file

@ -1,3 +1,17 @@
// 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 queue package queue
import ( import (
@ -241,7 +255,7 @@ func (q *fifo) process() {
} }
}() }()
q.resubmitExpiredBuilds() q.resubmitExpiredPipelines()
q.filterWaiting() q.filterWaiting()
for pending, worker := q.assignToWorker(); pending != nil && worker != nil; pending, worker = q.assignToWorker() { for pending, worker := q.assignToWorker(); pending != nil && worker != nil; pending, worker = q.assignToWorker() {
task := pending.Value.(*Task) task := pending.Value.(*Task)
@ -303,7 +317,7 @@ func (q *fifo) assignToWorker() (*list.Element, *worker) {
return nil, nil return nil, nil
} }
func (q *fifo) resubmitExpiredBuilds() { func (q *fifo) resubmitExpiredPipelines() {
for id, state := range q.running { for id, state := range q.running {
if time.Now().After(state.deadline) { if time.Now().After(state.deadline) {
q.pending.PushFront(state.item) q.pending.PushFront(state.item)

View file

@ -1,3 +1,4 @@
// Copyright 2022 Woodpecker Authors
// Copyright 2018 Drone.IO Inc. // Copyright 2018 Drone.IO Inc.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
@ -213,27 +214,27 @@ func (c *config) Perm(ctx context.Context, u *model.User, r *model.Repo) (*model
} }
// File fetches the file from the Bitbucket repository and returns its contents. // File fetches the file from the Bitbucket repository and returns its contents.
func (c *config) File(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, f string) ([]byte, error) { func (c *config) File(ctx context.Context, u *model.User, r *model.Repo, p *model.Pipeline, f string) ([]byte, error) {
config, err := c.newClient(ctx, u).FindSource(r.Owner, r.Name, b.Commit, f) config, err := c.newClient(ctx, u).FindSource(r.Owner, r.Name, p.Commit, f)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return []byte(*config), err return []byte(*config), err
} }
func (c *config) Dir(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, f string) ([]*remote.FileMeta, error) { func (c *config) Dir(ctx context.Context, u *model.User, r *model.Repo, p *model.Pipeline, f string) ([]*remote.FileMeta, error) {
return nil, fmt.Errorf("Not implemented") return nil, fmt.Errorf("Not implemented")
} }
// Status creates a build status for the Bitbucket commit. // Status creates a pipeline status for the Bitbucket commit.
func (c *config) Status(ctx context.Context, user *model.User, repo *model.Repo, build *model.Build, proc *model.Proc) error { func (c *config) Status(ctx context.Context, user *model.User, repo *model.Repo, pipeline *model.Pipeline, proc *model.Proc) error {
status := internal.BuildStatus{ status := internal.PipelineStatus{
State: convertStatus(build.Status), State: convertStatus(pipeline.Status),
Desc: common.GetBuildStatusDescription(build.Status), Desc: common.GetPipelineStatusDescription(pipeline.Status),
Key: "Woodpecker", Key: "Woodpecker",
URL: common.GetBuildStatusLink(repo, build, nil), URL: common.GetPipelineStatusLink(repo, pipeline, nil),
} }
return c.newClient(ctx, user).CreateStatus(repo.Owner, repo.Name, build.Commit, &status) return c.newClient(ctx, user).CreateStatus(repo.Owner, repo.Name, pipeline.Commit, &status)
} }
// Activate activates the repository by registering repository push hooks with // Activate activates the repository by registering repository push hooks with
@ -301,8 +302,8 @@ func (c *config) BranchHead(ctx context.Context, u *model.User, r *model.Repo, b
} }
// Hook parses the incoming Bitbucket hook and returns the Repository and // Hook parses the incoming Bitbucket hook and returns the Repository and
// Build details. If the hook is unsupported nil values are returned. // Pipeline details. If the hook is unsupported nil values are returned.
func (c *config) Hook(ctx context.Context, req *http.Request) (*model.Repo, *model.Build, error) { func (c *config) Hook(ctx context.Context, req *http.Request) (*model.Repo, *model.Pipeline, error) {
return parseHook(req) return parseHook(req)
} }

View file

@ -1,3 +1,4 @@
// Copyright 2022 Woodpecker Authors
// Copyright 2018 Drone.IO Inc. // Copyright 2018 Drone.IO Inc.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
@ -195,12 +196,12 @@ func Test_bitbucket(t *testing.T) {
g.Describe("When downloading a file", func() { g.Describe("When downloading a file", func() {
g.It("Should return the bytes", func() { g.It("Should return the bytes", func() {
raw, err := c.File(ctx, fakeUser, fakeRepo, fakeBuild, "file") raw, err := c.File(ctx, fakeUser, fakeRepo, fakePipeline, "file")
g.Assert(err).IsNil() g.Assert(err).IsNil()
g.Assert(len(raw) != 0).IsTrue() g.Assert(len(raw) != 0).IsTrue()
}) })
g.It("Should handle not found error", func() { g.It("Should handle not found error", func() {
_, err := c.File(ctx, fakeUser, fakeRepo, fakeBuild, "file_not_found") _, err := c.File(ctx, fakeUser, fakeRepo, fakePipeline, "file_not_found")
g.Assert(err).IsNotNil() g.Assert(err).IsNotNil()
}) })
}) })
@ -254,7 +255,7 @@ func Test_bitbucket(t *testing.T) {
}) })
g.It("Should update the status", func() { g.It("Should update the status", func() {
err := c.Status(ctx, fakeUser, fakeRepo, fakeBuild, fakeProc) err := c.Status(ctx, fakeUser, fakeRepo, fakePipeline, fakeProc)
g.Assert(err).IsNil() g.Assert(err).IsNil()
}) })
@ -350,7 +351,7 @@ var (
FullName: "test_name/permission_admin", FullName: "test_name/permission_admin",
} }
fakeBuild = &model.Build{ fakePipeline = &model.Pipeline{
Commit: "9ecad50", Commit: "9ecad50",
} }

View file

@ -1,3 +1,4 @@
// Copyright 2022 Woodpecker Authors
// Copyright 2018 Drone.IO Inc. // Copyright 2018 Drone.IO Inc.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
@ -129,9 +130,9 @@ func convertWorkspace(from *internal.Workspace) *model.Team {
} }
// convertPullHook is a helper function used to convert a Bitbucket pull request // convertPullHook is a helper function used to convert a Bitbucket pull request
// hook to the Woodpecker build struct holding commit information. // hook to the Woodpecker pipeline struct holding commit information.
func convertPullHook(from *internal.PullRequestHook) *model.Build { func convertPullHook(from *internal.PullRequestHook) *model.Pipeline {
return &model.Build{ return &model.Pipeline{
Event: model.EventPull, Event: model.EventPull,
Commit: from.PullRequest.Dest.Commit.Hash, Commit: from.PullRequest.Dest.Commit.Hash,
Ref: fmt.Sprintf("refs/heads/%s", from.PullRequest.Dest.Branch.Name), Ref: fmt.Sprintf("refs/heads/%s", from.PullRequest.Dest.Branch.Name),
@ -151,9 +152,9 @@ func convertPullHook(from *internal.PullRequestHook) *model.Build {
} }
// convertPushHook is a helper function used to convert a Bitbucket push // convertPushHook is a helper function used to convert a Bitbucket push
// hook to the Woodpecker build struct holding commit information. // hook to the Woodpecker pipeline struct holding commit information.
func convertPushHook(hook *internal.PushHook, change *internal.Change) *model.Build { func convertPushHook(hook *internal.PushHook, change *internal.Change) *model.Pipeline {
build := &model.Build{ pipeline := &model.Pipeline{
Commit: change.New.Target.Hash, Commit: change.New.Target.Hash,
Link: change.New.Target.Links.HTML.Href, Link: change.New.Target.Links.HTML.Href,
Branch: change.New.Name, Branch: change.New.Name,
@ -165,16 +166,16 @@ func convertPushHook(hook *internal.PushHook, change *internal.Change) *model.Bu
} }
switch change.New.Type { switch change.New.Type {
case "tag", "annotated_tag", "bookmark": case "tag", "annotated_tag", "bookmark":
build.Event = model.EventTag pipeline.Event = model.EventTag
build.Ref = fmt.Sprintf("refs/tags/%s", change.New.Name) pipeline.Ref = fmt.Sprintf("refs/tags/%s", change.New.Name)
default: default:
build.Event = model.EventPush pipeline.Event = model.EventPush
build.Ref = fmt.Sprintf("refs/heads/%s", change.New.Name) pipeline.Ref = fmt.Sprintf("refs/heads/%s", change.New.Name)
} }
if len(change.New.Target.Author.Raw) != 0 { if len(change.New.Target.Author.Raw) != 0 {
build.Email = extractEmail(change.New.Target.Author.Raw) pipeline.Email = extractEmail(change.New.Target.Author.Raw)
} }
return build return pipeline
} }
// regex for git author fields ("name <name@mail.tld>") // regex for git author fields ("name <name@mail.tld>")

View file

@ -1,3 +1,4 @@
// Copyright 2022 Woodpecker Authors
// Copyright 2018 Drone.IO Inc. // Copyright 2018 Drone.IO Inc.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
@ -114,7 +115,7 @@ func Test_helper(t *testing.T) {
g.Assert(link).Equal("https://bitbucket.org/foo/bar.git") g.Assert(link).Equal("https://bitbucket.org/foo/bar.git")
}) })
g.It("should convert pull hook to build", func() { g.It("should convert pull hook to pipeline", func() {
hook := &internal.PullRequestHook{} hook := &internal.PullRequestHook{}
hook.Actor.Login = "octocat" hook.Actor.Login = "octocat"
hook.Actor.Links.Avatar.Href = "https://..." hook.Actor.Links.Avatar.Href = "https://..."
@ -127,21 +128,21 @@ func Test_helper(t *testing.T) {
hook.PullRequest.Desc = "updated README" hook.PullRequest.Desc = "updated README"
hook.PullRequest.Updated = time.Now() hook.PullRequest.Updated = time.Now()
build := convertPullHook(hook) pipeline := convertPullHook(hook)
g.Assert(build.Event).Equal(model.EventPull) g.Assert(pipeline.Event).Equal(model.EventPull)
g.Assert(build.Author).Equal(hook.Actor.Login) g.Assert(pipeline.Author).Equal(hook.Actor.Login)
g.Assert(build.Avatar).Equal(hook.Actor.Links.Avatar.Href) g.Assert(pipeline.Avatar).Equal(hook.Actor.Links.Avatar.Href)
g.Assert(build.Commit).Equal(hook.PullRequest.Dest.Commit.Hash) g.Assert(pipeline.Commit).Equal(hook.PullRequest.Dest.Commit.Hash)
g.Assert(build.Branch).Equal(hook.PullRequest.Dest.Branch.Name) g.Assert(pipeline.Branch).Equal(hook.PullRequest.Dest.Branch.Name)
g.Assert(build.Link).Equal(hook.PullRequest.Links.HTML.Href) g.Assert(pipeline.Link).Equal(hook.PullRequest.Links.HTML.Href)
g.Assert(build.Ref).Equal("refs/heads/master") g.Assert(pipeline.Ref).Equal("refs/heads/master")
g.Assert(build.Refspec).Equal("change:master") g.Assert(pipeline.Refspec).Equal("change:master")
g.Assert(build.Remote).Equal("https://bitbucket.org/baz/bar") g.Assert(pipeline.Remote).Equal("https://bitbucket.org/baz/bar")
g.Assert(build.Message).Equal(hook.PullRequest.Desc) g.Assert(pipeline.Message).Equal(hook.PullRequest.Desc)
g.Assert(build.Timestamp).Equal(hook.PullRequest.Updated.Unix()) g.Assert(pipeline.Timestamp).Equal(hook.PullRequest.Updated.Unix())
}) })
g.It("should convert push hook to build", func() { g.It("should convert push hook to pipeline", func() {
change := internal.Change{} change := internal.Change{}
change.New.Target.Hash = "73f9c44d" change.New.Target.Hash = "73f9c44d"
change.New.Name = "master" change.New.Name = "master"
@ -154,29 +155,29 @@ func Test_helper(t *testing.T) {
hook.Actor.Login = "octocat" hook.Actor.Login = "octocat"
hook.Actor.Links.Avatar.Href = "https://..." hook.Actor.Links.Avatar.Href = "https://..."
build := convertPushHook(&hook, &change) pipeline := convertPushHook(&hook, &change)
g.Assert(build.Event).Equal(model.EventPush) g.Assert(pipeline.Event).Equal(model.EventPush)
g.Assert(build.Email).Equal("test@domain.tld") g.Assert(pipeline.Email).Equal("test@domain.tld")
g.Assert(build.Author).Equal(hook.Actor.Login) g.Assert(pipeline.Author).Equal(hook.Actor.Login)
g.Assert(build.Avatar).Equal(hook.Actor.Links.Avatar.Href) g.Assert(pipeline.Avatar).Equal(hook.Actor.Links.Avatar.Href)
g.Assert(build.Commit).Equal(change.New.Target.Hash) g.Assert(pipeline.Commit).Equal(change.New.Target.Hash)
g.Assert(build.Branch).Equal(change.New.Name) g.Assert(pipeline.Branch).Equal(change.New.Name)
g.Assert(build.Link).Equal(change.New.Target.Links.HTML.Href) g.Assert(pipeline.Link).Equal(change.New.Target.Links.HTML.Href)
g.Assert(build.Ref).Equal("refs/heads/master") g.Assert(pipeline.Ref).Equal("refs/heads/master")
g.Assert(build.Message).Equal(change.New.Target.Message) g.Assert(pipeline.Message).Equal(change.New.Target.Message)
g.Assert(build.Timestamp).Equal(change.New.Target.Date.Unix()) g.Assert(pipeline.Timestamp).Equal(change.New.Target.Date.Unix())
}) })
g.It("should convert tag hook to build", func() { g.It("should convert tag hook to pipeline", func() {
change := internal.Change{} change := internal.Change{}
change.New.Name = "v1.0.0" change.New.Name = "v1.0.0"
change.New.Type = "tag" change.New.Type = "tag"
hook := internal.PushHook{} hook := internal.PushHook{}
build := convertPushHook(&hook, &change) pipeline := convertPushHook(&hook, &change)
g.Assert(build.Event).Equal(model.EventTag) g.Assert(pipeline.Event).Equal(model.EventTag)
g.Assert(build.Ref).Equal("refs/tags/v1.0.0") g.Assert(pipeline.Ref).Equal("refs/tags/v1.0.0")
}) })
}) })
} }

View file

@ -155,7 +155,7 @@ func (c *Client) FindSource(owner, name, revision, path string) (*string, error)
return c.do(uri, get, nil, nil) return c.do(uri, get, nil, nil)
} }
func (c *Client) CreateStatus(owner, name, revision string, status *BuildStatus) error { func (c *Client) CreateStatus(owner, name, revision string, status *PipelineStatus) error {
uri := fmt.Sprintf(pathStatus, c.base, owner, name, revision) uri := fmt.Sprintf(pathStatus, c.base, owner, name, revision)
_, err := c.do(uri, post, status, nil) _, err := c.do(uri, post, status, nil)
return err return err

View file

@ -43,7 +43,7 @@ type WorkspacesResp struct {
Values []*Workspace `json:"values"` Values []*Workspace `json:"values"`
} }
type BuildStatus struct { type PipelineStatus struct {
State string `json:"state"` State string `json:"state"`
Key string `json:"key"` Key string `json:"key"`
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`

View file

@ -32,8 +32,8 @@ const (
) )
// parseHook parses a Bitbucket hook from an http.Request request and returns // parseHook parses a Bitbucket hook from an http.Request request and returns
// Repo and Build detail. If a hook type is unsupported nil values are returned. // Repo and Pipeline detail. If a hook type is unsupported nil values are returned.
func parseHook(r *http.Request) (*model.Repo, *model.Build, error) { func parseHook(r *http.Request) (*model.Repo, *model.Pipeline, error) {
payload, _ := io.ReadAll(r.Body) payload, _ := io.ReadAll(r.Body)
switch r.Header.Get(hookEvent) { switch r.Header.Get(hookEvent) {
@ -45,9 +45,9 @@ func parseHook(r *http.Request) (*model.Repo, *model.Build, error) {
return nil, nil, nil return nil, nil, nil
} }
// parsePushHook parses a push hook and returns the Repo and Build details. // parsePushHook parses a push hook and returns the Repo and Pipeline details.
// If the commit type is unsupported nil values are returned. // If the commit type is unsupported nil values are returned.
func parsePushHook(payload []byte) (*model.Repo, *model.Build, error) { func parsePushHook(payload []byte) (*model.Repo, *model.Pipeline, error) {
hook := internal.PushHook{} hook := internal.PushHook{}
err := json.Unmarshal(payload, &hook) err := json.Unmarshal(payload, &hook)
@ -64,9 +64,9 @@ func parsePushHook(payload []byte) (*model.Repo, *model.Build, error) {
return nil, nil, nil return nil, nil, nil
} }
// parsePullHook parses a pull request hook and returns the Repo and Build // parsePullHook parses a pull request hook and returns the Repo and Pipeline
// details. If the pull request is closed nil values are returned. // details. If the pull request is closed nil values are returned.
func parsePullHook(payload []byte) (*model.Repo, *model.Build, error) { func parsePullHook(payload []byte) (*model.Repo, *model.Pipeline, error) {
hook := internal.PullRequestHook{} hook := internal.PullRequestHook{}
if err := json.Unmarshal(payload, &hook); err != nil { if err := json.Unmarshal(payload, &hook); err != nil {

View file

@ -1,3 +1,4 @@
// Copyright 2022 Woodpecker Authors
// Copyright 2018 Drone.IO Inc. // Copyright 2018 Drone.IO Inc.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
@ -178,29 +179,29 @@ func (c *Config) Perm(ctx context.Context, u *model.User, repo *model.Repo) (*mo
return client.FindRepoPerms(repo.Owner, repo.Name) return client.FindRepoPerms(repo.Owner, repo.Name)
} }
func (c *Config) File(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, f string) ([]byte, error) { func (c *Config) File(ctx context.Context, u *model.User, r *model.Repo, p *model.Pipeline, f string) ([]byte, error) {
client := internal.NewClientWithToken(ctx, c.URL, c.Consumer, u.Token) client := internal.NewClientWithToken(ctx, c.URL, c.Consumer, u.Token)
return client.FindFileForRepo(r.Owner, r.Name, f, b.Ref) return client.FindFileForRepo(r.Owner, r.Name, f, p.Ref)
} }
func (c *Config) Dir(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, f string) ([]*remote.FileMeta, error) { func (c *Config) Dir(ctx context.Context, u *model.User, r *model.Repo, p *model.Pipeline, f string) ([]*remote.FileMeta, error) {
return nil, fmt.Errorf("Not implemented") return nil, fmt.Errorf("Not implemented")
} }
// Status is not supported by the bitbucketserver driver. // Status is not supported by the bitbucketserver driver.
func (c *Config) Status(ctx context.Context, user *model.User, repo *model.Repo, build *model.Build, proc *model.Proc) error { func (c *Config) Status(ctx context.Context, user *model.User, repo *model.Repo, pipeline *model.Pipeline, proc *model.Proc) error {
status := internal.BuildStatus{ status := internal.PipelineStatus{
State: convertStatus(build.Status), State: convertStatus(pipeline.Status),
Desc: common.GetBuildStatusDescription(build.Status), Desc: common.GetPipelineStatusDescription(pipeline.Status),
Name: fmt.Sprintf("Woodpecker #%d - %s", build.Number, build.Branch), Name: fmt.Sprintf("Woodpecker #%d - %s", pipeline.Number, pipeline.Branch),
Key: "Woodpecker", Key: "Woodpecker",
URL: common.GetBuildStatusLink(repo, build, nil), URL: common.GetPipelineStatusLink(repo, pipeline, nil),
} }
client := internal.NewClientWithToken(ctx, c.URL, c.Consumer, user.Token) client := internal.NewClientWithToken(ctx, c.URL, c.Consumer, user.Token)
return client.CreateStatus(build.Commit, &status) return client.CreateStatus(pipeline.Commit, &status)
} }
func (c *Config) Netrc(user *model.User, r *model.Repo) (*model.Netrc, error) { func (c *Config) Netrc(user *model.User, r *model.Repo) (*model.Netrc, error) {
@ -247,7 +248,7 @@ func (c *Config) Deactivate(ctx context.Context, u *model.User, r *model.Repo, l
return client.DeleteHook(r.Owner, r.Name, link) return client.DeleteHook(r.Owner, r.Name, link)
} }
func (c *Config) Hook(ctx context.Context, r *http.Request) (*model.Repo, *model.Build, error) { func (c *Config) Hook(ctx context.Context, r *http.Request) (*model.Repo, *model.Pipeline, error) {
return parseHook(r, c.URL) return parseHook(r, c.URL)
} }

View file

@ -1,3 +1,4 @@
// Copyright 2022 Woodpecker Authors
// Copyright 2018 Drone.IO Inc. // Copyright 2018 Drone.IO Inc.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
@ -79,8 +80,8 @@ func convertRepo(from *internal.Repo) *model.Repo {
} }
// convertPushHook is a helper function used to convert a Bitbucket push // convertPushHook is a helper function used to convert a Bitbucket push
// hook to the Woodpecker build struct holding commit information. // hook to the Woodpecker pipeline struct holding commit information.
func convertPushHook(hook *internal.PostHook, baseURL string) *model.Build { func convertPushHook(hook *internal.PostHook, baseURL string) *model.Pipeline {
branch := strings.TrimPrefix( branch := strings.TrimPrefix(
strings.TrimPrefix( strings.TrimPrefix(
hook.RefChanges[0].RefID, hook.RefChanges[0].RefID,
@ -95,7 +96,7 @@ func convertPushHook(hook *internal.PostHook, baseURL string) *model.Build {
authorLabel = authorLabel[0:37] + "..." authorLabel = authorLabel[0:37] + "..."
} }
build := &model.Build{ pipeline := &model.Pipeline{
Commit: hook.RefChanges[0].ToHash, // TODO check for index value Commit: hook.RefChanges[0].ToHash, // TODO check for index value
Branch: branch, Branch: branch,
Message: hook.Changesets.Values[0].ToCommit.Message, // TODO check for index Values Message: hook.Changesets.Values[0].ToCommit.Message, // TODO check for index Values
@ -107,12 +108,12 @@ func convertPushHook(hook *internal.PostHook, baseURL string) *model.Build {
Link: fmt.Sprintf("%s/projects/%s/repos/%s/commits/%s", baseURL, hook.Repository.Project.Key, hook.Repository.Slug, hook.RefChanges[0].ToHash), Link: fmt.Sprintf("%s/projects/%s/repos/%s/commits/%s", baseURL, hook.Repository.Project.Key, hook.Repository.Slug, hook.RefChanges[0].ToHash),
} }
if strings.HasPrefix(hook.RefChanges[0].RefID, "refs/tags/") { if strings.HasPrefix(hook.RefChanges[0].RefID, "refs/tags/") {
build.Event = model.EventTag pipeline.Event = model.EventTag
} else { } else {
build.Event = model.EventPush pipeline.Event = model.EventPush
} }
return build return pipeline
} }
// convertUser is a helper function used to convert a Bitbucket user account // convertUser is a helper function used to convert a Bitbucket user account

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