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.
//
// Licensed under the Apache License, Version 2.0 (the "License");
@ -80,20 +81,20 @@ func (r *Runner) Run(ctx context.Context) error {
timeout = time.Duration(minutes) * time.Minute
}
repoName := extractRepositoryName(work.Config) // hack
buildNumber := extractBuildNumber(work.Config) // hack
repoName := extractRepositoryName(work.Config) // hack
pipelineNumber := extractPipelineNumber(work.Config) // hack
r.counter.Add(
work.ID,
timeout,
repoName,
buildNumber,
pipelineNumber,
)
defer r.counter.Done(work.ID)
logger := log.With().
Str("repo", repoName).
Str("build", buildNumber).
Str("pipeline", pipelineNumber).
Str("id", work.ID).
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
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_STARTED"] = strconv.FormatInt(state.Pipeline.Time, 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
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_JOB_STATUS"] = "failure"
}
@ -311,9 +318,9 @@ func (r *Runner) Run(ctx context.Context) error {
pipeline.WithTracer(defaultTracer),
pipeline.WithEngine(*r.engine),
pipeline.WithDescription(map[string]string{
"ID": work.ID,
"Repo": repoName,
"Build": buildNumber,
"ID": work.ID,
"Repo": repoName,
"Pipeline": pipelineNumber,
}),
).Run()
@ -363,7 +370,7 @@ func extractRepositoryName(config *backend.Config) string {
return config.Stages[0].Steps[0].Environment["CI_REPO"]
}
// extract build number from the configuration
func extractBuildNumber(config *backend.Config) string {
return config.Stages[0].Steps[0].Environment["CI_BUILD_NUMBER"]
// extract pipeline number from the configuration
func extractPipelineNumber(config *backend.Config) string {
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.
//
// Licensed under the Apache License, Version 2.0 (the "License");
@ -29,23 +30,23 @@ type State struct {
}
type Info struct {
ID string `json:"id"`
Repo string `json:"repository"`
Build string `json:"build_number"`
Started time.Time `json:"build_started"`
Timeout time.Duration `json:"build_timeout"`
ID string `json:"id"`
Repo string `json:"repository"`
Pipeline string `json:"build_number"`
Started time.Time `json:"build_started"`
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.Polling--
s.Running++
s.Metadata[id] = Info{
ID: id,
Repo: repo,
Build: build,
Timeout: timeout,
Started: time.Now().UTC(),
ID: id,
Repo: repo,
Pipeline: pipeline,
Timeout: timeout,
Started: time.Now().UTC(),
}
s.Unlock()
}

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
import (
@ -53,7 +67,7 @@ func cronList(c *cli.Context) error {
return nil
}
// template for build list information
// template for pipeline list information
var tmplCronList = "\x1b[33m{{ .Name }} \x1b[0m" + `
ID: {{ .ID }}
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
import (
@ -17,7 +31,7 @@ import (
var Command = &cli.Command{
Name: "deploy",
Usage: "deploy code",
ArgsUsage: "<repo/name> <build> <environment>",
ArgsUsage: "<repo/name> <pipeline> <environment>",
Action: deploy,
Flags: append(common.GlobalFlags,
common.FormatFlag(tmplDeployInfo),
@ -60,33 +74,33 @@ func deploy(c *cli.Context) error {
event := c.String("event")
status := c.String("status")
buildArg := c.Args().Get(1)
pipelineArg := c.Args().Get(1)
var number int
if buildArg == "last" {
// Fetch the build number from the last build
builds, berr := client.BuildList(owner, name)
if pipelineArg == "last" {
// Fetch the pipeline number from the last pipeline
pipelines, berr := client.PipelineList(owner, name)
if berr != nil {
return berr
}
for _, build := range builds {
if branch != "" && build.Branch != branch {
for _, pipeline := range pipelines {
if branch != "" && pipeline.Branch != branch {
continue
}
if event != "" && build.Event != event {
if event != "" && pipeline.Event != event {
continue
}
if status != "" && build.Status != status {
if status != "" && pipeline.Status != status {
continue
}
if build.Number > number {
number = build.Number
if pipeline.Number > number {
number = pipeline.Number
}
}
if number == 0 {
return fmt.Errorf("Cannot deploy failure build")
return fmt.Errorf("Cannot deploy failure pipeline")
}
} else {
number, err = strconv.Atoi(buildArg)
number, err = strconv.Atoi(pipelineArg)
if err != nil {
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
import (
@ -30,7 +44,7 @@ import (
// Command exports the exec command.
var Command = &cli.Command{
Name: "exec",
Usage: "execute a local build",
Usage: "execute a local pipeline",
ArgsUsage: "[path/to/.woodpecker.yml]",
Action: run,
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"),
Private: c.Bool("repo-private"),
},
Curr: frontend.Build{
Number: c.Int64("build-number"),
Parent: c.Int64("parent-build-number"),
Created: c.Int64("build-created"),
Started: c.Int64("build-started"),
Finished: c.Int64("build-finished"),
Status: c.String("build-status"),
Event: c.String("build-event"),
Link: c.String("build-link"),
Target: c.String("build-target"),
Curr: frontend.Pipeline{
Number: c.Int64("pipeline-number"),
Parent: c.Int64("pipeline-parent"),
Created: c.Int64("pipeline-created"),
Started: c.Int64("pipeline-started"),
Finished: c.Int64("pipeline-finished"),
Status: c.String("pipeline-status"),
Event: c.String("pipeline-event"),
Link: c.String("pipeline-link"),
Target: c.String("pipeline-target"),
Commit: frontend.Commit{
Sha: c.String("commit-sha"),
Ref: c.String("commit-ref"),
@ -254,14 +268,14 @@ func metadataFromContext(c *cli.Context, axis matrix.Axis) frontend.Metadata {
},
},
},
Prev: frontend.Build{
Number: c.Int64("prev-build-number"),
Created: c.Int64("prev-build-created"),
Started: c.Int64("prev-build-started"),
Finished: c.Int64("prev-build-finished"),
Status: c.String("prev-build-status"),
Event: c.String("prev-build-event"),
Link: c.String("prev-build-link"),
Prev: frontend.Pipeline{
Number: c.Int64("prev-pipeline-number"),
Created: c.Int64("prev-pipeline-created"),
Started: c.Int64("prev-pipeline-started"),
Finished: c.Int64("prev-pipeline-finished"),
Status: c.String("prev-pipeline-status"),
Event: c.String("prev-pipeline-event"),
Link: c.String("prev-pipeline-link"),
Commit: frontend.Commit{
Sha: c.String("prev-commit-sha"),
Ref: c.String("prev-commit-ref"),

View file

@ -26,19 +26,19 @@ var flags = []cli.Flag{
&cli.BoolFlag{
EnvVars: []string{"WOODPECKER_LOCAL"},
Name: "local",
Usage: "build from local directory",
Usage: "run from local directory",
Value: true,
},
&cli.DurationFlag{
EnvVars: []string{"WOODPECKER_TIMEOUT"},
Name: "timeout",
Usage: "build timeout",
Usage: "pipeline timeout",
Value: time.Hour,
},
&cli.StringSliceFlag{
EnvVars: []string{"WOODPECKER_VOLUMES"},
Name: "volumes",
Usage: "build volumes",
Usage: "pipeline volumes",
},
&cli.StringSliceFlag{
EnvVars: []string{"WOODPECKER_NETWORKS"},
@ -131,41 +131,41 @@ var flags = []cli.Flag{
Name: "repo-private",
},
&cli.IntFlag{
EnvVars: []string{"CI_BUILD_NUMBER"},
Name: "build-number",
EnvVars: []string{"CI_PIPELINE_NUMBER"},
Name: "pipeline-number",
},
&cli.IntFlag{
EnvVars: []string{"CI_PARENT_BUILD_NUMBER"},
Name: "parent-build-number",
EnvVars: []string{"CI_PIPELINE_PARENT"},
Name: "pipeline-parent",
},
&cli.Int64Flag{
EnvVars: []string{"CI_BUILD_CREATED"},
Name: "build-created",
EnvVars: []string{"CI_PIPELINE_CREATED"},
Name: "pipeline-created",
},
&cli.Int64Flag{
EnvVars: []string{"CI_BUILD_STARTED"},
Name: "build-started",
EnvVars: []string{"CI_PIPELINE_STARTED"},
Name: "pipeline-started",
},
&cli.Int64Flag{
EnvVars: []string{"CI_BUILD_FINISHED"},
Name: "build-finished",
EnvVars: []string{"CI_PIPELINE_FINISHED"},
Name: "pipeline-finished",
},
&cli.StringFlag{
EnvVars: []string{"CI_BUILD_STATUS"},
Name: "build-status",
EnvVars: []string{"CI_PIPELINE_STATUS"},
Name: "pipeline-status",
},
&cli.StringFlag{
EnvVars: []string{"CI_BUILD_EVENT"},
Name: "build-event",
EnvVars: []string{"CI_PIPELINE_EVENT"},
Name: "pipeline-event",
Value: "manual",
},
&cli.StringFlag{
EnvVars: []string{"CI_BUILD_LINK"},
Name: "build-link",
EnvVars: []string{"CI_PIPELINE_LINK"},
Name: "pipeline-link",
},
&cli.StringFlag{
EnvVars: []string{"CI_BUILD_TARGET"},
Name: "build-target",
EnvVars: []string{"CI_PIPELINE_TARGET"},
Name: "pipeline-target",
},
&cli.StringFlag{
EnvVars: []string{"CI_COMMIT_SHA"},
@ -200,32 +200,32 @@ var flags = []cli.Flag{
Name: "commit-author-email",
},
&cli.IntFlag{
EnvVars: []string{"CI_PREV_BUILD_NUMBER"},
Name: "prev-build-number",
EnvVars: []string{"CI_PREV_PIPELINE_NUMBER"},
Name: "prev-pipeline-number",
},
&cli.Int64Flag{
EnvVars: []string{"CI_PREV_BUILD_CREATED"},
Name: "prev-build-created",
EnvVars: []string{"CI_PREV_PIPELINE_CREATED"},
Name: "prev-pipeline-created",
},
&cli.Int64Flag{
EnvVars: []string{"CI_PREV_BUILD_STARTED"},
Name: "prev-build-started",
EnvVars: []string{"CI_PREV_PIPELINE_STARTED"},
Name: "prev-pipeline-started",
},
&cli.Int64Flag{
EnvVars: []string{"CI_PREV_BUILD_FINISHED"},
Name: "prev-build-finished",
EnvVars: []string{"CI_PREV_PIPELINE_FINISHED"},
Name: "prev-pipeline-finished",
},
&cli.StringFlag{
EnvVars: []string{"CI_PREV_BUILD_STATUS"},
Name: "prev-build-status",
EnvVars: []string{"CI_PREV_PIPELINE_STATUS"},
Name: "prev-pipeline-status",
},
&cli.StringFlag{
EnvVars: []string{"CI_PREV_BUILD_EVENT"},
Name: "prev-build-event",
EnvVars: []string{"CI_PREV_PIPELINE_EVENT"},
Name: "prev-pipeline-event",
},
&cli.StringFlag{
EnvVars: []string{"CI_PREV_BUILD_LINK"},
Name: "prev-build-link",
EnvVars: []string{"CI_PREV_PIPELINE_LINK"},
Name: "prev-pipeline-link",
},
&cli.StringFlag{
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
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
import (
@ -6,7 +20,7 @@ import (
"github.com/woodpecker-ci/woodpecker/cli/common"
)
// Command exports the build command set.
// Command exports the log command set.
var Command = &cli.Command{
Name: "log",
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
import (
@ -13,7 +27,7 @@ import (
var logPurgeCmd = &cli.Command{
Name: "purge",
Usage: "purge a log",
ArgsUsage: "<repo/name> <build>",
ArgsUsage: "<repo/name> <pipeline>",
Action: logPurge,
Flags: common.GlobalFlags,
}
@ -39,6 +53,6 @@ func logPurge(c *cli.Context) (err error) {
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
}

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 (
"os"
@ -13,16 +27,16 @@ import (
"github.com/woodpecker-ci/woodpecker/cli/internal"
)
var buildCreateCmd = &cli.Command{
var pipelineCreateCmd = &cli.Command{
Name: "create",
Usage: "create new build",
Usage: "create new pipeline",
ArgsUsage: "<repo/name>",
Action: buildCreate,
Action: pipelineCreate,
Flags: append(common.GlobalFlags,
common.FormatFlag(tmplBuildList),
common.FormatFlag(tmplPipelineList),
&cli.StringFlag{
Name: "branch",
Usage: "branch to create build from",
Usage: "branch to create pipeline from",
Required: true,
},
&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()
owner, name, err := internal.ParseRepo(repo)
@ -55,12 +69,12 @@ func buildCreate(c *cli.Context) error {
}
}
options := &woodpecker.BuildOptions{
options := &woodpecker.PipelineOptions{
Branch: branch,
Variables: variables,
}
build, err := client.BuildCreate(owner, name, options)
pipeline, err := client.PipelineCreate(owner, name, options)
if err != nil {
return err
}
@ -70,7 +84,7 @@ func buildCreate(c *cli.Context) error {
return err
}
if err := tmpl.Execute(os.Stdout, build); err != nil {
if err := tmpl.Execute(os.Stdout, pipeline); err != nil {
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 (
"os"
@ -10,13 +24,13 @@ import (
"github.com/woodpecker-ci/woodpecker/cli/internal"
)
var buildListCmd = &cli.Command{
var pipelineListCmd = &cli.Command{
Name: "ls",
Usage: "show build history",
Usage: "show pipeline history",
ArgsUsage: "<repo/name>",
Action: buildList,
Action: pipelineList,
Flags: append(common.GlobalFlags,
common.FormatFlag(tmplBuildList),
common.FormatFlag(tmplPipelineList),
&cli.StringFlag{
Name: "branch",
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()
owner, name, err := internal.ParseRepo(repo)
if err != nil {
@ -49,7 +63,7 @@ func buildList(c *cli.Context) error {
return err
}
builds, err := client.BuildList(owner, name)
pipelines, err := client.PipelineList(owner, name)
if err != nil {
return err
}
@ -65,20 +79,20 @@ func buildList(c *cli.Context) error {
limit := c.Int("limit")
var count int
for _, build := range builds {
for _, pipeline := range pipelines {
if count >= limit {
break
}
if branch != "" && build.Branch != branch {
if branch != "" && pipeline.Branch != branch {
continue
}
if event != "" && build.Event != event {
if event != "" && pipeline.Event != event {
continue
}
if status != "" && build.Status != status {
if status != "" && pipeline.Status != status {
continue
}
if err := tmpl.Execute(os.Stdout, build); err != nil {
if err := tmpl.Execute(os.Stdout, pipeline); err != nil {
return err
}
count++
@ -86,8 +100,8 @@ func buildList(c *cli.Context) error {
return nil
}
// template for build list information
var tmplBuildList = "\x1b[33mBuild #{{ .Number }} \x1b[0m" + `
// template for pipeline list information
var tmplPipelineList = "\x1b[33mBuild #{{ .Number }} \x1b[0m" + `
Status: {{ .Status }}
Event: {{ .Event }}
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
import (
@ -53,7 +67,7 @@ func registryList(c *cli.Context) error {
return nil
}
// template for build list information
// template for registry list information
var tmplRegistryList = "\x1b[33m{{ .Address }} \x1b[0m" + `
Username: {{ .Username }}
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
import (
@ -38,12 +52,12 @@ var repoUpdateCmd = &cli.Command{
Usage: "repository configuration path (e.g. .woodpecker.yml)",
},
&cli.IntFlag{
Name: "build-counter",
Usage: "repository starting build number",
Name: "pipeline-counter",
Usage: "repository starting pipeline number",
},
&cli.BoolFlag{
Name: "unsafe",
Usage: "validate updating the build-counter is unsafe",
Usage: "validate updating the pipeline-counter is unsafe",
},
),
}
@ -61,13 +75,13 @@ func repoUpdate(c *cli.Context) error {
}
var (
visibility = c.String("visibility")
config = c.String("config")
timeout = c.Duration("timeout")
trusted = c.Bool("trusted")
gated = c.Bool("gated")
buildCounter = c.Int("build-counter")
unsafe = c.Bool("unsafe")
visibility = c.String("visibility")
config = c.String("config")
timeout = c.Duration("timeout")
trusted = c.Bool("trusted")
gated = c.Bool("gated")
pipelineCounter = c.Int("pipeline-counter")
unsafe = c.Bool("unsafe")
)
patch := new(woodpecker.RepoPatch)
@ -90,11 +104,11 @@ func repoUpdate(c *cli.Context) error {
patch.Visibility = &visibility
}
}
if c.IsSet("build-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")
if c.IsSet("pipeline-counter") && !unsafe {
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 {
patch.BuildCounter = &buildCounter
if c.IsSet("pipeline-counter") && unsafe {
patch.PipelineCounter = &pipelineCounter
}
if _, err := client.RepoPatch(owner, name, patch); err != nil {

View file

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

View file

@ -21,7 +21,6 @@ import (
zlog "github.com/rs/zerolog/log"
"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/cron"
"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/log"
"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/repo"
"github.com/woodpecker-ci/woodpecker/cli/secret"
@ -46,7 +46,7 @@ func newApp() *cli.App {
app.EnableBashCompletion = true
app.Flags = common.GlobalFlags
app.Commands = []*cli.Command{
build.Command,
pipeline.Command,
log.Command,
deploy.Command,
exec.Command,

View file

@ -1,3 +1,4 @@
// Copyright 2022 Woodpecker Authors
// Copyright 2018 Drone.IO Inc.
//
// 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") {
log.Debug().Msgf("server has sqlite3 support")
} 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{
Namespace: "woodpecker",
Name: "pending_jobs",
Help: "Total number of pending build processes.",
Help: "Total number of pending pipeline processes.",
})
waitingJobs := promauto.NewGauge(prometheus.GaugeOpts{
Namespace: "woodpecker",
Name: "waiting_jobs",
Help: "Total number of builds waiting on deps.",
Help: "Total number of pipeline waiting on deps.",
})
runningJobs := promauto.NewGauge(prometheus.GaugeOpts{
Namespace: "woodpecker",
Name: "running_jobs",
Help: "Total number of running build processes.",
Help: "Total number of running pipeline processes.",
})
workers := promauto.NewGauge(prometheus.GaugeOpts{
Namespace: "woodpecker",
Name: "worker_count",
Help: "Total number of workers.",
})
builds := promauto.NewGauge(prometheus.GaugeOpts{
pipelines := promauto.NewGauge(prometheus.GaugeOpts{
Namespace: "woodpecker",
Name: "build_total_count",
Help: "Total number of builds.",
Name: "pipeline_total_count",
Help: "Total number of pipelines.",
})
users := promauto.NewGauge(prometheus.GaugeOpts{
Namespace: "woodpecker",
@ -353,8 +354,8 @@ func setupMetrics(g *errgroup.Group, _store store.Store) {
for {
repoCount, _ := _store.GetRepoCount()
userCount, _ := _store.GetUserCount()
buildCount, _ := _store.GetBuildCount()
builds.Set(float64(buildCount))
pipelineCount, _ := _store.GetPipelineCount()
pipelines.Set(float64(pipelineCount))
users.Set(float64(userCount))
repos.Set(float64(repoCount))
time.Sleep(10 * time.Second)

View file

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

View file

@ -46,86 +46,86 @@ 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.
| NAME | Description |
|--------------------------------|----------------------------------------------------------------------------------------------|
| `CI=woodpecker` | environment is woodpecker |
| | **Repository** |
| `CI_REPO` | repository full name `<owner>/<name>` |
| `CI_REPO_OWNER` | repository owner |
| `CI_REPO_NAME` | repository name |
| `CI_REPO_SCM` | repository SCM (git) |
| `CI_REPO_LINK` | repository link |
| `CI_REPO_REMOTE` | repository clone URL |
| `CI_REPO_DEFAULT_BRANCH` | repository default branch (master) |
| `CI_REPO_PRIVATE` | repository is private |
| `CI_REPO_TRUSTED` | repository is trusted |
| | **Current Commit** |
| `CI_COMMIT_SHA` | commit SHA |
| `CI_COMMIT_REF` | commit ref |
| `CI_COMMIT_REFSPEC` | commit ref spec |
| `CI_COMMIT_BRANCH` | commit branch (equals target branch for pull requests) |
| `CI_COMMIT_SOURCE_BRANCH` | commit source branch |
| `CI_COMMIT_TARGET_BRANCH` | commit target branch |
| `CI_COMMIT_TAG` | commit tag name (empty if event is not `tag`) |
| `CI_COMMIT_PULL_REQUEST` | commit pull request number (empty if event is not `pull_request`) |
| `CI_COMMIT_LINK` | commit link in remote |
| `CI_COMMIT_MESSAGE` | commit message |
| `CI_COMMIT_AUTHOR` | commit author username |
| `CI_COMMIT_AUTHOR_EMAIL` | commit author email address |
| `CI_COMMIT_AUTHOR_AVATAR` | commit author avatar |
| | **Current build** |
| `CI_BUILD_NUMBER` | build number |
| `CI_BUILD_PARENT` | build number of parent build |
| `CI_BUILD_EVENT` | build event (push, pull_request, tag, deployment) |
| `CI_BUILD_LINK` | build link in CI |
| `CI_BUILD_DEPLOY_TARGET` | build deploy target for `deployment` events (i.e. production) |
| `CI_BUILD_STATUS` | build status (success, failure) |
| `CI_BUILD_CREATED` | build created UNIX timestamp |
| `CI_BUILD_STARTED` | build started UNIX timestamp |
| `CI_BUILD_FINISHED` | build finished UNIX timestamp |
| | **Current job** |
| `CI_JOB_NUMBER` | job number |
| `CI_JOB_STATUS` | job status (success, failure) |
| `CI_JOB_STARTED` | job started UNIX timestamp |
| `CI_JOB_FINISHED` | job finished UNIX timestamp |
| | **Previous commit** |
| `CI_PREV_COMMIT_SHA` | previous commit SHA |
| `CI_PREV_COMMIT_REF` | previous commit ref |
| `CI_PREV_COMMIT_REFSPEC` | previous commit ref spec |
| `CI_PREV_COMMIT_BRANCH` | previous commit branch |
| `CI_PREV_COMMIT_SOURCE_BRANCH` | previous commit source branch |
| `CI_PREV_COMMIT_TARGET_BRANCH` | previous commit target branch |
| `CI_PREV_COMMIT_LINK` | previous commit link in remote |
| `CI_PREV_COMMIT_MESSAGE` | previous commit message |
| `CI_PREV_COMMIT_AUTHOR` | previous commit author username |
| `CI_PREV_COMMIT_AUTHOR_EMAIL` | previous commit author email address |
| `CI_PREV_COMMIT_AUTHOR_AVATAR` | previous commit author avatar |
| | **Previous build** |
| `CI_PREV_BUILD_NUMBER` | previous build number |
| `CI_PREV_BUILD_PARENT` | previous build number of parent build |
| `CI_PREV_BUILD_EVENT` | previous build event (push, pull_request, tag, deployment) |
| `CI_PREV_BUILD_LINK` | previous build link in CI |
| `CI_PREV_BUILD_DEPLOY_TARGET` | previous build deploy target for `deployment` events (i.e. production) |
| `CI_PREV_BUILD_STATUS` | previous build status (success, failure) |
| `CI_PREV_BUILD_CREATED` | previous build created UNIX timestamp |
| `CI_PREV_BUILD_STARTED` | previous build started UNIX timestamp |
| `CI_PREV_BUILD_FINISHED` | previous build finished UNIX timestamp |
| | &emsp; |
| `CI_WORKSPACE` | Path of the workspace where source code gets cloned to |
| | **System** |
| `CI_SYSTEM_NAME` | name of the CI system: `woodpecker` |
| `CI_SYSTEM_LINK` | link to CI system |
| `CI_SYSTEM_HOST` | hostname of CI server |
| `CI_SYSTEM_VERSION` | version of the server |
| | **Internal** - Please don't use! |
| `CI_SCRIPT` | Internal script path. Used to call pipeline step commands. |
| `CI_NETRC_USERNAME` | Credentials for private repos to be able to clone data. (Only available for specific images) |
| `CI_NETRC_PASSWORD` | Credentials for private repos to be able to clone data. (Only available for specific images) |
| `CI_NETRC_MACHINE` | Credentials for private repos to be able to clone data. (Only available for specific images) |
| NAME | Description |
|----------------------------------|----------------------------------------------------------------------------------------------|
| `CI=woodpecker` | environment is woodpecker |
| | **Repository** |
| `CI_REPO` | repository full name `<owner>/<name>` |
| `CI_REPO_OWNER` | repository owner |
| `CI_REPO_NAME` | repository name |
| `CI_REPO_SCM` | repository SCM (git) |
| `CI_REPO_LINK` | repository link |
| `CI_REPO_REMOTE` | repository clone URL |
| `CI_REPO_DEFAULT_BRANCH` | repository default branch (master) |
| `CI_REPO_PRIVATE` | repository is private |
| `CI_REPO_TRUSTED` | repository is trusted |
| | **Current Commit** |
| `CI_COMMIT_SHA` | commit SHA |
| `CI_COMMIT_REF` | commit ref |
| `CI_COMMIT_REFSPEC` | commit ref spec |
| `CI_COMMIT_BRANCH` | commit branch (equals target branch for pull requests) |
| `CI_COMMIT_SOURCE_BRANCH` | commit source branch |
| `CI_COMMIT_TARGET_BRANCH` | commit target branch |
| `CI_COMMIT_TAG` | commit tag name (empty if event is not `tag`) |
| `CI_COMMIT_PULL_REQUEST` | commit pull request number (empty if event is not `pull_request`) |
| `CI_COMMIT_LINK` | commit link in remote |
| `CI_COMMIT_MESSAGE` | commit message |
| `CI_COMMIT_AUTHOR` | commit author username |
| `CI_COMMIT_AUTHOR_EMAIL` | commit author email address |
| `CI_COMMIT_AUTHOR_AVATAR` | commit author avatar |
| | **Current pipeline** |
| `CI_PIPELINE_NUMBER` | pipeline number |
| `CI_PIPELINE_PARENT` | number of parent pipeline |
| `CI_PIPELINE_EVENT` | pipeline event (push, pull_request, tag, deployment) |
| `CI_PIPELINE_LINK` | pipeline link in CI |
| `CI_PIPELINE_DEPLOY_TARGET` | pipeline deploy target for `deployment` events (ie production) |
| `CI_PIPELINE_STATUS` | pipeline status (success, failure) |
| `CI_PIPELINE_CREATED` | pipeline created UNIX timestamp |
| `CI_PIPELINE_STARTED` | pipeline started UNIX timestamp |
| `CI_PIPELINE_FINISHED` | pipeline finished UNIX timestamp |
| | **Current job** |
| `CI_JOB_NUMBER` | job number |
| `CI_JOB_STATUS` | job status (success, failure) |
| `CI_JOB_STARTED` | job started UNIX timestamp |
| `CI_JOB_FINISHED` | job finished UNIX timestamp |
| | **Previous commit** |
| `CI_PREV_COMMIT_SHA` | previous commit SHA |
| `CI_PREV_COMMIT_REF` | previous commit ref |
| `CI_PREV_COMMIT_REFSPEC` | previous commit ref spec |
| `CI_PREV_COMMIT_BRANCH` | previous commit branch |
| `CI_PREV_COMMIT_SOURCE_BRANCH` | previous commit source branch |
| `CI_PREV_COMMIT_TARGET_BRANCH` | previous commit target branch |
| `CI_PREV_COMMIT_LINK` | previous commit link in remote |
| `CI_PREV_COMMIT_MESSAGE` | previous commit message |
| `CI_PREV_COMMIT_AUTHOR` | previous commit author username |
| `CI_PREV_COMMIT_AUTHOR_EMAIL` | previous commit author email address |
| `CI_PREV_COMMIT_AUTHOR_AVATAR` | previous commit author avatar |
| | **Previous pipeline** |
| `CI_PREV_PIPELINE_NUMBER` | previous pipeline number |
| `CI_PREV_PIPELINE_PARENT` | previous pipeline number of parent pipeline |
| `CI_PREV_PIPELINE_EVENT` | previous pipeline event (push, pull_request, tag, deployment) |
| `CI_PREV_PIPELINE_LINK` | previous pipeline link in CI |
| `CI_PREV_PIPELINE_DEPLOY_TARGET` | previous pipeline deploy target for `deployment` events (ie production) |
| `CI_PREV_PIPELINE_STATUS` | previous pipeline status (success, failure) |
| `CI_PREV_PIPELINE_CREATED` | previous pipeline created UNIX timestamp |
| `CI_PREV_PIPELINE_STARTED` | previous pipeline started UNIX timestamp |
| `CI_PREV_PIPELINE_FINISHED` | previous pipeline finished UNIX timestamp |
| | &emsp; |
| `CI_WORKSPACE` | Path of the workspace where source code gets cloned to |
| | **System** |
| `CI_SYSTEM_NAME` | name of the CI system: `woodpecker` |
| `CI_SYSTEM_LINK` | link to CI system |
| `CI_SYSTEM_HOST` | hostname of CI server |
| `CI_SYSTEM_VERSION` | version of the server |
| | **Internal** - Please don't use! |
| `CI_SCRIPT` | Internal script path. Used to call pipeline step commands. |
| `CI_NETRC_USERNAME` | Credentials for private repos to be able to clone data. (Only available for specific images) |
| `CI_NETRC_PASSWORD` | Credentials for private repos to be able to clone data. (Only available for specific images) |
| `CI_NETRC_MACHINE` | Credentials for private repos to be able to clone data. (Only available for specific images) |
## 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
services:
@ -152,7 +152,7 @@ pipeline:
## 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:

View file

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

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.
- Refactored support of old agent filter labels and expression. Learn how to use the new [filter](./20-usage/20-pipeline-syntax.md#labels)
- Renamed step environment variable `CI_SYSTEM_ARCH` to `CI_SYSTEM_PLATFORM`. Same applies for the cli exec variable.
- Renamed environment variables `CI_BUILD_*` and `CI_PREV_BUILD_*` to `CI_PIPELINE_*` and `CI_PREV_PIPELINE_*`, old ones are still available but deprecated
- Renamed 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

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
import (
@ -99,7 +113,7 @@ func (e *local) Wait(context.Context, *types.Step) (*types.State, error) {
ExitCode := 0
if eerr, ok := err.(*exec.ExitError); ok {
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
}
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_SOURCE_BRANCH"] = env["CI_COMMIT_SOURCE_BRANCH"]
env["DRONE_TARGET_BRANCH"] = env["CI_COMMIT_TARGET_BRANCH"]
// build
env["DRONE_BUILD_NUMBER"] = env["CI_BUILD_NUMBER"]
env["DRONE_BUILD_PARENT"] = env["CI_BUILD_PARENT"]
env["DRONE_BUILD_EVENT"] = env["CI_BUILD_EVENT"]
env["DRONE_BUILD_STATUS"] = env["CI_BUILD_STATUS"]
env["DRONE_BUILD_LINK"] = env["CI_BUILD_LINK"]
env["DRONE_BUILD_CREATED"] = env["CI_BUILD_CREATED"]
env["DRONE_BUILD_STARTED"] = env["CI_BUILD_STARTED"]
env["DRONE_BUILD_FINISHED"] = env["CI_BUILD_FINISHED"]
// pipeline
env["DRONE_BUILD_NUMBER"] = env["CI_PIPELINE_NUMBER"]
env["DRONE_BUILD_PARENT"] = env["CI_PIPELINE_PARENT"]
env["DRONE_BUILD_EVENT"] = env["CI_PIPELINE_EVENT"]
env["DRONE_BUILD_STATUS"] = env["CI_PIPELINE_STATUS"]
env["DRONE_BUILD_LINK"] = env["CI_PIPELINE_LINK"]
env["DRONE_BUILD_CREATED"] = env["CI_PIPELINE_CREATED"]
env["DRONE_BUILD_STARTED"] = env["CI_PIPELINE_STARTED"]
env["DRONE_BUILD_FINISHED"] = env["CI_PIPELINE_FINISHED"]
// commit
env["DRONE_COMMIT"] = env["CI_COMMIT_SHA"]
env["DRONE_COMMIT_BEFORE"] = env["CI_PREV_COMMIT_SHA"]

View file

@ -35,12 +35,12 @@ const (
type (
// Metadata defines runtime m.
Metadata struct {
ID string `json:"id,omitempty"`
Repo Repo `json:"repo,omitempty"`
Curr Build `json:"curr,omitempty"`
Prev Build `json:"prev,omitempty"`
Job Job `json:"job,omitempty"`
Sys System `json:"sys,omitempty"`
ID string `json:"id,omitempty"`
Repo Repo `json:"repo,omitempty"`
Curr Pipeline `json:"curr,omitempty"`
Prev Pipeline `json:"prev,omitempty"`
Job Job `json:"job,omitempty"`
Sys System `json:"sys,omitempty"`
}
// Repo defines runtime metadata for a repository.
@ -53,8 +53,8 @@ type (
Branch string `json:"default_branch,omitempty"`
}
// Build defines runtime metadata for a build.
Build struct {
// Pipeline defines runtime metadata for a pipeline.
Pipeline struct {
Number int64 `json:"number,omitempty"`
Created int64 `json:"created,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_PULL_REQUEST": "", // will be set if event is pr
"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),
"CI_PIPELINE_NUMBER": strconv.FormatInt(m.Curr.Number, 10),
"CI_PIPELINE_PARENT": strconv.FormatInt(m.Curr.Parent, 10),
"CI_PIPELINE_EVENT": m.Curr.Event,
"CI_PIPELINE_LINK": m.Curr.Link,
"CI_PIPELINE_DEPLOY_TARGET": m.Curr.Target,
"CI_PIPELINE_STATUS": m.Curr.Status,
"CI_PIPELINE_CREATED": strconv.FormatInt(m.Curr.Created, 10),
"CI_PIPELINE_STARTED": strconv.FormatInt(m.Curr.Started, 10),
"CI_PIPELINE_FINISHED": strconv.FormatInt(m.Curr.Finished, 10),
"CI_JOB_NUMBER": strconv.Itoa(m.Job.Number),
"CI_JOB_STATUS": "", // will be set by agent
@ -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_AVATAR": m.Prev.Commit.Author.Avatar,
"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),
"CI_PREV_PIPELINE_NUMBER": strconv.FormatInt(m.Prev.Number, 10),
"CI_PREV_PIPELINE_PARENT": strconv.FormatInt(m.Prev.Parent, 10),
"CI_PREV_PIPELINE_EVENT": m.Prev.Event,
"CI_PREV_PIPELINE_LINK": m.Prev.Link,
"CI_PREV_PIPELINE_DEPLOY_TARGET": m.Prev.Target,
"CI_PREV_PIPELINE_STATUS": m.Prev.Status,
"CI_PREV_PIPELINE_CREATED": strconv.FormatInt(m.Prev.Created, 10),
"CI_PREV_PIPELINE_STARTED": strconv.FormatInt(m.Prev.Started, 10),
"CI_PREV_PIPELINE_FINISHED": strconv.FormatInt(m.Prev.Finished, 10),
"CI_SYSTEM_NAME": m.Sys.Name,
"CI_SYSTEM_LINK": m.Sys.Link,
@ -204,6 +204,26 @@ func (m *Metadata) Environ() map[string]string {
// DEPRECATED
"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 {
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
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
// the compiled pipeline configuration that should be skipped. The
// 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
// and path. The workspace base is a volume created at runtime and
// 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.
func WithWorkspace(base, path string) Option {
return func(compiler *Compiler) {
@ -177,7 +191,7 @@ func WithProxy() Option {
}
// WithNetworks configures the compiler with additional networks
// to be connected to build containers
// to be connected to pipeline containers
func WithNetworks(networks ...string) Option {
return func(compiler *Compiler) {
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
import (
@ -7,7 +21,7 @@ import (
"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
func generateScriptPosix(commands []string) string {
var buf bytes.Buffer
@ -27,7 +41,7 @@ func generateScriptPosix(commands []string) string {
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.
const setupScript = `
if [ -n "$CI_NETRC_MACHINE" ]; then
@ -44,7 +58,7 @@ unset CI_SCRIPT
%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.
const traceScript = `
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
import (
@ -39,7 +53,7 @@ $netrc=[string]::Format("{0}\_netrc",$Env:HOME);
%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.
const traceScriptWin = `
Write-Output ('+ %s');

View file

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

View file

@ -392,7 +392,7 @@ func TestConstraints(t *testing.T) {
desc: "no constraints, must match on default events",
conf: "",
with: frontend.Metadata{
Curr: frontend.Build{
Curr: frontend.Pipeline{
Event: frontend.EventPush,
},
},
@ -401,99 +401,99 @@ func TestConstraints(t *testing.T) {
{
desc: "global branch filter",
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,
},
{
desc: "global branch filter",
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,
},
{
desc: "repo constraint",
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,
},
{
desc: "repo constraint",
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,
},
{
desc: "ref constraint",
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,
},
{
desc: "ref constraint",
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,
},
{
desc: "platform constraint",
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,
},
{
desc: "platform constraint",
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,
},
{
desc: "instance constraint",
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,
},
{
desc: "instance constraint",
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,
},
{
desc: "filter cron by default constraint",
conf: "{}",
with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventCron}},
with: frontend.Metadata{Curr: frontend.Pipeline{Event: frontend.EventCron}},
want: false,
},
{
desc: "filter cron by matching name",
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,
},
{
desc: "filter cron by name",
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,
},
{
desc: "no constraints, event gets filtered by default event filter",
conf: "",
with: frontend.Metadata{
Curr: frontend.Build{Event: "non-default"},
Curr: frontend.Pipeline{Event: "non-default"},
},
want: false,
},
{
desc: "filter by eval based on event",
conf: `{ evaluate: 'CI_BUILD_EVENT == "push"' }`,
with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventPush}},
conf: `{ evaluate: 'CI_PIPELINE_EVENT == "push"' }`,
with: frontend.Metadata{Curr: frontend.Pipeline{Event: frontend.EventPush}},
want: true,
},
{
desc: "filter by eval based on event and repo",
conf: `{ evaluate: 'CI_BUILD_EVENT == "push" && CI_REPO == "owner/repo"' }`,
with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventPush}, Repo: frontend.Repo{Name: "owner/repo"}},
conf: `{ evaluate: 'CI_PIPELINE_EVENT == "push" && CI_REPO == "owner/repo"' }`,
with: frontend.Metadata{Curr: frontend.Pipeline{Event: frontend.EventPush}, Repo: frontend.Repo{Name: "owner/repo"}},
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
import (
@ -13,10 +27,10 @@ const (
limitAxis = 25
)
// Matrix represents the build matrix.
// Matrix represents the pipeline matrix.
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
// 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)
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 {
break
}

View file

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

View file

@ -29,6 +29,10 @@ var DefaultTracer = TraceFunc(func(state *State) error {
if state.Pipeline.Step.Environment == 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_STARTED"] = strconv.FormatInt(state.Pipeline.Time, 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)
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_JOB_STATUS"] = "failure"
}
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 2018 Drone.IO Inc.
//
// Licensed under the Apache License, Version 2.0 (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
}
build, err := _store.GetBuildLast(repo, branch)
pipeline, err := _store.GetPipelineLast(repo, branch)
if err != nil {
log.Warn().Err(err).Msg("")
build = nil
pipeline = nil
}
// we serve an SVG, so set content type appropriately.
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) {
@ -66,13 +67,13 @@ func GetCC(c *gin.Context) {
return
}
builds, err := _store.GetBuildList(repo, 1)
if err != nil || len(builds) == 0 {
pipelines, err := _store.GetPipelineList(repo, 1)
if err != nil || len(pipelines) == 0 {
c.AbortWithStatus(404)
return
}
url := fmt.Sprintf("%s/%s/%d", server.Config.Server.Host, repo.FullName, builds[0].Number)
cc := ccmenu.New(repo, builds[0], url)
url := fmt.Sprintf("%s/%s/%d", server.Config.Server.Host, repo.FullName, pipelines[0].Number)
cc := ccmenu.New(repo, pipelines[0], url)
c.XML(200, cc)
}

View file

@ -1,3 +1,4 @@
// Copyright 2022 Woodpecker Authors
// Copyright 2018 Drone.IO Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
@ -27,7 +28,7 @@ import (
"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) {
_store := store.FromContext(c)
num, err := strconv.ParseInt(c.Param("number"), 10, 64)
@ -37,13 +38,13 @@ func FileList(c *gin.Context) {
}
repo := session.Repo(c)
build, err := _store.GetBuildNumber(repo, num)
pipeline, err := _store.GetPipelineNumber(repo, num)
if err != nil {
_ = c.AbortWithError(http.StatusInternalServerError, err)
return
}
files, err := _store.FileList(build)
files, err := _store.FileList(pipeline)
if err != nil {
_ = c.AbortWithError(http.StatusInternalServerError, err)
return
@ -76,13 +77,13 @@ func FileGet(c *gin.Context) {
return
}
build, err := _store.GetBuildNumber(repo, num)
pipeline, err := _store.GetPipelineNumber(repo, num)
if err != nil {
_ = c.AbortWithError(http.StatusInternalServerError, err)
return
}
proc, err := _store.ProcFind(build, pid)
proc, err := _store.ProcFind(pipeline, pid)
if err != nil {
_ = c.AbortWithError(http.StatusInternalServerError, err)
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 2018 Drone.IO Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -79,7 +80,7 @@ func PostHook(c *gin.Context) {
return
}
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)
c.String(http.StatusOK, msg)
return
@ -174,10 +175,10 @@ func PostHook(c *gin.Context) {
return
}
build, err := pipeline.Create(c, _store, repo, tmpBuild)
pl, err := pipeline.Create(c, _store, repo, tmpBuild)
if err != nil {
handlePipelineErr(c, err)
} 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 2018 Drone.IO Inc.
//
// Licensed under the Apache License, Version 2.0 (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"
)
func CreateBuild(c *gin.Context) {
func CreatePipeline(c *gin.Context) {
_store := store.FromContext(c)
repo := session.Repo(c)
var p model.BuildOptions
var p model.PipelineOptions
err := json.NewDecoder(c.Request.Body).Decode(&p)
if err != nil {
@ -53,25 +54,25 @@ func CreateBuild(c *gin.Context) {
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 {
handlePipelineErr(c, err)
} 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 {
return &model.Build{
func createTmpPipeline(event model.WebhookEvent, commitSHA string, repo *model.Repo, user *model.User, opts *model.PipelineOptions) *model.Pipeline {
return &model.Pipeline{
Event: event,
Commit: commitSHA,
Branch: opts.Branch,
Timestamp: time.Now().UTC().Unix(),
Avatar: user.Avatar,
Message: "MANUAL BUILD @ " + opts.Branch,
Message: "MANUAL PIPELINE @ " + opts.Branch,
Ref: opts.Branch,
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)
page, err := strconv.Atoi(c.DefaultQuery("page", "1"))
if err != nil {
@ -92,18 +93,18 @@ func GetBuilds(c *gin.Context) {
return
}
builds, err := store.FromContext(c).GetBuildList(repo, page)
pipelines, err := store.FromContext(c).GetPipelineList(repo, page)
if err != nil {
c.AbortWithStatus(http.StatusInternalServerError)
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)
if c.Param("number") == "latest" {
GetBuildLast(c)
GetPipelineLast(c)
return
}
@ -114,62 +115,62 @@ func GetBuild(c *gin.Context) {
return
}
build, err := _store.GetBuildNumber(repo, num)
pl, err := _store.GetPipelineNumber(repo, num)
if err != nil {
_ = c.AbortWithError(http.StatusInternalServerError, err)
return
}
files, _ := _store.FileList(build)
procs, _ := _store.ProcList(build)
if build.Procs, err = model.Tree(procs); err != nil {
files, _ := _store.FileList(pl)
procs, _ := _store.ProcList(pl)
if pl.Procs, err = model.Tree(procs); err != nil {
_ = c.AbortWithError(http.StatusInternalServerError, err)
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)
repo := session.Repo(c)
branch := c.DefaultQuery("branch", repo.Branch)
build, err := _store.GetBuildLast(repo, branch)
pl, err := _store.GetPipelineLast(repo, branch)
if err != nil {
c.String(http.StatusInternalServerError, err.Error())
return
}
procs, err := _store.ProcList(build)
procs, err := _store.ProcList(pl)
if err != nil {
_ = c.AbortWithError(http.StatusInternalServerError, err)
return
}
if build.Procs, err = model.Tree(procs); err != nil {
if pl.Procs, err = model.Tree(procs); err != nil {
_ = c.AbortWithError(http.StatusInternalServerError, err)
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)
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.
num, _ := strconv.ParseInt(c.Params.ByName("number"), 10, 64)
ppid, _ := strconv.Atoi(c.Params.ByName("pid"))
name := c.Params.ByName("proc")
build, err := _store.GetBuildNumber(repo, num)
pl, err := _store.GetPipelineNumber(repo, num)
if err != nil {
_ = c.AbortWithError(404, err)
return
}
proc, err := _store.ProcChild(build, ppid, name)
proc, err := _store.ProcChild(pl, ppid, name)
if err != nil {
_ = c.AbortWithError(404, err)
return
@ -193,18 +194,18 @@ func GetProcLogs(c *gin.Context) {
_store := store.FromContext(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.
num, _ := strconv.ParseInt(c.Params.ByName("number"), 10, 64)
pid, _ := strconv.Atoi(c.Params.ByName("pid"))
build, err := _store.GetBuildNumber(repo, num)
pl, err := _store.GetPipelineNumber(repo, num)
if err != nil {
_ = c.AbortWithError(http.StatusNotFound, err)
return
}
proc, err := _store.ProcFind(build, pid)
proc, err := _store.ProcFind(pl, pid)
if err != nil {
_ = c.AbortWithError(http.StatusNotFound, err)
return
@ -224,7 +225,7 @@ func GetProcLogs(c *gin.Context) {
}
}
func GetBuildConfig(c *gin.Context) {
func GetPipelineConfig(c *gin.Context) {
_store := store.FromContext(c)
repo := session.Repo(c)
num, err := strconv.ParseInt(c.Param("number"), 10, 64)
@ -233,13 +234,13 @@ func GetBuildConfig(c *gin.Context) {
return
}
build, err := _store.GetBuildNumber(repo, num)
pl, err := _store.GetPipelineNumber(repo, num)
if err != nil {
_ = c.AbortWithError(http.StatusInternalServerError, err)
return
}
configs, err := _store.ConfigsForBuild(build.ID)
configs, err := _store.ConfigsForPipeline(pl.ID)
if err != nil {
c.String(http.StatusInternalServerError, err.Error())
return
@ -248,19 +249,19 @@ func GetBuildConfig(c *gin.Context) {
c.JSON(http.StatusOK, configs)
}
// DeleteBuild cancels a build
func DeleteBuild(c *gin.Context) {
// DeletePipeline cancels a pipeline
func DeletePipeline(c *gin.Context) {
_store := store.FromContext(c)
repo := session.Repo(c)
num, _ := strconv.ParseInt(c.Params.ByName("number"), 10, 64)
build, err := _store.GetBuildNumber(repo, num)
pl, err := _store.GetPipelineNumber(repo, num)
if err != nil {
_ = c.AbortWithError(http.StatusNotFound, err)
return
}
if err := pipeline.Cancel(c, _store, repo, build); err != nil {
if err := pipeline.Cancel(c, _store, repo, pl); err != nil {
handlePipelineErr(c, err)
} else {
c.Status(http.StatusNoContent)
@ -276,17 +277,17 @@ func PostApproval(c *gin.Context) {
num, _ = strconv.ParseInt(c.Params.ByName("number"), 10, 64)
)
build, err := _store.GetBuildNumber(repo, num)
pl, err := _store.GetPipelineNumber(repo, num)
if err != nil {
_ = c.AbortWithError(404, err)
return
}
newBuild, err := pipeline.Approve(c, _store, build, user, repo)
newpipeline, err := pipeline.Approve(c, _store, pl, user, repo)
if err != nil {
handlePipelineErr(c, err)
} 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)
)
build, err := _store.GetBuildNumber(repo, num)
pl, err := _store.GetPipelineNumber(repo, num)
if err != nil {
c.String(http.StatusNotFound, "%v", err)
return
}
build, err = pipeline.Decline(c, _store, build, user, repo)
pl, err = pipeline.Decline(c, _store, pl, user, repo)
if err != nil {
handlePipelineErr(c, err)
} else {
c.JSON(200, build)
c.JSON(200, pl)
}
}
func GetBuildQueue(c *gin.Context) {
out, err := store.FromContext(c).GetBuildQueue()
func GetPipelineQueue(c *gin.Context) {
out, err := store.FromContext(c).GetPipelineQueue()
if err != nil {
c.String(500, "Error getting build queue. %s", err)
c.String(500, "Error getting pipeline queue. %s", err)
return
}
c.JSON(200, out)
}
// PostBuild restarts a build optional with altered event, deploy or environment
func PostBuild(c *gin.Context) {
// PostPipeline restarts a pipeline optional with altered event, deploy or environment
func PostPipeline(c *gin.Context) {
_store := store.FromContext(c)
repo := session.Repo(c)
@ -340,9 +341,9 @@ func PostBuild(c *gin.Context) {
return
}
build, err := _store.GetBuildNumber(repo, num)
pl, err := _store.GetPipelineNumber(repo, num)
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)
return
}
@ -351,20 +352,20 @@ func PostBuild(c *gin.Context) {
refreshUserToken(c, user)
// make Deploy overridable
build.Deploy = c.DefaultQuery("deploy_to", build.Deploy)
pl.Deploy = c.DefaultQuery("deploy_to", pl.Deploy)
// make Event overridable
if event, ok := c.GetQuery("event"); ok {
build.Event = model.WebhookEvent(event)
pl.Event = model.WebhookEvent(event)
if !model.ValidateWebhookEvent(build.Event) {
msg := fmt.Sprintf("build event '%s' is invalid", event)
if !model.ValidateWebhookEvent(pl.Event) {
msg := fmt.Sprintf("pipeline event '%s' is invalid", event)
c.String(http.StatusBadRequest, msg)
return
}
}
// Read query string parameters into buildParams, exclude reserved params
// Read query string parameters into pipelineParams, exclude reserved params
envs := map[string]string{}
for key, val := range c.Request.URL.Query() {
switch key {
@ -372,43 +373,43 @@ func PostBuild(c *gin.Context) {
case "fork", "event", "deploy_to":
continue
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
// TODO: sanitize the value
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 {
handlePipelineErr(c, err)
} else {
c.JSON(200, newBuild)
c.JSON(200, newpipeline)
}
}
func DeleteBuildLogs(c *gin.Context) {
func DeletePipelineLogs(c *gin.Context) {
_store := store.FromContext(c)
repo := session.Repo(c)
user := session.User(c)
num, _ := strconv.ParseInt(c.Params.ByName("number"), 10, 64)
build, err := _store.GetBuildNumber(repo, num)
pl, err := _store.GetPipelineNumber(repo, num)
if err != nil {
_ = c.AbortWithError(404, err)
return
}
procs, err := _store.ProcList(build)
procs, err := _store.ProcList(pl)
if err != nil {
_ = c.AbortWithError(404, err)
return
}
switch build.Status {
switch pl.Status {
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
}

View file

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

View file

@ -1,3 +1,4 @@
// Copyright 2022 Woodpecker Authors
// Copyright 2018 Drone.IO Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
@ -140,18 +141,18 @@ func LogStreamSSE(c *gin.Context) {
repo := session.Repo(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.
buildn, _ := strconv.ParseInt(c.Param("build"), 10, 64)
pipelinen, _ := strconv.ParseInt(c.Param("pipeline"), 10, 64)
jobn, _ := strconv.Atoi(c.Param("number"))
build, err := _store.GetBuildNumber(repo, buildn)
pipeline, err := _store.GetPipelineNumber(repo, pipelinen)
if err != nil {
log.Debug().Msgf("stream cannot get build number: %v", err)
logWriteStringErr(io.WriteString(rw, "event: error\ndata: build not found\n\n"))
log.Debug().Msgf("stream cannot get pipeline number: %v", err)
logWriteStringErr(io.WriteString(rw, "event: error\ndata: pipeline not found\n\n"))
return
}
proc, err := _store.ProcFind(build, jobn)
proc, err := _store.ProcFind(pipeline, jobn)
if err != nil {
log.Debug().Msgf("stream cannot get proc number: %v", err)
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
func Generate(pipeline *model.Build) string {
func Generate(pipeline *model.Pipeline) string {
if pipeline == nil {
return badgeNone
}

View file

@ -23,7 +23,7 @@ import (
"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.
//
// http://ccmenu.org/
@ -43,7 +43,7 @@ type CCProject struct {
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{
Name: r.FullName,
WebURL: link,
@ -52,8 +52,8 @@ func New(r *model.Repo, b *model.Build, link string) *CCProjects {
LastBuildLabel: "Unknown",
}
// if the build is not currently running then
// we can return the latest build status.
// if the pipeline is not currently running then
// we can return the latest pipeline status.
if b.Status != model.StatusPending &&
b.Status != model.StatusRunning {
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)
}
// ensure the last build Status accepts a valid
// ensure the last pipeline status accepts a valid
// ccmenu enumeration
switch b.Status {
case model.StatusError, model.StatusKilled:

View file

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

View file

@ -105,7 +105,7 @@ func runCron(store store.Store, remote remote.Remote, cron *model.Cron, now time
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)
if err != nil {
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 repo, &model.Build{
return repo, &model.Pipeline{
Event: model.EventCron,
Commit: commit,
Ref: "refs/heads/" + cron.Branch,

View file

@ -49,18 +49,18 @@ func TestCreateBuild(t *testing.T) {
store.On("GetUser", mock.Anything).Return(creator, 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",
})
assert.NoError(t, err)
assert.EqualValues(t, &model.Build{
assert.EqualValues(t, &model.Pipeline{
Event: "cron",
Commit: "sha1",
Branch: "default",
Ref: "refs/heads/default",
Message: "test",
Sender: "test",
}, build)
}, pipeline)
}
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 2018 Drone.IO Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -41,14 +42,14 @@ import (
)
type RPC struct {
remote remote.Remote
queue queue.Queue
pubsub pubsub.Publisher
logger logging.Log
store store.Store
host string
buildTime *prometheus.GaugeVec
buildCount *prometheus.CounterVec
remote remote.Remote
queue queue.Queue
pubsub pubsub.Publisher
logger logging.Log
store store.Store
host string
pipelineTime *prometheus.GaugeVec
pipelineCount *prometheus.CounterVec
}
// 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
}
build, err := s.store.GetBuild(pproc.BuildID)
pipeline, err := s.store.GetPipeline(pproc.PipelineID)
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
}
proc, err := s.store.ProcChild(build, pproc.PID, state.Proc)
proc, err := s.store.ProcChild(pipeline, pproc.PID, state.Proc)
if err != nil {
log.Error().Msgf("error: cannot find proc with name %s: %s", state.Proc, 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 {
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
}
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")
}
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")
}
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")
return err
}
@ -151,8 +152,8 @@ func (s *RPC) Update(c context.Context, id string, state rpc.State) error {
},
}
message.Data, _ = json.Marshal(model.Event{
Repo: *repo,
Build: *build,
Repo: *repo,
Pipeline: *pipeline,
})
if err := s.pubsub.Publish(c, "topic/events", message); err != nil {
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
}
build, err := s.store.GetBuild(pproc.BuildID)
pipeline, err := s.store.GetPipeline(pproc.PipelineID)
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
}
proc, err := s.store.ProcChild(build, pproc.PID, file.Proc)
proc, err := s.store.ProcChild(pipeline, pproc.PID, file.Proc)
if err != nil {
log.Error().Msgf("error: cannot find child proc with name %s: %s", file.Proc, err)
return err
@ -194,13 +195,13 @@ func (s *RPC) Upload(c context.Context, id string, file *rpc.File) error {
}
report := &model.File{
BuildID: proc.BuildID,
ProcID: proc.ID,
PID: proc.PID,
Mime: file.Mime,
Name: file.Name,
Size: file.Size,
Time: file.Time,
PipelineID: proc.PipelineID,
ProcID: proc.ID,
PID: proc.PID,
Mime: file.Mime,
Name: file.Name,
Size: file.Size,
Time: file.Time,
}
if d, ok := file.Meta["X-Tests-Passed"]; ok {
report.Passed, _ = strconv.Atoi(d)
@ -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 {
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
}
repo, err := s.store.GetRepo(build.RepoID)
repo, err := s.store.GetRepo(pipeline.RepoID)
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
}
if build.Status == model.StatusPending {
if build, err = shared.UpdateToStatusRunning(s.store, *build, state.Started); err != nil {
log.Error().Msgf("error: init: cannot update build_id %d state: %s", build.ID, err)
if pipeline.Status == model.StatusPending {
if pipeline, err = shared.UpdateToStatusRunning(s.store, *pipeline, state.Started); err != nil {
log.Error().Msgf("error: init: cannot update build_id %d state: %s", pipeline.ID, err)
}
}
defer func() {
build.Procs, _ = s.store.ProcList(build)
pipeline.Procs, _ = s.store.ProcList(pipeline)
message := pubsub.Message{
Labels: map[string]string{
"repo": repo.FullName,
@ -281,8 +282,8 @@ func (s *RPC) Init(c context.Context, id string, state rpc.State) error {
},
}
message.Data, _ = json.Marshal(model.Event{
Repo: *repo,
Build: *build,
Repo: *repo,
Pipeline: *pipeline,
})
if err := s.pubsub.Publish(c, "topic/events", message); err != nil {
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
}
build, err := s.store.GetBuild(proc.BuildID)
pipeline, err := s.store.GetPipeline(proc.PipelineID)
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
}
repo, err := s.store.GetRepo(build.RepoID)
repo, err := s.store.GetRepo(pipeline.RepoID)
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
}
log.Trace().
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).
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)
}
procs, err := s.store.ProcList(build)
procs, err := s.store.ProcList(pipeline)
if err != nil {
return err
}
s.completeChildrenIfParentCompleted(procs, proc)
if !model.IsThereRunningStage(procs) {
if build, err = shared.UpdateStatusToDone(s.store, *build, model.BuildStatus(procs), proc.Stopped); err != nil {
log.Error().Err(err).Msgf("error: done: cannot update build_id %d final state", build.ID)
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", pipeline.ID)
}
}
s.updateRemoteStatus(c, repo, build, proc)
s.updateRemoteStatus(c, repo, pipeline, proc)
if err := s.logger.Close(c, id); err != nil {
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
}
if build.Status == model.StatusSuccess || build.Status == model.StatusFailure {
s.buildCount.WithLabelValues(repo.FullName, build.Branch, string(build.Status), "total").Inc()
s.buildTime.WithLabelValues(repo.FullName, build.Branch, string(build.Status), "total").Set(float64(build.Finished - build.Started))
if pipeline.Status == model.StatusSuccess || pipeline.Status == model.StatusFailure {
s.pipelineCount.WithLabelValues(repo.FullName, pipeline.Branch, string(pipeline.Status), "total").Inc()
s.pipelineTime.WithLabelValues(repo.FullName, pipeline.Branch, string(pipeline.Status), "total").Set(float64(pipeline.Finished - pipeline.Started))
}
if model.IsMultiPipeline(procs) {
s.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
@ -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)
if err != nil {
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
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 {
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) {
if build.Procs, err = model.Tree(procs); err != nil {
func (s *RPC) notify(c context.Context, repo *model.Repo, pipeline *model.Pipeline, procs []*model.Proc) (err error) {
if pipeline.Procs, err = model.Tree(procs); err != nil {
return err
}
message := pubsub.Message{
@ -429,8 +430,8 @@ func (s *RPC) notify(c context.Context, repo *model.Repo, build *model.Build, pr
},
}
message.Data, _ = json.Marshal(model.Event{
Repo: *repo,
Build: *build,
Repo: *repo,
Pipeline: *pipeline,
})
if err := s.pubsub.Publish(c, "topic/events", message); err != nil {
log.Error().Err(err).Msgf("grpc could not notify event: '%v'", message)

View file

@ -37,25 +37,25 @@ type WoodpeckerServer struct {
}
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",
Name: "build_time",
Help: "Build time.",
Name: "pipeline_time",
Help: "Pipeline time.",
}, []string{"repo", "branch", "status", "pipeline"})
buildCount := promauto.NewCounterVec(prometheus.CounterOpts{
pipelineCount := promauto.NewCounterVec(prometheus.CounterOpts{
Namespace: "woodpecker",
Name: "build_count",
Help: "Build count.",
Name: "pipeline_count",
Help: "Pipeline count.",
}, []string{"repo", "branch", "status", "pipeline"})
peer := RPC{
remote: remote,
store: store,
queue: queue,
pubsub: pubsub,
logger: logger,
host: host,
buildTime: buildTime,
buildCount: buildCount,
remote: remote,
store: store,
queue: queue,
pubsub: pubsub,
logger: logger,
host: host,
pipelineTime: pipelineTime,
pipelineCount: pipelineCount,
}
return &WoodpeckerServer{peer: peer}
}

View file

@ -17,11 +17,11 @@ package model
// ConfigStore persists pipeline configuration to storage.
type ConfigStore interface {
ConfigsForBuild(buildID int64) ([]*Config, error)
ConfigsForPipeline(pipelineID int64) ([]*Config, error)
ConfigFindIdentical(repoID int64, hash string) (*Config, error)
ConfigFindApproved(*Config) (bool, error)
ConfigCreate(*Config) error
BuildConfigCreate(*BuildConfig) error
PipelineConfigCreate(*PipelineConfig) error
}
// Config represents a pipeline configuration.
@ -33,8 +33,8 @@ type Config struct {
Data []byte `json:"data" xorm:"config_data"`
}
// BuildConfig is the n:n relation between Build and Config
type BuildConfig struct {
ConfigID int64 `json:"-" xorm:"UNIQUE(s) NOT NULL 'config_id'"`
BuildID int64 `json:"-" xorm:"UNIQUE(s) NOT NULL 'build_id'"`
// PipelineConfig is the n:n relation between Pipeline and Config
type PipelineConfig struct {
ConfigID int64 `json:"-" xorm:"UNIQUE(s) NOT NULL 'config_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.
//
// 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.
//
// Licensed under the Apache License, Version 2.0 (the "License");
@ -14,11 +15,11 @@
package model
// EventType defines the possible types of build events.
// EventType defines the possible types of pipeline events.
type EventType string
// Event represents a build event.
// Event represents a pipeline event.
type Event struct {
Repo Repo `json:"repo"`
Build Build `json:"build"`
Repo Repo `json:"repo"`
Pipeline Pipeline `json:"build"`
}

View file

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

View file

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

View file

@ -20,32 +20,32 @@ import "fmt"
// ProcStore persists process information to storage.
type ProcStore interface {
ProcLoad(int64) (*Proc, error)
ProcFind(*Build, int) (*Proc, error)
ProcChild(*Build, int, string) (*Proc, error)
ProcList(*Build) ([]*Proc, error)
ProcFind(*Pipeline, int) (*Proc, error)
ProcChild(*Pipeline, int, string) (*Proc, error)
ProcList(*Pipeline) ([]*Proc, error)
ProcCreate([]*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
type Proc struct {
ID int64 `json:"id" xorm:"pk autoincr 'proc_id'"`
BuildID int64 `json:"build_id" xorm:"UNIQUE(s) INDEX 'proc_build_id'"`
PID int `json:"pid" xorm:"UNIQUE(s) 'proc_pid'"`
PPID int `json:"ppid" xorm:"proc_ppid"`
PGID int `json:"pgid" xorm:"proc_pgid"`
Name string `json:"name" xorm:"proc_name"`
State StatusValue `json:"state" xorm:"proc_state"`
Error string `json:"error,omitempty" xorm:"VARCHAR(500) proc_error"`
ExitCode int `json:"exit_code" xorm:"proc_exit_code"`
Started int64 `json:"start_time,omitempty" xorm:"proc_started"`
Stopped int64 `json:"end_time,omitempty" xorm:"proc_stopped"`
Machine string `json:"machine,omitempty" xorm:"proc_machine"`
Platform string `json:"platform,omitempty" xorm:"proc_platform"`
Environ map[string]string `json:"environ,omitempty" xorm:"json 'proc_environ'"`
Children []*Proc `json:"children,omitempty" xorm:"-"`
ID int64 `json:"id" xorm:"pk autoincr 'proc_id'"`
PipelineID int64 `json:"build_id" xorm:"UNIQUE(s) INDEX 'proc_build_id'"`
PID int `json:"pid" xorm:"UNIQUE(s) 'proc_pid'"`
PPID int `json:"ppid" xorm:"proc_ppid"`
PGID int `json:"pgid" xorm:"proc_pgid"`
Name string `json:"name" xorm:"proc_name"`
State StatusValue `json:"state" xorm:"proc_state"`
Error string `json:"error,omitempty" xorm:"VARCHAR(500) proc_error"`
ExitCode int `json:"exit_code" xorm:"proc_exit_code"`
Started int64 `json:"start_time,omitempty" xorm:"proc_started"`
Stopped int64 `json:"end_time,omitempty" xorm:"proc_stopped"`
Machine string `json:"machine,omitempty" xorm:"proc_machine"`
Platform string `json:"platform,omitempty" xorm:"proc_platform"`
Environ map[string]string `json:"environ,omitempty" xorm:"json 'proc_environ'"`
Children []*Proc `json:"children,omitempty" xorm:"-"`
}
type UpdateProcStore interface {
@ -111,8 +111,8 @@ func Tree(procs []*Proc) ([]*Proc, error) {
return nodes, nil
}
// BuildStatus determine build status based on corresponding proc list
func BuildStatus(procs []*Proc) StatusValue {
// PipelineStatus determine pipeline status based on corresponding proc list
func PipelineStatus(procs []*Proc) StatusValue {
status := StatusSuccess
for _, p := range procs {

View file

@ -22,32 +22,32 @@ import (
func TestTree(t *testing.T) {
procs := []*Proc{{
ID: 25,
PID: 2,
BuildID: 6,
PPID: 1,
PGID: 2,
Name: "clone",
State: StatusSuccess,
Error: "0",
ID: 25,
PID: 2,
PipelineID: 6,
PPID: 1,
PGID: 2,
Name: "clone",
State: StatusSuccess,
Error: "0",
}, {
ID: 24,
BuildID: 6,
PID: 1,
PPID: 0,
PGID: 1,
Name: "lint",
State: StatusFailure,
Error: "1",
ID: 24,
PipelineID: 6,
PID: 1,
PPID: 0,
PGID: 1,
Name: "lint",
State: StatusFailure,
Error: "1",
}, {
ID: 26,
BuildID: 6,
PID: 3,
PPID: 1,
PGID: 3,
Name: "lint",
State: StatusFailure,
Error: "1",
ID: 26,
PipelineID: 6,
PID: 3,
PPID: 1,
PGID: 3,
Name: "lint",
State: StatusFailure,
Error: "1",
}}
procs, err := Tree(procs)
assert.NoError(t, err)
@ -55,14 +55,14 @@ func TestTree(t *testing.T) {
assert.Len(t, procs[0].Children, 2)
procs = []*Proc{{
ID: 25,
PID: 2,
BuildID: 6,
PPID: 1,
PGID: 2,
Name: "clone",
State: StatusSuccess,
Error: "0",
ID: 25,
PID: 2,
PipelineID: 6,
PPID: 1,
PGID: 2,
Name: "clone",
State: StatusSuccess,
Error: "0",
}}
_, err = Tree(procs)
assert.Error(t, 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 model
type Redirection struct {

View file

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

View file

@ -26,23 +26,23 @@ import (
"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
func Approve(ctx context.Context, store store.Store, build *model.Build, user *model.User, repo *model.Repo) (*model.Build, error) {
if build.Status != model.StatusBlocked {
return nil, ErrBadRequest{Msg: fmt.Sprintf("cannot decline a build with status %s", build.Status)}
func Approve(ctx context.Context, store store.Store, pipeline *model.Pipeline, user *model.User, repo *model.Repo) (*model.Pipeline, error) {
if pipeline.Status != model.StatusBlocked {
return nil, ErrBadRequest{Msg: fmt.Sprintf("cannot decline a pipeline with status %s", pipeline.Status)}
}
// fetch the build file from the database
configs, err := store.ConfigsForBuild(build.ID)
// fetch the pipeline file from the database
configs, err := store.ConfigsForPipeline(pipeline.ID)
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)
return nil, ErrNotFound{Msg: msg}
}
if build, err = shared.UpdateToStatusPending(store, *build, user.Login); err != nil {
return nil, fmt.Errorf("error updating build. %s", err)
if pipeline, err = shared.UpdateToStatusPending(store, *pipeline, user.Login); err != nil {
return nil, fmt.Errorf("error updating pipeline. %s", err)
}
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})
}
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 {
msg := fmt.Sprintf("failure to createBuildItems for %s", repo.FullName)
log.Error().Err(err).Msg(msg)
return nil, err
}
build, err = start(ctx, store, build, user, repo, buildItems)
pipeline, err = start(ctx, store, pipeline, user, repo, pipelineItems)
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)
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"
)
// Cancel the build and returns the status.
func Cancel(ctx context.Context, store store.Store, repo *model.Repo, build *model.Build) error {
if build.Status != model.StatusRunning && build.Status != model.StatusPending && build.Status != model.StatusBlocked {
return ErrBadRequest{Msg: "Cannot cancel a non-running or non-pending or non-blocked build"}
// Cancel the pipeline and returns the status.
func Cancel(ctx context.Context, store store.Store, repo *model.Repo, pipeline *model.Pipeline) error {
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 pipeline"}
}
procs, err := store.ProcList(build)
procs, err := store.ProcList(pipeline)
if err != nil {
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
for _, proc := range procs {
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 {
log.Error().Err(err).Msgf("UpdateToStatusKilled: %v", build)
log.Error().Err(err).Msgf("UpdateToStatusKilled: %v", pipeline)
return err
}
@ -108,13 +108,13 @@ func Cancel(ctx context.Context, store store.Store, repo *model.Repo, build *mod
func cancelPreviousPipelines(
ctx context.Context,
_store store.Store,
build *model.Build,
pipeline *model.Pipeline,
repo *model.Repo,
) error {
// check this event should cancel previous pipelines
eventIncluded := false
for _, ev := range repo.CancelPreviousPipelineEvents {
if ev == build.Event {
if ev == pipeline.Event {
eventIncluded = true
break
}
@ -124,38 +124,38 @@ func cancelPreviousPipelines(
}
// get all active activeBuilds
activeBuilds, err := _store.GetActiveBuildList(repo, -1)
activeBuilds, err := _store.GetActivePipelineList(repo, -1)
if err != nil {
return err
}
buildNeedsCancel := func(active *model.Build) (bool, error) {
pipelineNeedsCancel := func(active *model.Pipeline) (bool, error) {
// always filter on same event
if active.Event != build.Event {
if active.Event != pipeline.Event {
return false, nil
}
// find events for the same context
switch build.Event {
switch pipeline.Event {
case model.EventPush:
return build.Branch == active.Branch, nil
return pipeline.Branch == active.Branch, nil
default:
return build.Refspec == active.Refspec, nil
return pipeline.Refspec == active.Refspec, nil
}
}
for _, active := range activeBuilds {
if active.ID == build.ID {
// same build. e.g. self
if active.ID == pipeline.ID {
// same pipeline. e.g. self
continue
}
cancel, err := buildNeedsCancel(active)
cancel, err := pipelineNeedsCancel(active)
if err != nil {
log.Error().
Err(err).
Str("Ref", active.Ref).
Msg("Error while trying to cancel build, skipping")
Msg("Error while trying to cancel pipeline, skipping")
continue
}
@ -168,7 +168,7 @@ func cancelPreviousPipelines(
Err(err).
Str("Ref", active.Ref).
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"
)
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))
conf, err := store.ConfigFindIdentical(build.RepoID, sha)
conf, err := store.ConfigFindIdentical(pipeline.RepoID, sha)
if err != nil {
conf = &model.Config{
RepoID: build.RepoID,
RepoID: pipeline.RepoID,
Data: remoteYamlConfig.Data,
Hash: sha,
Name: shared.SanitizePath(remoteYamlConfig.Name),
@ -37,18 +37,18 @@ func findOrPersistPipelineConfig(store store.Store, build *model.Build, remoteYa
err = store.ConfigCreate(conf)
if err != nil {
// 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 {
return nil, err
}
}
}
buildConfig := &model.BuildConfig{
ConfigID: conf.ID,
BuildID: build.ID,
pipelineConfig := &model.PipelineConfig{
ConfigID: conf.ID,
PipelineID: pipeline.ID,
}
if err := store.BuildConfigCreate(buildConfig); err != nil {
if err := store.PipelineConfigCreate(pipelineConfig); err != nil {
return nil, err
}

View file

@ -28,8 +28,8 @@ import (
"github.com/woodpecker-ci/woodpecker/server/store"
)
// Create a new build and start it
func Create(ctx context.Context, _store store.Store, repo *model.Repo, build *model.Build) (*model.Build, error) {
// Create a new pipeline and start it
func Create(ctx context.Context, _store store.Store, repo *model.Repo, pipeline *model.Pipeline) (*model.Pipeline, error) {
repoUser, err := _store.GetUser(repo.UserID)
if err != nil {
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
// may be stale. Therefore, we should refresh prior to dispatching
// the build.
// the pipeline.
if refresher, ok := server.Config.Services.Remote.(remote.Refresher); ok {
refreshed, err := refresher.Refresh(ctx, repoUser)
if err != nil {
@ -59,11 +59,11 @@ func Create(ctx context.Context, _store store.Store, repo *model.Repo, build *mo
parseErr error
)
// fetch the build file from the remote
configFetcher := shared.NewConfigFetcher(server.Config.Services.Remote, server.Config.Services.ConfigService, repoUser, repo, build)
// fetch the pipeline file from the remote
configFetcher := shared.NewConfigFetcher(server.Config.Services.Remote, server.Config.Services.ConfigService, repoUser, repo, pipeline)
remoteYamlConfigs, configFetchErr = configFetcher.Fetch(ctx)
if configFetchErr == nil {
filtered, parseErr = checkIfFiltered(build, remoteYamlConfigs)
filtered, parseErr = checkIfFiltered(pipeline, remoteYamlConfigs)
if parseErr == nil {
if filtered {
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
}
if zeroSteps(build, remoteYamlConfigs) {
if zeroSteps(pipeline, remoteYamlConfigs) {
err := ErrFiltered{Msg: "step conditions yield zero runnable steps"}
log.Debug().Str("repo", repo.FullName).Msgf("%v", 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
build.RepoID = repo.ID
build.Verified = true
build.Status = model.StatusPending
// update some pipeline fields
pipeline.RepoID = repo.ID
pipeline.Verified = true
pipeline.Status = model.StatusPending
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)
build.Started = time.Now().Unix()
build.Finished = build.Started
build.Status = model.StatusError
build.Error = fmt.Sprintf("pipeline definition not found in %s", repo.FullName)
log.Debug().Str("repo", repo.FullName).Err(configFetchErr).Msgf("cannot find config '%s' in '%s' with user: '%s'", repo.Config, pipeline.Ref, repoUser.Login)
pipeline.Started = time.Now().Unix()
pipeline.Finished = pipeline.Started
pipeline.Status = model.StatusError
pipeline.Error = fmt.Sprintf("pipeline definition not found in %s", repo.FullName)
} else if parseErr != nil {
log.Debug().Str("repo", repo.FullName).Err(parseErr).Msg("failed to parse yaml")
build.Started = time.Now().Unix()
build.Finished = build.Started
build.Status = model.StatusError
build.Error = fmt.Sprintf("failed to parse pipeline: %s", parseErr.Error())
pipeline.Started = time.Now().Unix()
pipeline.Finished = pipeline.Started
pipeline.Status = model.StatusError
pipeline.Error = fmt.Sprintf("failed to parse pipeline: %s", parseErr.Error())
} else if repo.IsGated {
// 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 {
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)
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 {
_, err := findOrPersistPipelineConfig(_store, build, remoteYamlConfig)
_, err := findOrPersistPipelineConfig(_store, pipeline, remoteYamlConfig)
if err != nil {
msg := fmt.Sprintf("failure to find or persist pipeline config for %s", repo.FullName)
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 err := publishToTopic(ctx, build, repo); err != nil {
if pipeline.Status == model.StatusError {
if err := publishToTopic(ctx, pipeline, repo); err != nil {
log.Error().Err(err).Msg("publishToTopic")
}
if err := updateBuildStatus(ctx, build, repo, repoUser); err != nil {
log.Error().Err(err).Msg("updateBuildStatus")
if err := updatePipelineStatus(ctx, pipeline, repo, repoUser); err != nil {
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 {
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)
return nil, fmt.Errorf(msg)
}
if build.Status == model.StatusBlocked {
if err := publishToTopic(ctx, build, repo); err != nil {
if pipeline.Status == model.StatusBlocked {
if err := publishToTopic(ctx, pipeline, repo); err != nil {
log.Error().Err(err).Msg("publishToTopic")
}
if err := updateBuildStatus(ctx, build, repo, repoUser); err != nil {
log.Error().Err(err).Msg("updateBuildStatus")
if err := updatePipelineStatus(ctx, pipeline, repo, repoUser); err != nil {
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 {
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)
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"
)
// Decline update the status to declined for blocked build 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) {
if build.Status != model.StatusBlocked {
return nil, fmt.Errorf("cannot decline a build with status %s", build.Status)
// Decline update the status to declined for blocked pipeline because of a gated repo
func Decline(ctx context.Context, store store.Store, pipeline *model.Pipeline, user *model.User, repo *model.Repo) (*model.Pipeline, error) {
if pipeline.Status != model.StatusBlocked {
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 {
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")
}
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")
}
if err := updateBuildStatus(ctx, build, repo, user); err != nil {
if err := updatePipelineStatus(ctx, pipeline, repo, user); err != nil {
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")
}
return build, nil
return pipeline, nil
}

View file

@ -26,11 +26,11 @@ import (
"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{
Repo: &model.Repo{},
Curr: build,
Last: &model.Build{},
Curr: pipeline,
Last: &model.Pipeline{},
Netrc: &model.Netrc{},
Secs: []*model.Secret{},
Regs: []*model.Registry{},
@ -38,11 +38,11 @@ func zeroSteps(build *model.Build, remoteYamlConfigs []*remote.FileMeta) bool {
Yamls: remoteYamlConfigs,
}
buildItems, err := b.Build()
pipelineItems, err := b.Build()
if err != nil {
return false
}
if len(buildItems) == 0 {
if len(pipelineItems) == 0 {
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
// 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) {
log.Trace().Msgf("hook.branchFiltered(): build branch: '%s' build event: '%s' config count: %d", build.Branch, build.Event, len(remoteYamlConfigs))
func checkIfFiltered(pipeline *model.Pipeline, remoteYamlConfigs []*remote.FileMeta) (bool, error) {
log.Trace().Msgf("hook.branchFiltered(): pipeline branch: '%s' pipeline event: '%s' config count: %d", pipeline.Branch, pipeline.Event, len(remoteYamlConfigs))
matchMetadata := frontend.Metadata{
Curr: frontend.Build{
Event: string(build.Event),
Curr: frontend.Pipeline{
Event: string(pipeline.Event),
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)
if !parsedPipelineConfig.Branches.Match(build.Branch) {
if !parsedPipelineConfig.Branches.Match(pipeline.Branch) {
continue
}

View file

@ -23,16 +23,16 @@ import (
"github.com/woodpecker-ci/woodpecker/server/model"
)
func updateBuildStatus(ctx context.Context, build *model.Build, repo *model.Repo, user *model.User) error {
for _, proc := range build.Procs {
func updatePipelineStatus(ctx context.Context, pipeline *model.Pipeline, repo *model.Repo, user *model.User) error {
for _, proc := range pipeline.Procs {
// skip child procs
if !proc.IsParent() {
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 {
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
}
}

View file

@ -28,26 +28,26 @@ import (
"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)
if err != nil {
log.Error().Err(err).Msg("Failed to generate netrc file")
}
// get the previous build so that we can send status change notifications
last, err := store.GetBuildLastBefore(repo, build.Branch, build.ID)
// get the previous pipeline so that we can send status change notifications
last, err := store.GetPipelineLastBefore(repo, pipeline.Branch, pipeline.ID)
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 {
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)
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 {
@ -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
}
b := shared.ProcBuilder{
Repo: repo,
Curr: build,
Curr: pipeline,
Last: last,
Netrc: netrc,
Secs: secs,
@ -75,16 +75,16 @@ func createBuildItems(ctx context.Context, store store.Store, build *model.Build
Link: server.Config.Server.Host,
Yamls: yamls,
}
buildItems, err := b.Build()
pipelineItems, err := b.Build()
if err != nil {
build, uerr := shared.UpdateToStatusError(store, *build, err)
pipeline, uerr := shared.UpdateToStatusError(store, *pipeline, err)
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"
)
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
for _, item := range buildItems {
for _, item := range pipelineItems {
if item.Proc.State == model.StatusSkipped {
continue
}
@ -40,7 +40,7 @@ func queueBuild(build *model.Build, repo *model.Repo, buildItems []*shared.Build
}
task.Labels["platform"] = item.Platform
task.Labels["repo"] = repo.FullName
task.Dependencies = taskIds(item.DependsOn, buildItems)
task.Dependencies = taskIds(item.DependsOn, pipelineItems)
task.RunOn = item.RunsOn
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)
}
func taskIds(dependsOn []string, buildItems []*shared.BuildItem) (taskIds []string) {
func taskIds(dependsOn []string, pipelineItems []*shared.PipelineItem) (taskIds []string) {
for _, dep := range dependsOn {
for _, buildItem := range buildItems {
if buildItem.Proc.Name == dep {
taskIds = append(taskIds, fmt.Sprint(buildItem.Proc.ID))
for _, pipelineItem := range pipelineItems {
if pipelineItem.Proc.Name == dep {
taskIds = append(taskIds, fmt.Sprint(pipelineItem.Proc.ID))
}
}
}

View file

@ -30,20 +30,20 @@ import (
"github.com/woodpecker-ci/woodpecker/server/store"
)
// Restart a build 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) {
// 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.Pipeline, user *model.User, repo *model.Repo, envs map[string]string) (*model.Pipeline, error) {
switch lastBuild.Status {
case model.StatusDeclined,
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
// fetch the old pipeline config from database
configs, err := store.ConfigsForBuild(lastBuild.ID)
configs, err := store.ConfigsForPipeline(lastBuild.ID)
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)
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)
if err != nil {
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 {
@ -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
err = store.CreateBuild(newBuild)
err = store.CreatePipeline(newBuild)
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)
return nil, fmt.Errorf(msg)
}
@ -87,13 +87,13 @@ func Restart(ctx context.Context, store store.Store, lastBuild *model.Build, use
}
return newBuild, nil
}
if err := persistBuildConfigs(store, configs, newBuild.ID); err != nil {
msg := fmt.Sprintf("failure to persist build config for %s.", repo.FullName)
if err := persistPipelineConfigs(store, configs, newBuild.ID); err != nil {
msg := fmt.Sprintf("failure to persist pipeline config for %s.", repo.FullName)
log.Error().Err(err).Msg(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 errors.Is(err, &yaml.PipelineParseError{}) {
return newBuild, nil
@ -103,9 +103,9 @@ func Restart(ctx context.Context, store store.Store, lastBuild *model.Build, use
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 {
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)
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
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 {
buildConfig := &model.BuildConfig{
ConfigID: conf.ID,
BuildID: buildID,
pipelineConfig := &model.PipelineConfig{
ConfigID: conf.ID,
PipelineID: pipelineID,
}
err := store.BuildConfigCreate(buildConfig)
err := store.PipelineConfigCreate(pipelineConfig)
if err != nil {
return err
}
@ -128,7 +128,7 @@ func persistBuildConfigs(store store.Store, configs []*model.Config, buildID int
return nil
}
func createNewBuildOutOfOld(old *model.Build) *model.Build {
func createNewOutOfOld(old *model.Pipeline) *model.Pipeline {
new := *old
new.ID = 0
new.Number = 0

View file

@ -24,31 +24,31 @@ import (
"github.com/woodpecker-ci/woodpecker/server/store"
)
// start a build, 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) {
// call to cancel previous builds if needed
if err := cancelPreviousPipelines(ctx, store, activeBuild, repo); err != nil {
// start a pipeline, make sure it was stored persistent in the store before
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 pipelines if needed
if err := cancelPreviousPipelines(ctx, store, activePipeline, repo); err != nil {
// 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 {
log.Error().Err(err).Str("repo", repo.FullName).Msgf("error persisting procs for %s#%d", repo.FullName, activeBuild.Number)
if err := store.ProcCreate(activePipeline.Procs); err != nil {
log.Error().Err(err).Str("repo", repo.FullName).Msgf("error persisting procs for %s#%d", repo.FullName, activePipeline.Number)
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")
}
if err := queueBuild(activeBuild, repo, buildItems); err != nil {
if err := queueBuild(activePipeline, repo, pipelineItems); err != nil {
log.Error().Err(err).Msg("queueBuild")
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")
}
return activeBuild, nil
return activePipeline, nil
}

View file

@ -25,21 +25,21 @@ import (
)
// 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{
Labels: map[string]string{
"repo": repo.FullName,
"private": strconv.FormatBool(repo.IsSCMPrivate),
},
}
buildCopy := *build
if buildCopy.Procs, err = model.Tree(buildCopy.Procs); err != nil {
pipelineCopy := *pipeline
if pipelineCopy.Procs, err = model.Tree(pipelineCopy.Procs); err != nil {
return err
}
message.Data, _ = json.Marshal(model.Event{
Repo: *repo,
Build: buildCopy,
Repo: *repo,
Pipeline: pipelineCopy,
})
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
import (
@ -9,5 +23,5 @@ import (
type Extension interface {
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
import (
@ -22,9 +36,9 @@ type config struct {
}
type requestStructure struct {
Repo *model.Repo `json:"repo"`
Build *model.Build `json:"build"`
Configuration []*config `json:"configs"`
Repo *model.Repo `json:"repo"`
Pipeline *model.Pipeline `json:"build"`
Configuration []*config `json:"configs"`
}
type responseStructure struct {
@ -39,14 +53,14 @@ func (cp *http) IsConfigured() bool {
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))
for i, pipe := range currentFileMeta {
currentConfigs[i] = &config{Name: pipe.Name, Data: string(pipe.Data)}
}
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)
if err != nil && status != 204 {
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
import (
@ -24,7 +38,7 @@ func (b *builtin) SecretList(repo *model.Repo) ([]*model.Secret, error) {
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)
if err != nil {
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
import (
@ -241,7 +255,7 @@ func (q *fifo) process() {
}
}()
q.resubmitExpiredBuilds()
q.resubmitExpiredPipelines()
q.filterWaiting()
for pending, worker := q.assignToWorker(); pending != nil && worker != nil; pending, worker = q.assignToWorker() {
task := pending.Value.(*Task)
@ -303,7 +317,7 @@ func (q *fifo) assignToWorker() (*list.Element, *worker) {
return nil, nil
}
func (q *fifo) resubmitExpiredBuilds() {
func (q *fifo) resubmitExpiredPipelines() {
for id, state := range q.running {
if time.Now().After(state.deadline) {
q.pending.PushFront(state.item)

View file

@ -1,3 +1,4 @@
// Copyright 2022 Woodpecker Authors
// Copyright 2018 Drone.IO Inc.
//
// 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.
func (c *config) File(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, f string) ([]byte, error) {
config, err := c.newClient(ctx, u).FindSource(r.Owner, r.Name, b.Commit, f)
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, p.Commit, f)
if err != nil {
return nil, 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")
}
// Status creates a build 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 {
status := internal.BuildStatus{
State: convertStatus(build.Status),
Desc: common.GetBuildStatusDescription(build.Status),
// Status creates a pipeline status for the Bitbucket commit.
func (c *config) Status(ctx context.Context, user *model.User, repo *model.Repo, pipeline *model.Pipeline, proc *model.Proc) error {
status := internal.PipelineStatus{
State: convertStatus(pipeline.Status),
Desc: common.GetPipelineStatusDescription(pipeline.Status),
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
@ -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
// Build 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) {
// Pipeline details. If the hook is unsupported nil values are returned.
func (c *config) Hook(ctx context.Context, req *http.Request) (*model.Repo, *model.Pipeline, error) {
return parseHook(req)
}

View file

@ -1,3 +1,4 @@
// Copyright 2022 Woodpecker Authors
// Copyright 2018 Drone.IO Inc.
//
// 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.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(len(raw) != 0).IsTrue()
})
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()
})
})
@ -254,7 +255,7 @@ func Test_bitbucket(t *testing.T) {
})
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()
})
@ -350,7 +351,7 @@ var (
FullName: "test_name/permission_admin",
}
fakeBuild = &model.Build{
fakePipeline = &model.Pipeline{
Commit: "9ecad50",
}

View file

@ -1,3 +1,4 @@
// Copyright 2022 Woodpecker Authors
// Copyright 2018 Drone.IO Inc.
//
// 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
// hook to the Woodpecker build struct holding commit information.
func convertPullHook(from *internal.PullRequestHook) *model.Build {
return &model.Build{
// hook to the Woodpecker pipeline struct holding commit information.
func convertPullHook(from *internal.PullRequestHook) *model.Pipeline {
return &model.Pipeline{
Event: model.EventPull,
Commit: from.PullRequest.Dest.Commit.Hash,
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
// hook to the Woodpecker build struct holding commit information.
func convertPushHook(hook *internal.PushHook, change *internal.Change) *model.Build {
build := &model.Build{
// hook to the Woodpecker pipeline struct holding commit information.
func convertPushHook(hook *internal.PushHook, change *internal.Change) *model.Pipeline {
pipeline := &model.Pipeline{
Commit: change.New.Target.Hash,
Link: change.New.Target.Links.HTML.Href,
Branch: change.New.Name,
@ -165,16 +166,16 @@ func convertPushHook(hook *internal.PushHook, change *internal.Change) *model.Bu
}
switch change.New.Type {
case "tag", "annotated_tag", "bookmark":
build.Event = model.EventTag
build.Ref = fmt.Sprintf("refs/tags/%s", change.New.Name)
pipeline.Event = model.EventTag
pipeline.Ref = fmt.Sprintf("refs/tags/%s", change.New.Name)
default:
build.Event = model.EventPush
build.Ref = fmt.Sprintf("refs/heads/%s", change.New.Name)
pipeline.Event = model.EventPush
pipeline.Ref = fmt.Sprintf("refs/heads/%s", change.New.Name)
}
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>")

View file

@ -1,3 +1,4 @@
// Copyright 2022 Woodpecker Authors
// Copyright 2018 Drone.IO Inc.
//
// 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.It("should convert pull hook to build", func() {
g.It("should convert pull hook to pipeline", func() {
hook := &internal.PullRequestHook{}
hook.Actor.Login = "octocat"
hook.Actor.Links.Avatar.Href = "https://..."
@ -127,21 +128,21 @@ func Test_helper(t *testing.T) {
hook.PullRequest.Desc = "updated README"
hook.PullRequest.Updated = time.Now()
build := convertPullHook(hook)
g.Assert(build.Event).Equal(model.EventPull)
g.Assert(build.Author).Equal(hook.Actor.Login)
g.Assert(build.Avatar).Equal(hook.Actor.Links.Avatar.Href)
g.Assert(build.Commit).Equal(hook.PullRequest.Dest.Commit.Hash)
g.Assert(build.Branch).Equal(hook.PullRequest.Dest.Branch.Name)
g.Assert(build.Link).Equal(hook.PullRequest.Links.HTML.Href)
g.Assert(build.Ref).Equal("refs/heads/master")
g.Assert(build.Refspec).Equal("change:master")
g.Assert(build.Remote).Equal("https://bitbucket.org/baz/bar")
g.Assert(build.Message).Equal(hook.PullRequest.Desc)
g.Assert(build.Timestamp).Equal(hook.PullRequest.Updated.Unix())
pipeline := convertPullHook(hook)
g.Assert(pipeline.Event).Equal(model.EventPull)
g.Assert(pipeline.Author).Equal(hook.Actor.Login)
g.Assert(pipeline.Avatar).Equal(hook.Actor.Links.Avatar.Href)
g.Assert(pipeline.Commit).Equal(hook.PullRequest.Dest.Commit.Hash)
g.Assert(pipeline.Branch).Equal(hook.PullRequest.Dest.Branch.Name)
g.Assert(pipeline.Link).Equal(hook.PullRequest.Links.HTML.Href)
g.Assert(pipeline.Ref).Equal("refs/heads/master")
g.Assert(pipeline.Refspec).Equal("change:master")
g.Assert(pipeline.Remote).Equal("https://bitbucket.org/baz/bar")
g.Assert(pipeline.Message).Equal(hook.PullRequest.Desc)
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.New.Target.Hash = "73f9c44d"
change.New.Name = "master"
@ -154,29 +155,29 @@ func Test_helper(t *testing.T) {
hook.Actor.Login = "octocat"
hook.Actor.Links.Avatar.Href = "https://..."
build := convertPushHook(&hook, &change)
g.Assert(build.Event).Equal(model.EventPush)
g.Assert(build.Email).Equal("test@domain.tld")
g.Assert(build.Author).Equal(hook.Actor.Login)
g.Assert(build.Avatar).Equal(hook.Actor.Links.Avatar.Href)
g.Assert(build.Commit).Equal(change.New.Target.Hash)
g.Assert(build.Branch).Equal(change.New.Name)
g.Assert(build.Link).Equal(change.New.Target.Links.HTML.Href)
g.Assert(build.Ref).Equal("refs/heads/master")
g.Assert(build.Message).Equal(change.New.Target.Message)
g.Assert(build.Timestamp).Equal(change.New.Target.Date.Unix())
pipeline := convertPushHook(&hook, &change)
g.Assert(pipeline.Event).Equal(model.EventPush)
g.Assert(pipeline.Email).Equal("test@domain.tld")
g.Assert(pipeline.Author).Equal(hook.Actor.Login)
g.Assert(pipeline.Avatar).Equal(hook.Actor.Links.Avatar.Href)
g.Assert(pipeline.Commit).Equal(change.New.Target.Hash)
g.Assert(pipeline.Branch).Equal(change.New.Name)
g.Assert(pipeline.Link).Equal(change.New.Target.Links.HTML.Href)
g.Assert(pipeline.Ref).Equal("refs/heads/master")
g.Assert(pipeline.Message).Equal(change.New.Target.Message)
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.New.Name = "v1.0.0"
change.New.Type = "tag"
hook := internal.PushHook{}
build := convertPushHook(&hook, &change)
g.Assert(build.Event).Equal(model.EventTag)
g.Assert(build.Ref).Equal("refs/tags/v1.0.0")
pipeline := convertPushHook(&hook, &change)
g.Assert(pipeline.Event).Equal(model.EventTag)
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)
}
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)
_, err := c.do(uri, post, status, nil)
return err

View file

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

View file

@ -32,8 +32,8 @@ const (
)
// 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.
func parseHook(r *http.Request) (*model.Repo, *model.Build, error) {
// Repo and Pipeline detail. If a hook type is unsupported nil values are returned.
func parseHook(r *http.Request) (*model.Repo, *model.Pipeline, error) {
payload, _ := io.ReadAll(r.Body)
switch r.Header.Get(hookEvent) {
@ -45,9 +45,9 @@ func parseHook(r *http.Request) (*model.Repo, *model.Build, error) {
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.
func parsePushHook(payload []byte) (*model.Repo, *model.Build, error) {
func parsePushHook(payload []byte) (*model.Repo, *model.Pipeline, error) {
hook := internal.PushHook{}
err := json.Unmarshal(payload, &hook)
@ -64,9 +64,9 @@ func parsePushHook(payload []byte) (*model.Repo, *model.Build, error) {
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.
func parsePullHook(payload []byte) (*model.Repo, *model.Build, error) {
func parsePullHook(payload []byte) (*model.Repo, *model.Pipeline, error) {
hook := internal.PullRequestHook{}
if err := json.Unmarshal(payload, &hook); err != nil {

View file

@ -1,3 +1,4 @@
// Copyright 2022 Woodpecker Authors
// Copyright 2018 Drone.IO Inc.
//
// 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)
}
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)
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")
}
// 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 {
status := internal.BuildStatus{
State: convertStatus(build.Status),
Desc: common.GetBuildStatusDescription(build.Status),
Name: fmt.Sprintf("Woodpecker #%d - %s", build.Number, build.Branch),
func (c *Config) Status(ctx context.Context, user *model.User, repo *model.Repo, pipeline *model.Pipeline, proc *model.Proc) error {
status := internal.PipelineStatus{
State: convertStatus(pipeline.Status),
Desc: common.GetPipelineStatusDescription(pipeline.Status),
Name: fmt.Sprintf("Woodpecker #%d - %s", pipeline.Number, pipeline.Branch),
Key: "Woodpecker",
URL: common.GetBuildStatusLink(repo, build, nil),
URL: common.GetPipelineStatusLink(repo, pipeline, nil),
}
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) {
@ -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)
}
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)
}

View file

@ -1,3 +1,4 @@
// Copyright 2022 Woodpecker Authors
// Copyright 2018 Drone.IO Inc.
//
// 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
// hook to the Woodpecker build struct holding commit information.
func convertPushHook(hook *internal.PostHook, baseURL string) *model.Build {
// hook to the Woodpecker pipeline struct holding commit information.
func convertPushHook(hook *internal.PostHook, baseURL string) *model.Pipeline {
branch := strings.TrimPrefix(
strings.TrimPrefix(
hook.RefChanges[0].RefID,
@ -95,7 +96,7 @@ func convertPushHook(hook *internal.PostHook, baseURL string) *model.Build {
authorLabel = authorLabel[0:37] + "..."
}
build := &model.Build{
pipeline := &model.Pipeline{
Commit: hook.RefChanges[0].ToHash, // TODO check for index value
Branch: branch,
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),
}
if strings.HasPrefix(hook.RefChanges[0].RefID, "refs/tags/") {
build.Event = model.EventTag
pipeline.Event = model.EventTag
} 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

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