mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2024-12-24 10:07:21 +02:00
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:
parent
493ec45be6
commit
849e05bb8b
@ -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"]
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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,
|
||||
},
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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 }}
|
||||
`
|
@ -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
|
||||
}
|
@ -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)
|
||||
}
|
@ -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
|
||||
}
|
@ -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 }}
|
||||
`
|
@ -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 }}
|
||||
`
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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 }}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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"),
|
||||
|
@ -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"},
|
||||
|
@ -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 (
|
||||
|
@ -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",
|
||||
|
@ -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
58
cli/pipeline/approve.go
Normal 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
|
||||
}
|
@ -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
58
cli/pipeline/decline.go
Normal 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
87
cli/pipeline/info.go
Normal 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
59
cli/pipeline/kill.go
Normal 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
64
cli/pipeline/last.go
Normal 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)
|
||||
}
|
@ -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
67
cli/pipeline/logs.go
Normal 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
43
cli/pipeline/pipeline.go
Normal 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
94
cli/pipeline/ps.go
Normal 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
76
cli/pipeline/queue.go
Normal 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
82
cli/pipeline/start.go
Normal 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
62
cli/pipeline/stop.go
Normal 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
|
||||
}
|
@ -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 }}
|
||||
|
@ -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 {
|
||||
|
@ -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{
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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 |
|
||||
| |   |
|
||||
| `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 |
|
||||
| |   |
|
||||
| `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:
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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{
|
||||
|
@ -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"]
|
||||
|
@ -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/")
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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');
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
},
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
)
|
||||
|
||||
|
@ -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"))
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
@ -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}
|
||||
}
|
||||
|
@ -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'"`
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
// Copyright 2022 Woodpecker Authors
|
||||
// Copyright 2018 Drone.IO Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -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"`
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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"`
|
||||
}
|
@ -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 {
|
||||
|
@ -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)
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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",
|
||||
}
|
||||
|
||||
|
@ -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>")
|
||||
|
@ -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")
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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"`
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user