mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2024-12-01 14:21:07 +00: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
224 changed files with 4591 additions and 3831 deletions
|
@ -1,3 +1,4 @@
|
||||||
|
// Copyright 2022 Woodpecker Authors
|
||||||
// Copyright 2018 Drone.IO Inc.
|
// Copyright 2018 Drone.IO Inc.
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@ -81,19 +82,19 @@ func (r *Runner) Run(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
repoName := extractRepositoryName(work.Config) // hack
|
repoName := extractRepositoryName(work.Config) // hack
|
||||||
buildNumber := extractBuildNumber(work.Config) // hack
|
pipelineNumber := extractPipelineNumber(work.Config) // hack
|
||||||
|
|
||||||
r.counter.Add(
|
r.counter.Add(
|
||||||
work.ID,
|
work.ID,
|
||||||
timeout,
|
timeout,
|
||||||
repoName,
|
repoName,
|
||||||
buildNumber,
|
pipelineNumber,
|
||||||
)
|
)
|
||||||
defer r.counter.Done(work.ID)
|
defer r.counter.Done(work.ID)
|
||||||
|
|
||||||
logger := log.With().
|
logger := log.With().
|
||||||
Str("repo", repoName).
|
Str("repo", repoName).
|
||||||
Str("build", buildNumber).
|
Str("pipeline", pipelineNumber).
|
||||||
Str("id", work.ID).
|
Str("id", work.ID).
|
||||||
Logger()
|
Logger()
|
||||||
|
|
||||||
|
@ -288,6 +289,10 @@ func (r *Runner) Run(ctx context.Context) error {
|
||||||
|
|
||||||
// TODO: find better way to update this state and move it to pipeline to have the same env in cli-exec
|
// TODO: find better way to update this state and move it to pipeline to have the same env in cli-exec
|
||||||
state.Pipeline.Step.Environment["CI_MACHINE"] = r.hostname
|
state.Pipeline.Step.Environment["CI_MACHINE"] = r.hostname
|
||||||
|
state.Pipeline.Step.Environment["CI_PIPELINE_STATUS"] = "success"
|
||||||
|
state.Pipeline.Step.Environment["CI_PIPELINE_STARTED"] = strconv.FormatInt(state.Pipeline.Time, 10)
|
||||||
|
state.Pipeline.Step.Environment["CI_PIPELINE_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
|
||||||
|
// DEPRECATED
|
||||||
state.Pipeline.Step.Environment["CI_BUILD_STATUS"] = "success"
|
state.Pipeline.Step.Environment["CI_BUILD_STATUS"] = "success"
|
||||||
state.Pipeline.Step.Environment["CI_BUILD_STARTED"] = strconv.FormatInt(state.Pipeline.Time, 10)
|
state.Pipeline.Step.Environment["CI_BUILD_STARTED"] = strconv.FormatInt(state.Pipeline.Time, 10)
|
||||||
state.Pipeline.Step.Environment["CI_BUILD_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
|
state.Pipeline.Step.Environment["CI_BUILD_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
|
||||||
|
@ -299,6 +304,8 @@ func (r *Runner) Run(ctx context.Context) error {
|
||||||
state.Pipeline.Step.Environment["CI_SYSTEM_ARCH"] = runtime.GOOS + "/" + runtime.GOARCH
|
state.Pipeline.Step.Environment["CI_SYSTEM_ARCH"] = runtime.GOOS + "/" + runtime.GOARCH
|
||||||
|
|
||||||
if state.Pipeline.Error != nil {
|
if state.Pipeline.Error != nil {
|
||||||
|
state.Pipeline.Step.Environment["CI_PIPELINE_STATUS"] = "failure"
|
||||||
|
// DEPRECATED
|
||||||
state.Pipeline.Step.Environment["CI_BUILD_STATUS"] = "failure"
|
state.Pipeline.Step.Environment["CI_BUILD_STATUS"] = "failure"
|
||||||
state.Pipeline.Step.Environment["CI_JOB_STATUS"] = "failure"
|
state.Pipeline.Step.Environment["CI_JOB_STATUS"] = "failure"
|
||||||
}
|
}
|
||||||
|
@ -313,7 +320,7 @@ func (r *Runner) Run(ctx context.Context) error {
|
||||||
pipeline.WithDescription(map[string]string{
|
pipeline.WithDescription(map[string]string{
|
||||||
"ID": work.ID,
|
"ID": work.ID,
|
||||||
"Repo": repoName,
|
"Repo": repoName,
|
||||||
"Build": buildNumber,
|
"Pipeline": pipelineNumber,
|
||||||
}),
|
}),
|
||||||
).Run()
|
).Run()
|
||||||
|
|
||||||
|
@ -363,7 +370,7 @@ func extractRepositoryName(config *backend.Config) string {
|
||||||
return config.Stages[0].Steps[0].Environment["CI_REPO"]
|
return config.Stages[0].Steps[0].Environment["CI_REPO"]
|
||||||
}
|
}
|
||||||
|
|
||||||
// extract build number from the configuration
|
// extract pipeline number from the configuration
|
||||||
func extractBuildNumber(config *backend.Config) string {
|
func extractPipelineNumber(config *backend.Config) string {
|
||||||
return config.Stages[0].Steps[0].Environment["CI_BUILD_NUMBER"]
|
return config.Stages[0].Steps[0].Environment["CI_PIPELINE_NUMBER"]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// Copyright 2022 Woodpecker Authors
|
||||||
// Copyright 2018 Drone.IO Inc.
|
// Copyright 2018 Drone.IO Inc.
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@ -31,19 +32,19 @@ type State struct {
|
||||||
type Info struct {
|
type Info struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Repo string `json:"repository"`
|
Repo string `json:"repository"`
|
||||||
Build string `json:"build_number"`
|
Pipeline string `json:"build_number"`
|
||||||
Started time.Time `json:"build_started"`
|
Started time.Time `json:"build_started"`
|
||||||
Timeout time.Duration `json:"build_timeout"`
|
Timeout time.Duration `json:"build_timeout"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *State) Add(id string, timeout time.Duration, repo, build string) {
|
func (s *State) Add(id string, timeout time.Duration, repo, pipeline string) {
|
||||||
s.Lock()
|
s.Lock()
|
||||||
s.Polling--
|
s.Polling--
|
||||||
s.Running++
|
s.Running++
|
||||||
s.Metadata[id] = Info{
|
s.Metadata[id] = Info{
|
||||||
ID: id,
|
ID: id,
|
||||||
Repo: repo,
|
Repo: repo,
|
||||||
Build: build,
|
Pipeline: pipeline,
|
||||||
Timeout: timeout,
|
Timeout: timeout,
|
||||||
Started: time.Now().UTC(),
|
Started: time.Now().UTC(),
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
package cron
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -53,7 +67,7 @@ func cronList(c *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// template for build list information
|
// template for pipeline list information
|
||||||
var tmplCronList = "\x1b[33m{{ .Name }} \x1b[0m" + `
|
var tmplCronList = "\x1b[33m{{ .Name }} \x1b[0m" + `
|
||||||
ID: {{ .ID }}
|
ID: {{ .ID }}
|
||||||
Branch: {{ .Branch }}
|
Branch: {{ .Branch }}
|
||||||
|
|
|
@ -1,3 +1,17 @@
|
||||||
|
// Copyright 2022 Woodpecker Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
package deploy
|
package deploy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -17,7 +31,7 @@ import (
|
||||||
var Command = &cli.Command{
|
var Command = &cli.Command{
|
||||||
Name: "deploy",
|
Name: "deploy",
|
||||||
Usage: "deploy code",
|
Usage: "deploy code",
|
||||||
ArgsUsage: "<repo/name> <build> <environment>",
|
ArgsUsage: "<repo/name> <pipeline> <environment>",
|
||||||
Action: deploy,
|
Action: deploy,
|
||||||
Flags: append(common.GlobalFlags,
|
Flags: append(common.GlobalFlags,
|
||||||
common.FormatFlag(tmplDeployInfo),
|
common.FormatFlag(tmplDeployInfo),
|
||||||
|
@ -60,33 +74,33 @@ func deploy(c *cli.Context) error {
|
||||||
event := c.String("event")
|
event := c.String("event")
|
||||||
status := c.String("status")
|
status := c.String("status")
|
||||||
|
|
||||||
buildArg := c.Args().Get(1)
|
pipelineArg := c.Args().Get(1)
|
||||||
var number int
|
var number int
|
||||||
if buildArg == "last" {
|
if pipelineArg == "last" {
|
||||||
// Fetch the build number from the last build
|
// Fetch the pipeline number from the last pipeline
|
||||||
builds, berr := client.BuildList(owner, name)
|
pipelines, berr := client.PipelineList(owner, name)
|
||||||
if berr != nil {
|
if berr != nil {
|
||||||
return berr
|
return berr
|
||||||
}
|
}
|
||||||
for _, build := range builds {
|
for _, pipeline := range pipelines {
|
||||||
if branch != "" && build.Branch != branch {
|
if branch != "" && pipeline.Branch != branch {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if event != "" && build.Event != event {
|
if event != "" && pipeline.Event != event {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if status != "" && build.Status != status {
|
if status != "" && pipeline.Status != status {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if build.Number > number {
|
if pipeline.Number > number {
|
||||||
number = build.Number
|
number = pipeline.Number
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if number == 0 {
|
if number == 0 {
|
||||||
return fmt.Errorf("Cannot deploy failure build")
|
return fmt.Errorf("Cannot deploy failure pipeline")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
number, err = strconv.Atoi(buildArg)
|
number, err = strconv.Atoi(pipelineArg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,17 @@
|
||||||
|
// Copyright 2022 Woodpecker Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
package exec
|
package exec
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -30,7 +44,7 @@ import (
|
||||||
// Command exports the exec command.
|
// Command exports the exec command.
|
||||||
var Command = &cli.Command{
|
var Command = &cli.Command{
|
||||||
Name: "exec",
|
Name: "exec",
|
||||||
Usage: "execute a local build",
|
Usage: "execute a local pipeline",
|
||||||
ArgsUsage: "[path/to/.woodpecker.yml]",
|
ArgsUsage: "[path/to/.woodpecker.yml]",
|
||||||
Action: run,
|
Action: run,
|
||||||
Flags: append(common.GlobalFlags, flags...),
|
Flags: append(common.GlobalFlags, flags...),
|
||||||
|
@ -231,16 +245,16 @@ func metadataFromContext(c *cli.Context, axis matrix.Axis) frontend.Metadata {
|
||||||
Remote: c.String("repo-remote-url"),
|
Remote: c.String("repo-remote-url"),
|
||||||
Private: c.Bool("repo-private"),
|
Private: c.Bool("repo-private"),
|
||||||
},
|
},
|
||||||
Curr: frontend.Build{
|
Curr: frontend.Pipeline{
|
||||||
Number: c.Int64("build-number"),
|
Number: c.Int64("pipeline-number"),
|
||||||
Parent: c.Int64("parent-build-number"),
|
Parent: c.Int64("pipeline-parent"),
|
||||||
Created: c.Int64("build-created"),
|
Created: c.Int64("pipeline-created"),
|
||||||
Started: c.Int64("build-started"),
|
Started: c.Int64("pipeline-started"),
|
||||||
Finished: c.Int64("build-finished"),
|
Finished: c.Int64("pipeline-finished"),
|
||||||
Status: c.String("build-status"),
|
Status: c.String("pipeline-status"),
|
||||||
Event: c.String("build-event"),
|
Event: c.String("pipeline-event"),
|
||||||
Link: c.String("build-link"),
|
Link: c.String("pipeline-link"),
|
||||||
Target: c.String("build-target"),
|
Target: c.String("pipeline-target"),
|
||||||
Commit: frontend.Commit{
|
Commit: frontend.Commit{
|
||||||
Sha: c.String("commit-sha"),
|
Sha: c.String("commit-sha"),
|
||||||
Ref: c.String("commit-ref"),
|
Ref: c.String("commit-ref"),
|
||||||
|
@ -254,14 +268,14 @@ func metadataFromContext(c *cli.Context, axis matrix.Axis) frontend.Metadata {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Prev: frontend.Build{
|
Prev: frontend.Pipeline{
|
||||||
Number: c.Int64("prev-build-number"),
|
Number: c.Int64("prev-pipeline-number"),
|
||||||
Created: c.Int64("prev-build-created"),
|
Created: c.Int64("prev-pipeline-created"),
|
||||||
Started: c.Int64("prev-build-started"),
|
Started: c.Int64("prev-pipeline-started"),
|
||||||
Finished: c.Int64("prev-build-finished"),
|
Finished: c.Int64("prev-pipeline-finished"),
|
||||||
Status: c.String("prev-build-status"),
|
Status: c.String("prev-pipeline-status"),
|
||||||
Event: c.String("prev-build-event"),
|
Event: c.String("prev-pipeline-event"),
|
||||||
Link: c.String("prev-build-link"),
|
Link: c.String("prev-pipeline-link"),
|
||||||
Commit: frontend.Commit{
|
Commit: frontend.Commit{
|
||||||
Sha: c.String("prev-commit-sha"),
|
Sha: c.String("prev-commit-sha"),
|
||||||
Ref: c.String("prev-commit-ref"),
|
Ref: c.String("prev-commit-ref"),
|
||||||
|
|
|
@ -26,19 +26,19 @@ var flags = []cli.Flag{
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
EnvVars: []string{"WOODPECKER_LOCAL"},
|
EnvVars: []string{"WOODPECKER_LOCAL"},
|
||||||
Name: "local",
|
Name: "local",
|
||||||
Usage: "build from local directory",
|
Usage: "run from local directory",
|
||||||
Value: true,
|
Value: true,
|
||||||
},
|
},
|
||||||
&cli.DurationFlag{
|
&cli.DurationFlag{
|
||||||
EnvVars: []string{"WOODPECKER_TIMEOUT"},
|
EnvVars: []string{"WOODPECKER_TIMEOUT"},
|
||||||
Name: "timeout",
|
Name: "timeout",
|
||||||
Usage: "build timeout",
|
Usage: "pipeline timeout",
|
||||||
Value: time.Hour,
|
Value: time.Hour,
|
||||||
},
|
},
|
||||||
&cli.StringSliceFlag{
|
&cli.StringSliceFlag{
|
||||||
EnvVars: []string{"WOODPECKER_VOLUMES"},
|
EnvVars: []string{"WOODPECKER_VOLUMES"},
|
||||||
Name: "volumes",
|
Name: "volumes",
|
||||||
Usage: "build volumes",
|
Usage: "pipeline volumes",
|
||||||
},
|
},
|
||||||
&cli.StringSliceFlag{
|
&cli.StringSliceFlag{
|
||||||
EnvVars: []string{"WOODPECKER_NETWORKS"},
|
EnvVars: []string{"WOODPECKER_NETWORKS"},
|
||||||
|
@ -131,41 +131,41 @@ var flags = []cli.Flag{
|
||||||
Name: "repo-private",
|
Name: "repo-private",
|
||||||
},
|
},
|
||||||
&cli.IntFlag{
|
&cli.IntFlag{
|
||||||
EnvVars: []string{"CI_BUILD_NUMBER"},
|
EnvVars: []string{"CI_PIPELINE_NUMBER"},
|
||||||
Name: "build-number",
|
Name: "pipeline-number",
|
||||||
},
|
},
|
||||||
&cli.IntFlag{
|
&cli.IntFlag{
|
||||||
EnvVars: []string{"CI_PARENT_BUILD_NUMBER"},
|
EnvVars: []string{"CI_PIPELINE_PARENT"},
|
||||||
Name: "parent-build-number",
|
Name: "pipeline-parent",
|
||||||
},
|
},
|
||||||
&cli.Int64Flag{
|
&cli.Int64Flag{
|
||||||
EnvVars: []string{"CI_BUILD_CREATED"},
|
EnvVars: []string{"CI_PIPELINE_CREATED"},
|
||||||
Name: "build-created",
|
Name: "pipeline-created",
|
||||||
},
|
},
|
||||||
&cli.Int64Flag{
|
&cli.Int64Flag{
|
||||||
EnvVars: []string{"CI_BUILD_STARTED"},
|
EnvVars: []string{"CI_PIPELINE_STARTED"},
|
||||||
Name: "build-started",
|
Name: "pipeline-started",
|
||||||
},
|
},
|
||||||
&cli.Int64Flag{
|
&cli.Int64Flag{
|
||||||
EnvVars: []string{"CI_BUILD_FINISHED"},
|
EnvVars: []string{"CI_PIPELINE_FINISHED"},
|
||||||
Name: "build-finished",
|
Name: "pipeline-finished",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_BUILD_STATUS"},
|
EnvVars: []string{"CI_PIPELINE_STATUS"},
|
||||||
Name: "build-status",
|
Name: "pipeline-status",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_BUILD_EVENT"},
|
EnvVars: []string{"CI_PIPELINE_EVENT"},
|
||||||
Name: "build-event",
|
Name: "pipeline-event",
|
||||||
Value: "manual",
|
Value: "manual",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_BUILD_LINK"},
|
EnvVars: []string{"CI_PIPELINE_LINK"},
|
||||||
Name: "build-link",
|
Name: "pipeline-link",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_BUILD_TARGET"},
|
EnvVars: []string{"CI_PIPELINE_TARGET"},
|
||||||
Name: "build-target",
|
Name: "pipeline-target",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_COMMIT_SHA"},
|
EnvVars: []string{"CI_COMMIT_SHA"},
|
||||||
|
@ -200,32 +200,32 @@ var flags = []cli.Flag{
|
||||||
Name: "commit-author-email",
|
Name: "commit-author-email",
|
||||||
},
|
},
|
||||||
&cli.IntFlag{
|
&cli.IntFlag{
|
||||||
EnvVars: []string{"CI_PREV_BUILD_NUMBER"},
|
EnvVars: []string{"CI_PREV_PIPELINE_NUMBER"},
|
||||||
Name: "prev-build-number",
|
Name: "prev-pipeline-number",
|
||||||
},
|
},
|
||||||
&cli.Int64Flag{
|
&cli.Int64Flag{
|
||||||
EnvVars: []string{"CI_PREV_BUILD_CREATED"},
|
EnvVars: []string{"CI_PREV_PIPELINE_CREATED"},
|
||||||
Name: "prev-build-created",
|
Name: "prev-pipeline-created",
|
||||||
},
|
},
|
||||||
&cli.Int64Flag{
|
&cli.Int64Flag{
|
||||||
EnvVars: []string{"CI_PREV_BUILD_STARTED"},
|
EnvVars: []string{"CI_PREV_PIPELINE_STARTED"},
|
||||||
Name: "prev-build-started",
|
Name: "prev-pipeline-started",
|
||||||
},
|
},
|
||||||
&cli.Int64Flag{
|
&cli.Int64Flag{
|
||||||
EnvVars: []string{"CI_PREV_BUILD_FINISHED"},
|
EnvVars: []string{"CI_PREV_PIPELINE_FINISHED"},
|
||||||
Name: "prev-build-finished",
|
Name: "prev-pipeline-finished",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_PREV_BUILD_STATUS"},
|
EnvVars: []string{"CI_PREV_PIPELINE_STATUS"},
|
||||||
Name: "prev-build-status",
|
Name: "prev-pipeline-status",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_PREV_BUILD_EVENT"},
|
EnvVars: []string{"CI_PREV_PIPELINE_EVENT"},
|
||||||
Name: "prev-build-event",
|
Name: "prev-pipeline-event",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_PREV_BUILD_LINK"},
|
EnvVars: []string{"CI_PREV_PIPELINE_LINK"},
|
||||||
Name: "prev-build-link",
|
Name: "prev-pipeline-link",
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
EnvVars: []string{"CI_PREV_COMMIT_SHA"},
|
EnvVars: []string{"CI_PREV_COMMIT_SHA"},
|
||||||
|
|
|
@ -1,3 +1,17 @@
|
||||||
|
// Copyright 2022 Woodpecker Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
package exec
|
package exec
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
@ -1,3 +1,17 @@
|
||||||
|
// Copyright 2022 Woodpecker Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
package log
|
package log
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -6,7 +20,7 @@ import (
|
||||||
"github.com/woodpecker-ci/woodpecker/cli/common"
|
"github.com/woodpecker-ci/woodpecker/cli/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Command exports the build command set.
|
// Command exports the log command set.
|
||||||
var Command = &cli.Command{
|
var Command = &cli.Command{
|
||||||
Name: "log",
|
Name: "log",
|
||||||
Usage: "manage logs",
|
Usage: "manage logs",
|
||||||
|
|
|
@ -1,3 +1,17 @@
|
||||||
|
// Copyright 2022 Woodpecker Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
package log
|
package log
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -13,7 +27,7 @@ import (
|
||||||
var logPurgeCmd = &cli.Command{
|
var logPurgeCmd = &cli.Command{
|
||||||
Name: "purge",
|
Name: "purge",
|
||||||
Usage: "purge a log",
|
Usage: "purge a log",
|
||||||
ArgsUsage: "<repo/name> <build>",
|
ArgsUsage: "<repo/name> <pipeline>",
|
||||||
Action: logPurge,
|
Action: logPurge,
|
||||||
Flags: common.GlobalFlags,
|
Flags: common.GlobalFlags,
|
||||||
}
|
}
|
||||||
|
@ -39,6 +53,6 @@ func logPurge(c *cli.Context) (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Purging logs for build %s/%s#%d\n", owner, name, number)
|
fmt.Printf("Purging logs for pipeline %s/%s#%d\n", owner, name, number)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
58
cli/pipeline/approve.go
Normal file
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 (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
@ -13,16 +27,16 @@ import (
|
||||||
"github.com/woodpecker-ci/woodpecker/cli/internal"
|
"github.com/woodpecker-ci/woodpecker/cli/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
var buildCreateCmd = &cli.Command{
|
var pipelineCreateCmd = &cli.Command{
|
||||||
Name: "create",
|
Name: "create",
|
||||||
Usage: "create new build",
|
Usage: "create new pipeline",
|
||||||
ArgsUsage: "<repo/name>",
|
ArgsUsage: "<repo/name>",
|
||||||
Action: buildCreate,
|
Action: pipelineCreate,
|
||||||
Flags: append(common.GlobalFlags,
|
Flags: append(common.GlobalFlags,
|
||||||
common.FormatFlag(tmplBuildList),
|
common.FormatFlag(tmplPipelineList),
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "branch",
|
Name: "branch",
|
||||||
Usage: "branch to create build from",
|
Usage: "branch to create pipeline from",
|
||||||
Required: true,
|
Required: true,
|
||||||
},
|
},
|
||||||
&cli.StringSliceFlag{
|
&cli.StringSliceFlag{
|
||||||
|
@ -32,7 +46,7 @@ var buildCreateCmd = &cli.Command{
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildCreate(c *cli.Context) error {
|
func pipelineCreate(c *cli.Context) error {
|
||||||
repo := c.Args().First()
|
repo := c.Args().First()
|
||||||
|
|
||||||
owner, name, err := internal.ParseRepo(repo)
|
owner, name, err := internal.ParseRepo(repo)
|
||||||
|
@ -55,12 +69,12 @@ func buildCreate(c *cli.Context) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
options := &woodpecker.BuildOptions{
|
options := &woodpecker.PipelineOptions{
|
||||||
Branch: branch,
|
Branch: branch,
|
||||||
Variables: variables,
|
Variables: variables,
|
||||||
}
|
}
|
||||||
|
|
||||||
build, err := client.BuildCreate(owner, name, options)
|
pipeline, err := client.PipelineCreate(owner, name, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -70,7 +84,7 @@ func buildCreate(c *cli.Context) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := tmpl.Execute(os.Stdout, build); err != nil {
|
if err := tmpl.Execute(os.Stdout, pipeline); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
58
cli/pipeline/decline.go
Normal file
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 (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
@ -10,13 +24,13 @@ import (
|
||||||
"github.com/woodpecker-ci/woodpecker/cli/internal"
|
"github.com/woodpecker-ci/woodpecker/cli/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
var buildListCmd = &cli.Command{
|
var pipelineListCmd = &cli.Command{
|
||||||
Name: "ls",
|
Name: "ls",
|
||||||
Usage: "show build history",
|
Usage: "show pipeline history",
|
||||||
ArgsUsage: "<repo/name>",
|
ArgsUsage: "<repo/name>",
|
||||||
Action: buildList,
|
Action: pipelineList,
|
||||||
Flags: append(common.GlobalFlags,
|
Flags: append(common.GlobalFlags,
|
||||||
common.FormatFlag(tmplBuildList),
|
common.FormatFlag(tmplPipelineList),
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "branch",
|
Name: "branch",
|
||||||
Usage: "branch filter",
|
Usage: "branch filter",
|
||||||
|
@ -37,7 +51,7 @@ var buildListCmd = &cli.Command{
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildList(c *cli.Context) error {
|
func pipelineList(c *cli.Context) error {
|
||||||
repo := c.Args().First()
|
repo := c.Args().First()
|
||||||
owner, name, err := internal.ParseRepo(repo)
|
owner, name, err := internal.ParseRepo(repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -49,7 +63,7 @@ func buildList(c *cli.Context) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
builds, err := client.BuildList(owner, name)
|
pipelines, err := client.PipelineList(owner, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -65,20 +79,20 @@ func buildList(c *cli.Context) error {
|
||||||
limit := c.Int("limit")
|
limit := c.Int("limit")
|
||||||
|
|
||||||
var count int
|
var count int
|
||||||
for _, build := range builds {
|
for _, pipeline := range pipelines {
|
||||||
if count >= limit {
|
if count >= limit {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if branch != "" && build.Branch != branch {
|
if branch != "" && pipeline.Branch != branch {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if event != "" && build.Event != event {
|
if event != "" && pipeline.Event != event {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if status != "" && build.Status != status {
|
if status != "" && pipeline.Status != status {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err := tmpl.Execute(os.Stdout, build); err != nil {
|
if err := tmpl.Execute(os.Stdout, pipeline); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
count++
|
count++
|
||||||
|
@ -86,8 +100,8 @@ func buildList(c *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// template for build list information
|
// template for pipeline list information
|
||||||
var tmplBuildList = "\x1b[33mBuild #{{ .Number }} \x1b[0m" + `
|
var tmplPipelineList = "\x1b[33mBuild #{{ .Number }} \x1b[0m" + `
|
||||||
Status: {{ .Status }}
|
Status: {{ .Status }}
|
||||||
Event: {{ .Event }}
|
Event: {{ .Event }}
|
||||||
Commit: {{ .Commit }}
|
Commit: {{ .Commit }}
|
67
cli/pipeline/logs.go
Normal file
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
|
package registry
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -53,7 +67,7 @@ func registryList(c *cli.Context) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// template for build list information
|
// template for registry list information
|
||||||
var tmplRegistryList = "\x1b[33m{{ .Address }} \x1b[0m" + `
|
var tmplRegistryList = "\x1b[33m{{ .Address }} \x1b[0m" + `
|
||||||
Username: {{ .Username }}
|
Username: {{ .Username }}
|
||||||
Email: {{ .Email }}
|
Email: {{ .Email }}
|
||||||
|
|
|
@ -1,3 +1,17 @@
|
||||||
|
// Copyright 2022 Woodpecker Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
package repo
|
package repo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -38,12 +52,12 @@ var repoUpdateCmd = &cli.Command{
|
||||||
Usage: "repository configuration path (e.g. .woodpecker.yml)",
|
Usage: "repository configuration path (e.g. .woodpecker.yml)",
|
||||||
},
|
},
|
||||||
&cli.IntFlag{
|
&cli.IntFlag{
|
||||||
Name: "build-counter",
|
Name: "pipeline-counter",
|
||||||
Usage: "repository starting build number",
|
Usage: "repository starting pipeline number",
|
||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "unsafe",
|
Name: "unsafe",
|
||||||
Usage: "validate updating the build-counter is unsafe",
|
Usage: "validate updating the pipeline-counter is unsafe",
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
@ -66,7 +80,7 @@ func repoUpdate(c *cli.Context) error {
|
||||||
timeout = c.Duration("timeout")
|
timeout = c.Duration("timeout")
|
||||||
trusted = c.Bool("trusted")
|
trusted = c.Bool("trusted")
|
||||||
gated = c.Bool("gated")
|
gated = c.Bool("gated")
|
||||||
buildCounter = c.Int("build-counter")
|
pipelineCounter = c.Int("pipeline-counter")
|
||||||
unsafe = c.Bool("unsafe")
|
unsafe = c.Bool("unsafe")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -90,11 +104,11 @@ func repoUpdate(c *cli.Context) error {
|
||||||
patch.Visibility = &visibility
|
patch.Visibility = &visibility
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if c.IsSet("build-counter") && !unsafe {
|
if c.IsSet("pipeline-counter") && !unsafe {
|
||||||
fmt.Printf("Setting the build counter is an unsafe operation that could put your repository in an inconsistent state. Please use --unsafe to proceed")
|
fmt.Printf("Setting the pipeline counter is an unsafe operation that could put your repository in an inconsistent state. Please use --unsafe to proceed")
|
||||||
}
|
}
|
||||||
if c.IsSet("build-counter") && unsafe {
|
if c.IsSet("pipeline-counter") && unsafe {
|
||||||
patch.BuildCounter = &buildCounter
|
patch.PipelineCounter = &pipelineCounter
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := client.RepoPatch(owner, name, patch); err != nil {
|
if _, err := client.RepoPatch(owner, name, patch); err != nil {
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// Copyright 2022 Woodpecker Authors
|
||||||
// Copyright 2019 Laszlo Fogas
|
// Copyright 2019 Laszlo Fogas
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@ -80,7 +81,7 @@ var flags = []cli.Flag{
|
||||||
&cli.IntFlag{
|
&cli.IntFlag{
|
||||||
EnvVars: []string{"WOODPECKER_MAX_PROCS"},
|
EnvVars: []string{"WOODPECKER_MAX_PROCS"},
|
||||||
Name: "max-procs",
|
Name: "max-procs",
|
||||||
Usage: "agent parallel builds",
|
Usage: "agent parallel workflows",
|
||||||
Value: 1,
|
Value: 1,
|
||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
|
|
|
@ -21,7 +21,6 @@ import (
|
||||||
zlog "github.com/rs/zerolog/log"
|
zlog "github.com/rs/zerolog/log"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
|
||||||
"github.com/woodpecker-ci/woodpecker/cli/build"
|
|
||||||
"github.com/woodpecker-ci/woodpecker/cli/common"
|
"github.com/woodpecker-ci/woodpecker/cli/common"
|
||||||
"github.com/woodpecker-ci/woodpecker/cli/cron"
|
"github.com/woodpecker-ci/woodpecker/cli/cron"
|
||||||
"github.com/woodpecker-ci/woodpecker/cli/deploy"
|
"github.com/woodpecker-ci/woodpecker/cli/deploy"
|
||||||
|
@ -30,6 +29,7 @@ import (
|
||||||
"github.com/woodpecker-ci/woodpecker/cli/lint"
|
"github.com/woodpecker-ci/woodpecker/cli/lint"
|
||||||
"github.com/woodpecker-ci/woodpecker/cli/log"
|
"github.com/woodpecker-ci/woodpecker/cli/log"
|
||||||
"github.com/woodpecker-ci/woodpecker/cli/loglevel"
|
"github.com/woodpecker-ci/woodpecker/cli/loglevel"
|
||||||
|
"github.com/woodpecker-ci/woodpecker/cli/pipeline"
|
||||||
"github.com/woodpecker-ci/woodpecker/cli/registry"
|
"github.com/woodpecker-ci/woodpecker/cli/registry"
|
||||||
"github.com/woodpecker-ci/woodpecker/cli/repo"
|
"github.com/woodpecker-ci/woodpecker/cli/repo"
|
||||||
"github.com/woodpecker-ci/woodpecker/cli/secret"
|
"github.com/woodpecker-ci/woodpecker/cli/secret"
|
||||||
|
@ -46,7 +46,7 @@ func newApp() *cli.App {
|
||||||
app.EnableBashCompletion = true
|
app.EnableBashCompletion = true
|
||||||
app.Flags = common.GlobalFlags
|
app.Flags = common.GlobalFlags
|
||||||
app.Commands = []*cli.Command{
|
app.Commands = []*cli.Command{
|
||||||
build.Command,
|
pipeline.Command,
|
||||||
log.Command,
|
log.Command,
|
||||||
deploy.Command,
|
deploy.Command,
|
||||||
exec.Command,
|
exec.Command,
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// Copyright 2022 Woodpecker Authors
|
||||||
// Copyright 2018 Drone.IO Inc.
|
// Copyright 2018 Drone.IO Inc.
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@ -61,7 +62,7 @@ func setupStore(c *cli.Context) (store.Store, error) {
|
||||||
if datastore.SupportedDriver("sqlite3") {
|
if datastore.SupportedDriver("sqlite3") {
|
||||||
log.Debug().Msgf("server has sqlite3 support")
|
log.Debug().Msgf("server has sqlite3 support")
|
||||||
} else {
|
} else {
|
||||||
log.Debug().Msgf("server was build with no sqlite3 support!")
|
log.Debug().Msgf("server was built without sqlite3 support!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,27 +307,27 @@ func setupMetrics(g *errgroup.Group, _store store.Store) {
|
||||||
pendingJobs := promauto.NewGauge(prometheus.GaugeOpts{
|
pendingJobs := promauto.NewGauge(prometheus.GaugeOpts{
|
||||||
Namespace: "woodpecker",
|
Namespace: "woodpecker",
|
||||||
Name: "pending_jobs",
|
Name: "pending_jobs",
|
||||||
Help: "Total number of pending build processes.",
|
Help: "Total number of pending pipeline processes.",
|
||||||
})
|
})
|
||||||
waitingJobs := promauto.NewGauge(prometheus.GaugeOpts{
|
waitingJobs := promauto.NewGauge(prometheus.GaugeOpts{
|
||||||
Namespace: "woodpecker",
|
Namespace: "woodpecker",
|
||||||
Name: "waiting_jobs",
|
Name: "waiting_jobs",
|
||||||
Help: "Total number of builds waiting on deps.",
|
Help: "Total number of pipeline waiting on deps.",
|
||||||
})
|
})
|
||||||
runningJobs := promauto.NewGauge(prometheus.GaugeOpts{
|
runningJobs := promauto.NewGauge(prometheus.GaugeOpts{
|
||||||
Namespace: "woodpecker",
|
Namespace: "woodpecker",
|
||||||
Name: "running_jobs",
|
Name: "running_jobs",
|
||||||
Help: "Total number of running build processes.",
|
Help: "Total number of running pipeline processes.",
|
||||||
})
|
})
|
||||||
workers := promauto.NewGauge(prometheus.GaugeOpts{
|
workers := promauto.NewGauge(prometheus.GaugeOpts{
|
||||||
Namespace: "woodpecker",
|
Namespace: "woodpecker",
|
||||||
Name: "worker_count",
|
Name: "worker_count",
|
||||||
Help: "Total number of workers.",
|
Help: "Total number of workers.",
|
||||||
})
|
})
|
||||||
builds := promauto.NewGauge(prometheus.GaugeOpts{
|
pipelines := promauto.NewGauge(prometheus.GaugeOpts{
|
||||||
Namespace: "woodpecker",
|
Namespace: "woodpecker",
|
||||||
Name: "build_total_count",
|
Name: "pipeline_total_count",
|
||||||
Help: "Total number of builds.",
|
Help: "Total number of pipelines.",
|
||||||
})
|
})
|
||||||
users := promauto.NewGauge(prometheus.GaugeOpts{
|
users := promauto.NewGauge(prometheus.GaugeOpts{
|
||||||
Namespace: "woodpecker",
|
Namespace: "woodpecker",
|
||||||
|
@ -353,8 +354,8 @@ func setupMetrics(g *errgroup.Group, _store store.Store) {
|
||||||
for {
|
for {
|
||||||
repoCount, _ := _store.GetRepoCount()
|
repoCount, _ := _store.GetRepoCount()
|
||||||
userCount, _ := _store.GetUserCount()
|
userCount, _ := _store.GetUserCount()
|
||||||
buildCount, _ := _store.GetBuildCount()
|
pipelineCount, _ := _store.GetPipelineCount()
|
||||||
builds.Set(float64(buildCount))
|
pipelines.Set(float64(pipelineCount))
|
||||||
users.Set(float64(userCount))
|
users.Set(float64(userCount))
|
||||||
repos.Set(float64(repoCount))
|
repos.Set(float64(repoCount))
|
||||||
time.Sleep(10 * time.Second)
|
time.Sleep(10 * time.Second)
|
||||||
|
|
|
@ -23,7 +23,7 @@ pipeline:
|
||||||
- echo "Testing.."
|
- echo "Testing.."
|
||||||
```
|
```
|
||||||
|
|
||||||
### Build steps are containers
|
### Pipeline steps are containers
|
||||||
|
|
||||||
- Define any container image as context
|
- Define any container image as context
|
||||||
- either use your own and install the needed tools in custom image or
|
- either use your own and install the needed tools in custom image or
|
||||||
|
|
|
@ -47,7 +47,7 @@ pipeline:
|
||||||
This is the reference list of all environment variables available to your pipeline containers. These are injected into your pipeline step and plugins containers, at runtime.
|
This is the reference list of all environment variables available to your pipeline containers. These are injected into your pipeline step and plugins containers, at runtime.
|
||||||
|
|
||||||
| NAME | Description |
|
| NAME | Description |
|
||||||
|--------------------------------|----------------------------------------------------------------------------------------------|
|
|----------------------------------|----------------------------------------------------------------------------------------------|
|
||||||
| `CI=woodpecker` | environment is woodpecker |
|
| `CI=woodpecker` | environment is woodpecker |
|
||||||
| | **Repository** |
|
| | **Repository** |
|
||||||
| `CI_REPO` | repository full name `<owner>/<name>` |
|
| `CI_REPO` | repository full name `<owner>/<name>` |
|
||||||
|
@ -73,16 +73,16 @@ This is the reference list of all environment variables available to your pipeli
|
||||||
| `CI_COMMIT_AUTHOR` | commit author username |
|
| `CI_COMMIT_AUTHOR` | commit author username |
|
||||||
| `CI_COMMIT_AUTHOR_EMAIL` | commit author email address |
|
| `CI_COMMIT_AUTHOR_EMAIL` | commit author email address |
|
||||||
| `CI_COMMIT_AUTHOR_AVATAR` | commit author avatar |
|
| `CI_COMMIT_AUTHOR_AVATAR` | commit author avatar |
|
||||||
| | **Current build** |
|
| | **Current pipeline** |
|
||||||
| `CI_BUILD_NUMBER` | build number |
|
| `CI_PIPELINE_NUMBER` | pipeline number |
|
||||||
| `CI_BUILD_PARENT` | build number of parent build |
|
| `CI_PIPELINE_PARENT` | number of parent pipeline |
|
||||||
| `CI_BUILD_EVENT` | build event (push, pull_request, tag, deployment) |
|
| `CI_PIPELINE_EVENT` | pipeline event (push, pull_request, tag, deployment) |
|
||||||
| `CI_BUILD_LINK` | build link in CI |
|
| `CI_PIPELINE_LINK` | pipeline link in CI |
|
||||||
| `CI_BUILD_DEPLOY_TARGET` | build deploy target for `deployment` events (i.e. production) |
|
| `CI_PIPELINE_DEPLOY_TARGET` | pipeline deploy target for `deployment` events (ie production) |
|
||||||
| `CI_BUILD_STATUS` | build status (success, failure) |
|
| `CI_PIPELINE_STATUS` | pipeline status (success, failure) |
|
||||||
| `CI_BUILD_CREATED` | build created UNIX timestamp |
|
| `CI_PIPELINE_CREATED` | pipeline created UNIX timestamp |
|
||||||
| `CI_BUILD_STARTED` | build started UNIX timestamp |
|
| `CI_PIPELINE_STARTED` | pipeline started UNIX timestamp |
|
||||||
| `CI_BUILD_FINISHED` | build finished UNIX timestamp |
|
| `CI_PIPELINE_FINISHED` | pipeline finished UNIX timestamp |
|
||||||
| | **Current job** |
|
| | **Current job** |
|
||||||
| `CI_JOB_NUMBER` | job number |
|
| `CI_JOB_NUMBER` | job number |
|
||||||
| `CI_JOB_STATUS` | job status (success, failure) |
|
| `CI_JOB_STATUS` | job status (success, failure) |
|
||||||
|
@ -100,16 +100,16 @@ This is the reference list of all environment variables available to your pipeli
|
||||||
| `CI_PREV_COMMIT_AUTHOR` | previous commit author username |
|
| `CI_PREV_COMMIT_AUTHOR` | previous commit author username |
|
||||||
| `CI_PREV_COMMIT_AUTHOR_EMAIL` | previous commit author email address |
|
| `CI_PREV_COMMIT_AUTHOR_EMAIL` | previous commit author email address |
|
||||||
| `CI_PREV_COMMIT_AUTHOR_AVATAR` | previous commit author avatar |
|
| `CI_PREV_COMMIT_AUTHOR_AVATAR` | previous commit author avatar |
|
||||||
| | **Previous build** |
|
| | **Previous pipeline** |
|
||||||
| `CI_PREV_BUILD_NUMBER` | previous build number |
|
| `CI_PREV_PIPELINE_NUMBER` | previous pipeline number |
|
||||||
| `CI_PREV_BUILD_PARENT` | previous build number of parent build |
|
| `CI_PREV_PIPELINE_PARENT` | previous pipeline number of parent pipeline |
|
||||||
| `CI_PREV_BUILD_EVENT` | previous build event (push, pull_request, tag, deployment) |
|
| `CI_PREV_PIPELINE_EVENT` | previous pipeline event (push, pull_request, tag, deployment) |
|
||||||
| `CI_PREV_BUILD_LINK` | previous build link in CI |
|
| `CI_PREV_PIPELINE_LINK` | previous pipeline link in CI |
|
||||||
| `CI_PREV_BUILD_DEPLOY_TARGET` | previous build deploy target for `deployment` events (i.e. production) |
|
| `CI_PREV_PIPELINE_DEPLOY_TARGET` | previous pipeline deploy target for `deployment` events (ie production) |
|
||||||
| `CI_PREV_BUILD_STATUS` | previous build status (success, failure) |
|
| `CI_PREV_PIPELINE_STATUS` | previous pipeline status (success, failure) |
|
||||||
| `CI_PREV_BUILD_CREATED` | previous build created UNIX timestamp |
|
| `CI_PREV_PIPELINE_CREATED` | previous pipeline created UNIX timestamp |
|
||||||
| `CI_PREV_BUILD_STARTED` | previous build started UNIX timestamp |
|
| `CI_PREV_PIPELINE_STARTED` | previous pipeline started UNIX timestamp |
|
||||||
| `CI_PREV_BUILD_FINISHED` | previous build finished UNIX timestamp |
|
| `CI_PREV_PIPELINE_FINISHED` | previous pipeline finished UNIX timestamp |
|
||||||
| |   |
|
| |   |
|
||||||
| `CI_WORKSPACE` | Path of the workspace where source code gets cloned to |
|
| `CI_WORKSPACE` | Path of the workspace where source code gets cloned to |
|
||||||
| | **System** |
|
| | **System** |
|
||||||
|
@ -125,7 +125,7 @@ This is the reference list of all environment variables available to your pipeli
|
||||||
|
|
||||||
## Global environment variables
|
## Global environment variables
|
||||||
|
|
||||||
If you want specific environment variables to be available in all of your builds use the `WOODPECKER_ENVIRONMENT` setting on the Woodpecker server. Note that these can't overwrite any existing, built-in variables.
|
If you want specific environment variables to be available in all of your pipelines use the `WOODPECKER_ENVIRONMENT` setting on the Woodpecker server. Note that these can't overwrite any existing, built-in variables.
|
||||||
|
|
||||||
```diff
|
```diff
|
||||||
services:
|
services:
|
||||||
|
@ -152,7 +152,7 @@ pipeline:
|
||||||
|
|
||||||
## String Substitution
|
## String Substitution
|
||||||
|
|
||||||
Woodpecker provides the ability to substitute environment variables at runtime. This gives us the ability to use dynamic build or commit details in our pipeline configuration.
|
Woodpecker provides the ability to substitute environment variables at runtime. This gives us the ability to use dynamic settings, commands and filters in our pipeline configuration.
|
||||||
|
|
||||||
Example commit substitution:
|
Example commit substitution:
|
||||||
|
|
||||||
|
|
|
@ -35,16 +35,16 @@ scrape_configs:
|
||||||
List of Prometheus metrics specific to Woodpecker:
|
List of Prometheus metrics specific to Woodpecker:
|
||||||
|
|
||||||
```
|
```
|
||||||
# HELP woodpecker_build_count Build count.
|
# HELP woodpecker_pipeline_count Build count.
|
||||||
# TYPE woodpecker_build_count counter
|
# TYPE woodpecker_pipeline_count counter
|
||||||
woodpecker_build_count{branch="master",pipeline="total",repo="woodpecker-ci/woodpecker",status="success"} 3
|
woodpecker_build_count{branch="master",pipeline="total",repo="woodpecker-ci/woodpecker",status="success"} 3
|
||||||
woodpecker_build_count{branch="mkdocs",pipeline="total",repo="woodpecker-ci/woodpecker",status="success"} 3
|
woodpecker_build_count{branch="mkdocs",pipeline="total",repo="woodpecker-ci/woodpecker",status="success"} 3
|
||||||
# HELP woodpecker_build_time Build time.
|
# HELP woodpecker_pipeline_time Build time.
|
||||||
# TYPE woodpecker_build_time gauge
|
# TYPE woodpecker_pipeline_time gauge
|
||||||
woodpecker_build_time{branch="master",pipeline="total",repo="woodpecker-ci/woodpecker",status="success"} 116
|
woodpecker_build_time{branch="master",pipeline="total",repo="woodpecker-ci/woodpecker",status="success"} 116
|
||||||
woodpecker_build_time{branch="mkdocs",pipeline="total",repo="woodpecker-ci/woodpecker",status="success"} 155
|
woodpecker_build_time{branch="mkdocs",pipeline="total",repo="woodpecker-ci/woodpecker",status="success"} 155
|
||||||
# HELP woodpecker_build_total_count Total number of builds.
|
# HELP woodpecker_pipeline_total_count Total number of builds.
|
||||||
# TYPE woodpecker_build_total_count gauge
|
# TYPE woodpecker_pipeline_total_count gauge
|
||||||
woodpecker_build_total_count 1025
|
woodpecker_build_total_count 1025
|
||||||
# HELP woodpecker_pending_jobs Total number of pending build processes.
|
# HELP woodpecker_pending_jobs Total number of pending build processes.
|
||||||
# TYPE woodpecker_pending_jobs gauge
|
# TYPE woodpecker_pending_jobs gauge
|
||||||
|
|
|
@ -7,6 +7,9 @@ Some versions need some changes to the server configuration or the pipeline conf
|
||||||
- The signature used to verify extensions calls (like those used for the [config-extension](./30-administration/100-external-configuration-api.md)) done by the Woodpecker server switched from using a shared-secret HMac to an ed25519 key-pair. Read more about it at the [config-extensions](./30-administration/100-external-configuration-api.md) documentation.
|
- The signature used to verify extensions calls (like those used for the [config-extension](./30-administration/100-external-configuration-api.md)) done by the Woodpecker server switched from using a shared-secret HMac to an ed25519 key-pair. Read more about it at the [config-extensions](./30-administration/100-external-configuration-api.md) documentation.
|
||||||
- Refactored support of old agent filter labels and expression. Learn how to use the new [filter](./20-usage/20-pipeline-syntax.md#labels)
|
- Refactored support of old agent filter labels and expression. Learn how to use the new [filter](./20-usage/20-pipeline-syntax.md#labels)
|
||||||
- Renamed step environment variable `CI_SYSTEM_ARCH` to `CI_SYSTEM_PLATFORM`. Same applies for the cli exec variable.
|
- Renamed step environment variable `CI_SYSTEM_ARCH` to `CI_SYSTEM_PLATFORM`. Same applies for the cli exec variable.
|
||||||
|
- Renamed environment variables `CI_BUILD_*` and `CI_PREV_BUILD_*` to `CI_PIPELINE_*` and `CI_PREV_PIPELINE_*`, old ones are still available but deprecated
|
||||||
|
- Renamed API endpoints for pipelines (`<owner>/<repo>/builds/<buildId>` -> `<owner>/<repo>/pipelines/<pipelineId>`), old ones are still available but deprecated
|
||||||
|
- Updated Prometheus gauge `build_*` to `pipeline_*`
|
||||||
|
|
||||||
## 0.15.0
|
## 0.15.0
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,17 @@
|
||||||
|
// Copyright 2022 Woodpecker Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
package local
|
package local
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -99,7 +113,7 @@ func (e *local) Wait(context.Context, *types.Step) (*types.State, error) {
|
||||||
ExitCode := 0
|
ExitCode := 0
|
||||||
if eerr, ok := err.(*exec.ExitError); ok {
|
if eerr, ok := err.(*exec.ExitError); ok {
|
||||||
ExitCode = eerr.ExitCode()
|
ExitCode = eerr.ExitCode()
|
||||||
// Non-zero exit code is a build failure, but not an agent error.
|
// Non-zero exit code is a pipeline failure, but not an agent error.
|
||||||
err = nil
|
err = nil
|
||||||
}
|
}
|
||||||
return &types.State{
|
return &types.State{
|
||||||
|
|
|
@ -22,15 +22,15 @@ func (m *Metadata) setDroneEnviron(env map[string]string) {
|
||||||
env["DRONE_TAG"] = env["CI_COMMIT_TAG"]
|
env["DRONE_TAG"] = env["CI_COMMIT_TAG"]
|
||||||
env["DRONE_SOURCE_BRANCH"] = env["CI_COMMIT_SOURCE_BRANCH"]
|
env["DRONE_SOURCE_BRANCH"] = env["CI_COMMIT_SOURCE_BRANCH"]
|
||||||
env["DRONE_TARGET_BRANCH"] = env["CI_COMMIT_TARGET_BRANCH"]
|
env["DRONE_TARGET_BRANCH"] = env["CI_COMMIT_TARGET_BRANCH"]
|
||||||
// build
|
// pipeline
|
||||||
env["DRONE_BUILD_NUMBER"] = env["CI_BUILD_NUMBER"]
|
env["DRONE_BUILD_NUMBER"] = env["CI_PIPELINE_NUMBER"]
|
||||||
env["DRONE_BUILD_PARENT"] = env["CI_BUILD_PARENT"]
|
env["DRONE_BUILD_PARENT"] = env["CI_PIPELINE_PARENT"]
|
||||||
env["DRONE_BUILD_EVENT"] = env["CI_BUILD_EVENT"]
|
env["DRONE_BUILD_EVENT"] = env["CI_PIPELINE_EVENT"]
|
||||||
env["DRONE_BUILD_STATUS"] = env["CI_BUILD_STATUS"]
|
env["DRONE_BUILD_STATUS"] = env["CI_PIPELINE_STATUS"]
|
||||||
env["DRONE_BUILD_LINK"] = env["CI_BUILD_LINK"]
|
env["DRONE_BUILD_LINK"] = env["CI_PIPELINE_LINK"]
|
||||||
env["DRONE_BUILD_CREATED"] = env["CI_BUILD_CREATED"]
|
env["DRONE_BUILD_CREATED"] = env["CI_PIPELINE_CREATED"]
|
||||||
env["DRONE_BUILD_STARTED"] = env["CI_BUILD_STARTED"]
|
env["DRONE_BUILD_STARTED"] = env["CI_PIPELINE_STARTED"]
|
||||||
env["DRONE_BUILD_FINISHED"] = env["CI_BUILD_FINISHED"]
|
env["DRONE_BUILD_FINISHED"] = env["CI_PIPELINE_FINISHED"]
|
||||||
// commit
|
// commit
|
||||||
env["DRONE_COMMIT"] = env["CI_COMMIT_SHA"]
|
env["DRONE_COMMIT"] = env["CI_COMMIT_SHA"]
|
||||||
env["DRONE_COMMIT_BEFORE"] = env["CI_PREV_COMMIT_SHA"]
|
env["DRONE_COMMIT_BEFORE"] = env["CI_PREV_COMMIT_SHA"]
|
||||||
|
|
|
@ -37,8 +37,8 @@ type (
|
||||||
Metadata struct {
|
Metadata struct {
|
||||||
ID string `json:"id,omitempty"`
|
ID string `json:"id,omitempty"`
|
||||||
Repo Repo `json:"repo,omitempty"`
|
Repo Repo `json:"repo,omitempty"`
|
||||||
Curr Build `json:"curr,omitempty"`
|
Curr Pipeline `json:"curr,omitempty"`
|
||||||
Prev Build `json:"prev,omitempty"`
|
Prev Pipeline `json:"prev,omitempty"`
|
||||||
Job Job `json:"job,omitempty"`
|
Job Job `json:"job,omitempty"`
|
||||||
Sys System `json:"sys,omitempty"`
|
Sys System `json:"sys,omitempty"`
|
||||||
}
|
}
|
||||||
|
@ -53,8 +53,8 @@ type (
|
||||||
Branch string `json:"default_branch,omitempty"`
|
Branch string `json:"default_branch,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build defines runtime metadata for a build.
|
// Pipeline defines runtime metadata for a pipeline.
|
||||||
Build struct {
|
Pipeline struct {
|
||||||
Number int64 `json:"number,omitempty"`
|
Number int64 `json:"number,omitempty"`
|
||||||
Created int64 `json:"created,omitempty"`
|
Created int64 `json:"created,omitempty"`
|
||||||
Started int64 `json:"started,omitempty"`
|
Started int64 `json:"started,omitempty"`
|
||||||
|
@ -161,15 +161,15 @@ func (m *Metadata) Environ() map[string]string {
|
||||||
"CI_COMMIT_TAG": "", // will be set if event is tag
|
"CI_COMMIT_TAG": "", // will be set if event is tag
|
||||||
"CI_COMMIT_PULL_REQUEST": "", // will be set if event is pr
|
"CI_COMMIT_PULL_REQUEST": "", // will be set if event is pr
|
||||||
|
|
||||||
"CI_BUILD_NUMBER": strconv.FormatInt(m.Curr.Number, 10),
|
"CI_PIPELINE_NUMBER": strconv.FormatInt(m.Curr.Number, 10),
|
||||||
"CI_BUILD_PARENT": strconv.FormatInt(m.Curr.Parent, 10),
|
"CI_PIPELINE_PARENT": strconv.FormatInt(m.Curr.Parent, 10),
|
||||||
"CI_BUILD_EVENT": m.Curr.Event,
|
"CI_PIPELINE_EVENT": m.Curr.Event,
|
||||||
"CI_BUILD_LINK": m.Curr.Link,
|
"CI_PIPELINE_LINK": m.Curr.Link,
|
||||||
"CI_BUILD_DEPLOY_TARGET": m.Curr.Target,
|
"CI_PIPELINE_DEPLOY_TARGET": m.Curr.Target,
|
||||||
"CI_BUILD_STATUS": m.Curr.Status,
|
"CI_PIPELINE_STATUS": m.Curr.Status,
|
||||||
"CI_BUILD_CREATED": strconv.FormatInt(m.Curr.Created, 10),
|
"CI_PIPELINE_CREATED": strconv.FormatInt(m.Curr.Created, 10),
|
||||||
"CI_BUILD_STARTED": strconv.FormatInt(m.Curr.Started, 10),
|
"CI_PIPELINE_STARTED": strconv.FormatInt(m.Curr.Started, 10),
|
||||||
"CI_BUILD_FINISHED": strconv.FormatInt(m.Curr.Finished, 10),
|
"CI_PIPELINE_FINISHED": strconv.FormatInt(m.Curr.Finished, 10),
|
||||||
|
|
||||||
"CI_JOB_NUMBER": strconv.Itoa(m.Job.Number),
|
"CI_JOB_NUMBER": strconv.Itoa(m.Job.Number),
|
||||||
"CI_JOB_STATUS": "", // will be set by agent
|
"CI_JOB_STATUS": "", // will be set by agent
|
||||||
|
@ -186,15 +186,15 @@ func (m *Metadata) Environ() map[string]string {
|
||||||
"CI_PREV_COMMIT_AUTHOR_EMAIL": m.Prev.Commit.Author.Email,
|
"CI_PREV_COMMIT_AUTHOR_EMAIL": m.Prev.Commit.Author.Email,
|
||||||
"CI_PREV_COMMIT_AUTHOR_AVATAR": m.Prev.Commit.Author.Avatar,
|
"CI_PREV_COMMIT_AUTHOR_AVATAR": m.Prev.Commit.Author.Avatar,
|
||||||
|
|
||||||
"CI_PREV_BUILD_NUMBER": strconv.FormatInt(m.Prev.Number, 10),
|
"CI_PREV_PIPELINE_NUMBER": strconv.FormatInt(m.Prev.Number, 10),
|
||||||
"CI_PREV_BUILD_PARENT": strconv.FormatInt(m.Prev.Parent, 10),
|
"CI_PREV_PIPELINE_PARENT": strconv.FormatInt(m.Prev.Parent, 10),
|
||||||
"CI_PREV_BUILD_EVENT": m.Prev.Event,
|
"CI_PREV_PIPELINE_EVENT": m.Prev.Event,
|
||||||
"CI_PREV_BUILD_LINK": m.Prev.Link,
|
"CI_PREV_PIPELINE_LINK": m.Prev.Link,
|
||||||
"CI_PREV_BUILD_DEPLOY_TARGET": m.Prev.Target,
|
"CI_PREV_PIPELINE_DEPLOY_TARGET": m.Prev.Target,
|
||||||
"CI_PREV_BUILD_STATUS": m.Prev.Status,
|
"CI_PREV_PIPELINE_STATUS": m.Prev.Status,
|
||||||
"CI_PREV_BUILD_CREATED": strconv.FormatInt(m.Prev.Created, 10),
|
"CI_PREV_PIPELINE_CREATED": strconv.FormatInt(m.Prev.Created, 10),
|
||||||
"CI_PREV_BUILD_STARTED": strconv.FormatInt(m.Prev.Started, 10),
|
"CI_PREV_PIPELINE_STARTED": strconv.FormatInt(m.Prev.Started, 10),
|
||||||
"CI_PREV_BUILD_FINISHED": strconv.FormatInt(m.Prev.Finished, 10),
|
"CI_PREV_PIPELINE_FINISHED": strconv.FormatInt(m.Prev.Finished, 10),
|
||||||
|
|
||||||
"CI_SYSTEM_NAME": m.Sys.Name,
|
"CI_SYSTEM_NAME": m.Sys.Name,
|
||||||
"CI_SYSTEM_LINK": m.Sys.Link,
|
"CI_SYSTEM_LINK": m.Sys.Link,
|
||||||
|
@ -204,6 +204,26 @@ func (m *Metadata) Environ() map[string]string {
|
||||||
|
|
||||||
// DEPRECATED
|
// DEPRECATED
|
||||||
"CI_SYSTEM_ARCH": m.Sys.Platform, // TODO: remove after v1.0.x version
|
"CI_SYSTEM_ARCH": m.Sys.Platform, // TODO: remove after v1.0.x version
|
||||||
|
// use CI_PIPELINE_*
|
||||||
|
"CI_BUILD_NUMBER": strconv.FormatInt(m.Curr.Number, 10),
|
||||||
|
"CI_BUILD_PARENT": strconv.FormatInt(m.Curr.Parent, 10),
|
||||||
|
"CI_BUILD_EVENT": m.Curr.Event,
|
||||||
|
"CI_BUILD_LINK": m.Curr.Link,
|
||||||
|
"CI_BUILD_DEPLOY_TARGET": m.Curr.Target,
|
||||||
|
"CI_BUILD_STATUS": m.Curr.Status,
|
||||||
|
"CI_BUILD_CREATED": strconv.FormatInt(m.Curr.Created, 10),
|
||||||
|
"CI_BUILD_STARTED": strconv.FormatInt(m.Curr.Started, 10),
|
||||||
|
"CI_BUILD_FINISHED": strconv.FormatInt(m.Curr.Finished, 10),
|
||||||
|
// use CI_PREV_PIPELINE_*
|
||||||
|
"CI_PREV_BUILD_NUMBER": strconv.FormatInt(m.Prev.Number, 10),
|
||||||
|
"CI_PREV_BUILD_PARENT": strconv.FormatInt(m.Prev.Parent, 10),
|
||||||
|
"CI_PREV_BUILD_EVENT": m.Prev.Event,
|
||||||
|
"CI_PREV_BUILD_LINK": m.Prev.Link,
|
||||||
|
"CI_PREV_BUILD_DEPLOY_TARGET": m.Prev.Target,
|
||||||
|
"CI_PREV_BUILD_STATUS": m.Prev.Status,
|
||||||
|
"CI_PREV_BUILD_CREATED": strconv.FormatInt(m.Prev.Created, 10),
|
||||||
|
"CI_PREV_BUILD_STARTED": strconv.FormatInt(m.Prev.Started, 10),
|
||||||
|
"CI_PREV_BUILD_FINISHED": strconv.FormatInt(m.Prev.Finished, 10),
|
||||||
}
|
}
|
||||||
if m.Curr.Event == EventTag {
|
if m.Curr.Event == EventTag {
|
||||||
params["CI_COMMIT_TAG"] = strings.TrimPrefix(m.Curr.Commit.Ref, "refs/tags/")
|
params["CI_COMMIT_TAG"] = strings.TrimPrefix(m.Curr.Commit.Ref, "refs/tags/")
|
||||||
|
|
|
@ -1,3 +1,17 @@
|
||||||
|
// Copyright 2022 Woodpecker Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
package compiler
|
package compiler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -49,7 +63,7 @@ func WithSecret(secrets ...Secret) Option {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithMetadata configures the compiler with the repository, build
|
// WithMetadata configures the compiler with the repository, pipeline
|
||||||
// and system metadata. The metadata is used to remove steps from
|
// and system metadata. The metadata is used to remove steps from
|
||||||
// the compiled pipeline configuration that should be skipped. The
|
// the compiled pipeline configuration that should be skipped. The
|
||||||
// metadata is also added to each container as environment variables.
|
// metadata is also added to each container as environment variables.
|
||||||
|
@ -76,7 +90,7 @@ func WithNetrc(username, password, machine string) Option {
|
||||||
// WithWorkspace configures the compiler with the workspace base
|
// WithWorkspace configures the compiler with the workspace base
|
||||||
// and path. The workspace base is a volume created at runtime and
|
// and path. The workspace base is a volume created at runtime and
|
||||||
// mounted into all containers in the pipeline. The base and path
|
// mounted into all containers in the pipeline. The base and path
|
||||||
// are joined to provide the working directory for all build and
|
// are joined to provide the working directory for all pipeline and
|
||||||
// plugin steps in the pipeline.
|
// plugin steps in the pipeline.
|
||||||
func WithWorkspace(base, path string) Option {
|
func WithWorkspace(base, path string) Option {
|
||||||
return func(compiler *Compiler) {
|
return func(compiler *Compiler) {
|
||||||
|
@ -177,7 +191,7 @@ func WithProxy() Option {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithNetworks configures the compiler with additional networks
|
// WithNetworks configures the compiler with additional networks
|
||||||
// to be connected to build containers
|
// to be connected to pipeline containers
|
||||||
func WithNetworks(networks ...string) Option {
|
func WithNetworks(networks ...string) Option {
|
||||||
return func(compiler *Compiler) {
|
return func(compiler *Compiler) {
|
||||||
compiler.networks = networks
|
compiler.networks = networks
|
||||||
|
|
|
@ -1,3 +1,17 @@
|
||||||
|
// Copyright 2022 Woodpecker Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
package compiler
|
package compiler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -7,7 +21,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// generateScriptPosix is a helper function that generates a build script
|
// generateScriptPosix is a helper function that generates a step script
|
||||||
// for a linux container using the given
|
// for a linux container using the given
|
||||||
func generateScriptPosix(commands []string) string {
|
func generateScriptPosix(commands []string) string {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
|
@ -27,7 +41,7 @@ func generateScriptPosix(commands []string) string {
|
||||||
return base64.StdEncoding.EncodeToString([]byte(script))
|
return base64.StdEncoding.EncodeToString([]byte(script))
|
||||||
}
|
}
|
||||||
|
|
||||||
// setupScript is a helper script this is added to the build to ensure
|
// setupScript is a helper script this is added to the step script to ensure
|
||||||
// a minimum set of environment variables are set correctly.
|
// a minimum set of environment variables are set correctly.
|
||||||
const setupScript = `
|
const setupScript = `
|
||||||
if [ -n "$CI_NETRC_MACHINE" ]; then
|
if [ -n "$CI_NETRC_MACHINE" ]; then
|
||||||
|
@ -44,7 +58,7 @@ unset CI_SCRIPT
|
||||||
%s
|
%s
|
||||||
`
|
`
|
||||||
|
|
||||||
// traceScript is a helper script that is added to the build script
|
// traceScript is a helper script that is added to the step script
|
||||||
// to trace a command.
|
// to trace a command.
|
||||||
const traceScript = `
|
const traceScript = `
|
||||||
echo + %s
|
echo + %s
|
||||||
|
|
|
@ -1,3 +1,17 @@
|
||||||
|
// Copyright 2022 Woodpecker Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
package compiler
|
package compiler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -39,7 +53,7 @@ $netrc=[string]::Format("{0}\_netrc",$Env:HOME);
|
||||||
%s
|
%s
|
||||||
`
|
`
|
||||||
|
|
||||||
// traceScript is a helper script that is added to the build script
|
// traceScript is a helper script that is added to the step script
|
||||||
// to trace a command.
|
// to trace a command.
|
||||||
const traceScriptWin = `
|
const traceScriptWin = `
|
||||||
Write-Output ('+ %s');
|
Write-Output ('+ %s');
|
||||||
|
|
|
@ -80,7 +80,7 @@ func TestParse(t *testing.T) {
|
||||||
|
|
||||||
g.It("Should match event tester", func() {
|
g.It("Should match event tester", func() {
|
||||||
match, err := matchConfig.When.Match(frontend.Metadata{
|
match, err := matchConfig.When.Match(frontend.Metadata{
|
||||||
Curr: frontend.Build{
|
Curr: frontend.Pipeline{
|
||||||
Event: "tester",
|
Event: "tester",
|
||||||
},
|
},
|
||||||
}, false)
|
}, false)
|
||||||
|
@ -90,7 +90,7 @@ func TestParse(t *testing.T) {
|
||||||
|
|
||||||
g.It("Should match event tester2", func() {
|
g.It("Should match event tester2", func() {
|
||||||
match, err := matchConfig.When.Match(frontend.Metadata{
|
match, err := matchConfig.When.Match(frontend.Metadata{
|
||||||
Curr: frontend.Build{
|
Curr: frontend.Pipeline{
|
||||||
Event: "tester2",
|
Event: "tester2",
|
||||||
},
|
},
|
||||||
}, false)
|
}, false)
|
||||||
|
@ -100,7 +100,7 @@ func TestParse(t *testing.T) {
|
||||||
|
|
||||||
g.It("Should match branch tester", func() {
|
g.It("Should match branch tester", func() {
|
||||||
match, err := matchConfig.When.Match(frontend.Metadata{
|
match, err := matchConfig.When.Match(frontend.Metadata{
|
||||||
Curr: frontend.Build{
|
Curr: frontend.Pipeline{
|
||||||
Commit: frontend.Commit{
|
Commit: frontend.Commit{
|
||||||
Branch: "tester",
|
Branch: "tester",
|
||||||
},
|
},
|
||||||
|
@ -112,7 +112,7 @@ func TestParse(t *testing.T) {
|
||||||
|
|
||||||
g.It("Should not match event push", func() {
|
g.It("Should not match event push", func() {
|
||||||
match, err := matchConfig.When.Match(frontend.Metadata{
|
match, err := matchConfig.When.Match(frontend.Metadata{
|
||||||
Curr: frontend.Build{
|
Curr: frontend.Pipeline{
|
||||||
Event: "push",
|
Event: "push",
|
||||||
},
|
},
|
||||||
}, false)
|
}, false)
|
||||||
|
|
|
@ -392,7 +392,7 @@ func TestConstraints(t *testing.T) {
|
||||||
desc: "no constraints, must match on default events",
|
desc: "no constraints, must match on default events",
|
||||||
conf: "",
|
conf: "",
|
||||||
with: frontend.Metadata{
|
with: frontend.Metadata{
|
||||||
Curr: frontend.Build{
|
Curr: frontend.Pipeline{
|
||||||
Event: frontend.EventPush,
|
Event: frontend.EventPush,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -401,99 +401,99 @@ func TestConstraints(t *testing.T) {
|
||||||
{
|
{
|
||||||
desc: "global branch filter",
|
desc: "global branch filter",
|
||||||
conf: "{ branch: develop }",
|
conf: "{ branch: develop }",
|
||||||
with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventPush, Commit: frontend.Commit{Branch: "master"}}},
|
with: frontend.Metadata{Curr: frontend.Pipeline{Event: frontend.EventPush, Commit: frontend.Commit{Branch: "master"}}},
|
||||||
want: false,
|
want: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "global branch filter",
|
desc: "global branch filter",
|
||||||
conf: "{ branch: master }",
|
conf: "{ branch: master }",
|
||||||
with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventPush, Commit: frontend.Commit{Branch: "master"}}},
|
with: frontend.Metadata{Curr: frontend.Pipeline{Event: frontend.EventPush, Commit: frontend.Commit{Branch: "master"}}},
|
||||||
want: true,
|
want: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "repo constraint",
|
desc: "repo constraint",
|
||||||
conf: "{ repo: owner/* }",
|
conf: "{ repo: owner/* }",
|
||||||
with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventPush}, Repo: frontend.Repo{Name: "owner/repo"}},
|
with: frontend.Metadata{Curr: frontend.Pipeline{Event: frontend.EventPush}, Repo: frontend.Repo{Name: "owner/repo"}},
|
||||||
want: true,
|
want: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "repo constraint",
|
desc: "repo constraint",
|
||||||
conf: "{ repo: octocat/* }",
|
conf: "{ repo: octocat/* }",
|
||||||
with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventPush}, Repo: frontend.Repo{Name: "owner/repo"}},
|
with: frontend.Metadata{Curr: frontend.Pipeline{Event: frontend.EventPush}, Repo: frontend.Repo{Name: "owner/repo"}},
|
||||||
want: false,
|
want: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "ref constraint",
|
desc: "ref constraint",
|
||||||
conf: "{ ref: refs/tags/* }",
|
conf: "{ ref: refs/tags/* }",
|
||||||
with: frontend.Metadata{Curr: frontend.Build{Commit: frontend.Commit{Ref: "refs/tags/v1.0.0"}, Event: frontend.EventPush}},
|
with: frontend.Metadata{Curr: frontend.Pipeline{Commit: frontend.Commit{Ref: "refs/tags/v1.0.0"}, Event: frontend.EventPush}},
|
||||||
want: true,
|
want: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "ref constraint",
|
desc: "ref constraint",
|
||||||
conf: "{ ref: refs/tags/* }",
|
conf: "{ ref: refs/tags/* }",
|
||||||
with: frontend.Metadata{Curr: frontend.Build{Commit: frontend.Commit{Ref: "refs/heads/master"}, Event: frontend.EventPush}},
|
with: frontend.Metadata{Curr: frontend.Pipeline{Commit: frontend.Commit{Ref: "refs/heads/master"}, Event: frontend.EventPush}},
|
||||||
want: false,
|
want: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "platform constraint",
|
desc: "platform constraint",
|
||||||
conf: "{ platform: linux/amd64 }",
|
conf: "{ platform: linux/amd64 }",
|
||||||
with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventPush}, Sys: frontend.System{Platform: "linux/amd64"}},
|
with: frontend.Metadata{Curr: frontend.Pipeline{Event: frontend.EventPush}, Sys: frontend.System{Platform: "linux/amd64"}},
|
||||||
want: true,
|
want: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "platform constraint",
|
desc: "platform constraint",
|
||||||
conf: "{ repo: linux/amd64 }",
|
conf: "{ repo: linux/amd64 }",
|
||||||
with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventPush}, Sys: frontend.System{Platform: "windows/amd64"}},
|
with: frontend.Metadata{Curr: frontend.Pipeline{Event: frontend.EventPush}, Sys: frontend.System{Platform: "windows/amd64"}},
|
||||||
want: false,
|
want: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "instance constraint",
|
desc: "instance constraint",
|
||||||
conf: "{ instance: agent.tld }",
|
conf: "{ instance: agent.tld }",
|
||||||
with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventPush}, Sys: frontend.System{Host: "agent.tld"}},
|
with: frontend.Metadata{Curr: frontend.Pipeline{Event: frontend.EventPush}, Sys: frontend.System{Host: "agent.tld"}},
|
||||||
want: true,
|
want: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "instance constraint",
|
desc: "instance constraint",
|
||||||
conf: "{ instance: agent.tld }",
|
conf: "{ instance: agent.tld }",
|
||||||
with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventPush}, Sys: frontend.System{Host: "beta.agent.tld"}},
|
with: frontend.Metadata{Curr: frontend.Pipeline{Event: frontend.EventPush}, Sys: frontend.System{Host: "beta.agent.tld"}},
|
||||||
want: false,
|
want: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "filter cron by default constraint",
|
desc: "filter cron by default constraint",
|
||||||
conf: "{}",
|
conf: "{}",
|
||||||
with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventCron}},
|
with: frontend.Metadata{Curr: frontend.Pipeline{Event: frontend.EventCron}},
|
||||||
want: false,
|
want: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "filter cron by matching name",
|
desc: "filter cron by matching name",
|
||||||
conf: "{ event: cron, cron: job1 }",
|
conf: "{ event: cron, cron: job1 }",
|
||||||
with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventCron, Cron: "job1"}},
|
with: frontend.Metadata{Curr: frontend.Pipeline{Event: frontend.EventCron, Cron: "job1"}},
|
||||||
want: true,
|
want: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "filter cron by name",
|
desc: "filter cron by name",
|
||||||
conf: "{ event: cron, cron: job2 }",
|
conf: "{ event: cron, cron: job2 }",
|
||||||
with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventCron, Cron: "job1"}},
|
with: frontend.Metadata{Curr: frontend.Pipeline{Event: frontend.EventCron, Cron: "job1"}},
|
||||||
want: false,
|
want: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "no constraints, event gets filtered by default event filter",
|
desc: "no constraints, event gets filtered by default event filter",
|
||||||
conf: "",
|
conf: "",
|
||||||
with: frontend.Metadata{
|
with: frontend.Metadata{
|
||||||
Curr: frontend.Build{Event: "non-default"},
|
Curr: frontend.Pipeline{Event: "non-default"},
|
||||||
},
|
},
|
||||||
want: false,
|
want: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "filter by eval based on event",
|
desc: "filter by eval based on event",
|
||||||
conf: `{ evaluate: 'CI_BUILD_EVENT == "push"' }`,
|
conf: `{ evaluate: 'CI_PIPELINE_EVENT == "push"' }`,
|
||||||
with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventPush}},
|
with: frontend.Metadata{Curr: frontend.Pipeline{Event: frontend.EventPush}},
|
||||||
want: true,
|
want: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "filter by eval based on event and repo",
|
desc: "filter by eval based on event and repo",
|
||||||
conf: `{ evaluate: 'CI_BUILD_EVENT == "push" && CI_REPO == "owner/repo"' }`,
|
conf: `{ evaluate: 'CI_PIPELINE_EVENT == "push" && CI_REPO == "owner/repo"' }`,
|
||||||
with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventPush}, Repo: frontend.Repo{Name: "owner/repo"}},
|
with: frontend.Metadata{Curr: frontend.Pipeline{Event: frontend.EventPush}, Repo: frontend.Repo{Name: "owner/repo"}},
|
||||||
want: true,
|
want: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,17 @@
|
||||||
|
// Copyright 2022 Woodpecker Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
package matrix
|
package matrix
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -13,10 +27,10 @@ const (
|
||||||
limitAxis = 25
|
limitAxis = 25
|
||||||
)
|
)
|
||||||
|
|
||||||
// Matrix represents the build matrix.
|
// Matrix represents the pipeline matrix.
|
||||||
type Matrix map[string][]string
|
type Matrix map[string][]string
|
||||||
|
|
||||||
// Axis represents a single permutation of entries from the build matrix.
|
// Axis represents a single permutation of entries from the pipeline matrix.
|
||||||
type Axis map[string]string
|
type Axis map[string]string
|
||||||
|
|
||||||
// String returns a string representation of an Axis as a comma-separated list
|
// String returns a string representation of an Axis as a comma-separated list
|
||||||
|
@ -79,7 +93,7 @@ func calc(matrix Matrix) []Axis {
|
||||||
elem := p / decr % len(elems)
|
elem := p / decr % len(elems)
|
||||||
axis[tag] = elems[elem]
|
axis[tag] = elems[elem]
|
||||||
|
|
||||||
// enforce a maximum number of tags in the build matrix.
|
// enforce a maximum number of tags in the pipeline matrix.
|
||||||
if i > limitTags {
|
if i > limitTags {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.28.0
|
// protoc-gen-go v1.28.1
|
||||||
// protoc v3.12.4
|
// protoc v3.12.4
|
||||||
// source: woodpecker.proto
|
// source: woodpecker.proto
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,10 @@ var DefaultTracer = TraceFunc(func(state *State) error {
|
||||||
if state.Pipeline.Step.Environment == nil {
|
if state.Pipeline.Step.Environment == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
state.Pipeline.Step.Environment["CI_PIPELINE_STATUS"] = "success"
|
||||||
|
state.Pipeline.Step.Environment["CI_PIPELINE_STARTED"] = strconv.FormatInt(state.Pipeline.Time, 10)
|
||||||
|
state.Pipeline.Step.Environment["CI_PIPELINE_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
|
||||||
|
// DEPRECATED
|
||||||
state.Pipeline.Step.Environment["CI_BUILD_STATUS"] = "success"
|
state.Pipeline.Step.Environment["CI_BUILD_STATUS"] = "success"
|
||||||
state.Pipeline.Step.Environment["CI_BUILD_STARTED"] = strconv.FormatInt(state.Pipeline.Time, 10)
|
state.Pipeline.Step.Environment["CI_BUILD_STARTED"] = strconv.FormatInt(state.Pipeline.Time, 10)
|
||||||
state.Pipeline.Step.Environment["CI_BUILD_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
|
state.Pipeline.Step.Environment["CI_BUILD_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
|
||||||
|
@ -38,7 +42,10 @@ var DefaultTracer = TraceFunc(func(state *State) error {
|
||||||
state.Pipeline.Step.Environment["CI_JOB_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
|
state.Pipeline.Step.Environment["CI_JOB_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
|
||||||
|
|
||||||
if state.Pipeline.Error != nil {
|
if state.Pipeline.Error != nil {
|
||||||
|
state.Pipeline.Step.Environment["CI_PIPELINE_STATUS"] = "failure"
|
||||||
|
// DEPRECATED
|
||||||
state.Pipeline.Step.Environment["CI_BUILD_STATUS"] = "failure"
|
state.Pipeline.Step.Environment["CI_BUILD_STATUS"] = "failure"
|
||||||
|
|
||||||
state.Pipeline.Step.Environment["CI_JOB_STATUS"] = "failure"
|
state.Pipeline.Step.Environment["CI_JOB_STATUS"] = "failure"
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// Copyright 2018 Drone.IO Inc.
|
// Copyright 2022 Woodpecker Authors
|
||||||
// Copyright 2021 Informatyka Boguslawski sp. z o.o. sp.k., http://www.ib.pl/
|
// Copyright 2021 Informatyka Boguslawski sp. z o.o. sp.k., http://www.ib.pl/
|
||||||
|
// Copyright 2018 Drone.IO Inc.
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
|
@ -47,15 +48,15 @@ func GetBadge(c *gin.Context) {
|
||||||
branch = repo.Branch
|
branch = repo.Branch
|
||||||
}
|
}
|
||||||
|
|
||||||
build, err := _store.GetBuildLast(repo, branch)
|
pipeline, err := _store.GetPipelineLast(repo, branch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn().Err(err).Msg("")
|
log.Warn().Err(err).Msg("")
|
||||||
build = nil
|
pipeline = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// we serve an SVG, so set content type appropriately.
|
// we serve an SVG, so set content type appropriately.
|
||||||
c.Writer.Header().Set("Content-Type", "image/svg+xml")
|
c.Writer.Header().Set("Content-Type", "image/svg+xml")
|
||||||
c.String(http.StatusOK, badges.Generate(build))
|
c.String(http.StatusOK, badges.Generate(pipeline))
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetCC(c *gin.Context) {
|
func GetCC(c *gin.Context) {
|
||||||
|
@ -66,13 +67,13 @@ func GetCC(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
builds, err := _store.GetBuildList(repo, 1)
|
pipelines, err := _store.GetPipelineList(repo, 1)
|
||||||
if err != nil || len(builds) == 0 {
|
if err != nil || len(pipelines) == 0 {
|
||||||
c.AbortWithStatus(404)
|
c.AbortWithStatus(404)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
url := fmt.Sprintf("%s/%s/%d", server.Config.Server.Host, repo.FullName, builds[0].Number)
|
url := fmt.Sprintf("%s/%s/%d", server.Config.Server.Host, repo.FullName, pipelines[0].Number)
|
||||||
cc := ccmenu.New(repo, builds[0], url)
|
cc := ccmenu.New(repo, pipelines[0], url)
|
||||||
c.XML(200, cc)
|
c.XML(200, cc)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// Copyright 2022 Woodpecker Authors
|
||||||
// Copyright 2018 Drone.IO Inc.
|
// Copyright 2018 Drone.IO Inc.
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@ -27,7 +28,7 @@ import (
|
||||||
"github.com/woodpecker-ci/woodpecker/server/store"
|
"github.com/woodpecker-ci/woodpecker/server/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FileList gets a list file by build.
|
// FileList gets a list file by pipeline.
|
||||||
func FileList(c *gin.Context) {
|
func FileList(c *gin.Context) {
|
||||||
_store := store.FromContext(c)
|
_store := store.FromContext(c)
|
||||||
num, err := strconv.ParseInt(c.Param("number"), 10, 64)
|
num, err := strconv.ParseInt(c.Param("number"), 10, 64)
|
||||||
|
@ -37,13 +38,13 @@ func FileList(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
repo := session.Repo(c)
|
repo := session.Repo(c)
|
||||||
build, err := _store.GetBuildNumber(repo, num)
|
pipeline, err := _store.GetPipelineNumber(repo, num)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
files, err := _store.FileList(build)
|
files, err := _store.FileList(pipeline)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
|
@ -76,13 +77,13 @@ func FileGet(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
build, err := _store.GetBuildNumber(repo, num)
|
pipeline, err := _store.GetPipelineNumber(repo, num)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
proc, err := _store.ProcFind(build, pid)
|
proc, err := _store.ProcFind(pipeline, pid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// Copyright 2018 Drone.IO Inc.
|
// Copyright 2022 Woodpecker Authors
|
||||||
// Copyright 2021 Informatyka Boguslawski sp. z o.o. sp.k., http://www.ib.pl/
|
// Copyright 2021 Informatyka Boguslawski sp. z o.o. sp.k., http://www.ib.pl/
|
||||||
|
// Copyright 2018 Drone.IO Inc.
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
|
@ -79,7 +80,7 @@ func PostHook(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if tmpBuild == nil {
|
if tmpBuild == nil {
|
||||||
msg := "ignoring hook: hook parsing resulted in empty build"
|
msg := "ignoring hook: hook parsing resulted in empty pipeline"
|
||||||
log.Debug().Msg(msg)
|
log.Debug().Msg(msg)
|
||||||
c.String(http.StatusOK, msg)
|
c.String(http.StatusOK, msg)
|
||||||
return
|
return
|
||||||
|
@ -174,10 +175,10 @@ func PostHook(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
build, err := pipeline.Create(c, _store, repo, tmpBuild)
|
pl, err := pipeline.Create(c, _store, repo, tmpBuild)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
handlePipelineErr(c, err)
|
handlePipelineErr(c, err)
|
||||||
} else {
|
} else {
|
||||||
c.JSON(200, build)
|
c.JSON(200, pl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// Copyright 2018 Drone.IO Inc.
|
// Copyright 2022 Woodpecker Authors
|
||||||
// Copyright 2021 Informatyka Boguslawski sp. z o.o. sp.k., http://www.ib.pl/
|
// Copyright 2021 Informatyka Boguslawski sp. z o.o. sp.k., http://www.ib.pl/
|
||||||
|
// Copyright 2018 Drone.IO Inc.
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
|
@ -37,11 +38,11 @@ import (
|
||||||
"github.com/woodpecker-ci/woodpecker/server/store"
|
"github.com/woodpecker-ci/woodpecker/server/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
func CreateBuild(c *gin.Context) {
|
func CreatePipeline(c *gin.Context) {
|
||||||
_store := store.FromContext(c)
|
_store := store.FromContext(c)
|
||||||
repo := session.Repo(c)
|
repo := session.Repo(c)
|
||||||
|
|
||||||
var p model.BuildOptions
|
var p model.PipelineOptions
|
||||||
|
|
||||||
err := json.NewDecoder(c.Request.Body).Decode(&p)
|
err := json.NewDecoder(c.Request.Body).Decode(&p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -53,25 +54,25 @@ func CreateBuild(c *gin.Context) {
|
||||||
|
|
||||||
lastCommit, _ := server.Config.Services.Remote.BranchHead(c, user, repo, p.Branch)
|
lastCommit, _ := server.Config.Services.Remote.BranchHead(c, user, repo, p.Branch)
|
||||||
|
|
||||||
tmpBuild := createTmpBuild(model.EventManual, lastCommit, repo, user, &p)
|
tmpBuild := createTmpPipeline(model.EventManual, lastCommit, repo, user, &p)
|
||||||
|
|
||||||
build, err := pipeline.Create(c, _store, repo, tmpBuild)
|
pl, err := pipeline.Create(c, _store, repo, tmpBuild)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
handlePipelineErr(c, err)
|
handlePipelineErr(c, err)
|
||||||
} else {
|
} else {
|
||||||
c.JSON(http.StatusOK, build)
|
c.JSON(http.StatusOK, pl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createTmpBuild(event model.WebhookEvent, commitSHA string, repo *model.Repo, user *model.User, opts *model.BuildOptions) *model.Build {
|
func createTmpPipeline(event model.WebhookEvent, commitSHA string, repo *model.Repo, user *model.User, opts *model.PipelineOptions) *model.Pipeline {
|
||||||
return &model.Build{
|
return &model.Pipeline{
|
||||||
Event: event,
|
Event: event,
|
||||||
Commit: commitSHA,
|
Commit: commitSHA,
|
||||||
Branch: opts.Branch,
|
Branch: opts.Branch,
|
||||||
Timestamp: time.Now().UTC().Unix(),
|
Timestamp: time.Now().UTC().Unix(),
|
||||||
|
|
||||||
Avatar: user.Avatar,
|
Avatar: user.Avatar,
|
||||||
Message: "MANUAL BUILD @ " + opts.Branch,
|
Message: "MANUAL PIPELINE @ " + opts.Branch,
|
||||||
|
|
||||||
Ref: opts.Branch,
|
Ref: opts.Branch,
|
||||||
AdditionalVariables: opts.Variables,
|
AdditionalVariables: opts.Variables,
|
||||||
|
@ -84,7 +85,7 @@ func createTmpBuild(event model.WebhookEvent, commitSHA string, repo *model.Repo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetBuilds(c *gin.Context) {
|
func GetPipelines(c *gin.Context) {
|
||||||
repo := session.Repo(c)
|
repo := session.Repo(c)
|
||||||
page, err := strconv.Atoi(c.DefaultQuery("page", "1"))
|
page, err := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -92,18 +93,18 @@ func GetBuilds(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
builds, err := store.FromContext(c).GetBuildList(repo, page)
|
pipelines, err := store.FromContext(c).GetPipelineList(repo, page)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithStatus(http.StatusInternalServerError)
|
c.AbortWithStatus(http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.JSON(http.StatusOK, builds)
|
c.JSON(http.StatusOK, pipelines)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetBuild(c *gin.Context) {
|
func GetPipeline(c *gin.Context) {
|
||||||
_store := store.FromContext(c)
|
_store := store.FromContext(c)
|
||||||
if c.Param("number") == "latest" {
|
if c.Param("number") == "latest" {
|
||||||
GetBuildLast(c)
|
GetPipelineLast(c)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,62 +115,62 @@ func GetBuild(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
build, err := _store.GetBuildNumber(repo, num)
|
pl, err := _store.GetPipelineNumber(repo, num)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
files, _ := _store.FileList(build)
|
files, _ := _store.FileList(pl)
|
||||||
procs, _ := _store.ProcList(build)
|
procs, _ := _store.ProcList(pl)
|
||||||
if build.Procs, err = model.Tree(procs); err != nil {
|
if pl.Procs, err = model.Tree(procs); err != nil {
|
||||||
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
build.Files = files
|
pl.Files = files
|
||||||
|
|
||||||
c.JSON(http.StatusOK, build)
|
c.JSON(http.StatusOK, pl)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetBuildLast(c *gin.Context) {
|
func GetPipelineLast(c *gin.Context) {
|
||||||
_store := store.FromContext(c)
|
_store := store.FromContext(c)
|
||||||
repo := session.Repo(c)
|
repo := session.Repo(c)
|
||||||
branch := c.DefaultQuery("branch", repo.Branch)
|
branch := c.DefaultQuery("branch", repo.Branch)
|
||||||
|
|
||||||
build, err := _store.GetBuildLast(repo, branch)
|
pl, err := _store.GetPipelineLast(repo, branch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.String(http.StatusInternalServerError, err.Error())
|
c.String(http.StatusInternalServerError, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
procs, err := _store.ProcList(build)
|
procs, err := _store.ProcList(pl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if build.Procs, err = model.Tree(procs); err != nil {
|
if pl.Procs, err = model.Tree(procs); err != nil {
|
||||||
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.JSON(http.StatusOK, build)
|
c.JSON(http.StatusOK, pl)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetBuildLogs(c *gin.Context) {
|
func GetPipelineLogs(c *gin.Context) {
|
||||||
_store := store.FromContext(c)
|
_store := store.FromContext(c)
|
||||||
repo := session.Repo(c)
|
repo := session.Repo(c)
|
||||||
|
|
||||||
// parse the build number and job sequence number from
|
// parse the pipeline number and job sequence number from
|
||||||
// the request parameter.
|
// the request parameter.
|
||||||
num, _ := strconv.ParseInt(c.Params.ByName("number"), 10, 64)
|
num, _ := strconv.ParseInt(c.Params.ByName("number"), 10, 64)
|
||||||
ppid, _ := strconv.Atoi(c.Params.ByName("pid"))
|
ppid, _ := strconv.Atoi(c.Params.ByName("pid"))
|
||||||
name := c.Params.ByName("proc")
|
name := c.Params.ByName("proc")
|
||||||
|
|
||||||
build, err := _store.GetBuildNumber(repo, num)
|
pl, err := _store.GetPipelineNumber(repo, num)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = c.AbortWithError(404, err)
|
_ = c.AbortWithError(404, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
proc, err := _store.ProcChild(build, ppid, name)
|
proc, err := _store.ProcChild(pl, ppid, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = c.AbortWithError(404, err)
|
_ = c.AbortWithError(404, err)
|
||||||
return
|
return
|
||||||
|
@ -193,18 +194,18 @@ func GetProcLogs(c *gin.Context) {
|
||||||
_store := store.FromContext(c)
|
_store := store.FromContext(c)
|
||||||
repo := session.Repo(c)
|
repo := session.Repo(c)
|
||||||
|
|
||||||
// parse the build number and job sequence number from
|
// parse the pipeline number and job sequence number from
|
||||||
// the request parameter.
|
// the request parameter.
|
||||||
num, _ := strconv.ParseInt(c.Params.ByName("number"), 10, 64)
|
num, _ := strconv.ParseInt(c.Params.ByName("number"), 10, 64)
|
||||||
pid, _ := strconv.Atoi(c.Params.ByName("pid"))
|
pid, _ := strconv.Atoi(c.Params.ByName("pid"))
|
||||||
|
|
||||||
build, err := _store.GetBuildNumber(repo, num)
|
pl, err := _store.GetPipelineNumber(repo, num)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = c.AbortWithError(http.StatusNotFound, err)
|
_ = c.AbortWithError(http.StatusNotFound, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
proc, err := _store.ProcFind(build, pid)
|
proc, err := _store.ProcFind(pl, pid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = c.AbortWithError(http.StatusNotFound, err)
|
_ = c.AbortWithError(http.StatusNotFound, err)
|
||||||
return
|
return
|
||||||
|
@ -224,7 +225,7 @@ func GetProcLogs(c *gin.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetBuildConfig(c *gin.Context) {
|
func GetPipelineConfig(c *gin.Context) {
|
||||||
_store := store.FromContext(c)
|
_store := store.FromContext(c)
|
||||||
repo := session.Repo(c)
|
repo := session.Repo(c)
|
||||||
num, err := strconv.ParseInt(c.Param("number"), 10, 64)
|
num, err := strconv.ParseInt(c.Param("number"), 10, 64)
|
||||||
|
@ -233,13 +234,13 @@ func GetBuildConfig(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
build, err := _store.GetBuildNumber(repo, num)
|
pl, err := _store.GetPipelineNumber(repo, num)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
_ = c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
configs, err := _store.ConfigsForBuild(build.ID)
|
configs, err := _store.ConfigsForPipeline(pl.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.String(http.StatusInternalServerError, err.Error())
|
c.String(http.StatusInternalServerError, err.Error())
|
||||||
return
|
return
|
||||||
|
@ -248,19 +249,19 @@ func GetBuildConfig(c *gin.Context) {
|
||||||
c.JSON(http.StatusOK, configs)
|
c.JSON(http.StatusOK, configs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteBuild cancels a build
|
// DeletePipeline cancels a pipeline
|
||||||
func DeleteBuild(c *gin.Context) {
|
func DeletePipeline(c *gin.Context) {
|
||||||
_store := store.FromContext(c)
|
_store := store.FromContext(c)
|
||||||
repo := session.Repo(c)
|
repo := session.Repo(c)
|
||||||
num, _ := strconv.ParseInt(c.Params.ByName("number"), 10, 64)
|
num, _ := strconv.ParseInt(c.Params.ByName("number"), 10, 64)
|
||||||
|
|
||||||
build, err := _store.GetBuildNumber(repo, num)
|
pl, err := _store.GetPipelineNumber(repo, num)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = c.AbortWithError(http.StatusNotFound, err)
|
_ = c.AbortWithError(http.StatusNotFound, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := pipeline.Cancel(c, _store, repo, build); err != nil {
|
if err := pipeline.Cancel(c, _store, repo, pl); err != nil {
|
||||||
handlePipelineErr(c, err)
|
handlePipelineErr(c, err)
|
||||||
} else {
|
} else {
|
||||||
c.Status(http.StatusNoContent)
|
c.Status(http.StatusNoContent)
|
||||||
|
@ -276,17 +277,17 @@ func PostApproval(c *gin.Context) {
|
||||||
num, _ = strconv.ParseInt(c.Params.ByName("number"), 10, 64)
|
num, _ = strconv.ParseInt(c.Params.ByName("number"), 10, 64)
|
||||||
)
|
)
|
||||||
|
|
||||||
build, err := _store.GetBuildNumber(repo, num)
|
pl, err := _store.GetPipelineNumber(repo, num)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = c.AbortWithError(404, err)
|
_ = c.AbortWithError(404, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
newBuild, err := pipeline.Approve(c, _store, build, user, repo)
|
newpipeline, err := pipeline.Approve(c, _store, pl, user, repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
handlePipelineErr(c, err)
|
handlePipelineErr(c, err)
|
||||||
} else {
|
} else {
|
||||||
c.JSON(200, newBuild)
|
c.JSON(200, newpipeline)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -299,31 +300,31 @@ func PostDecline(c *gin.Context) {
|
||||||
num, _ = strconv.ParseInt(c.Params.ByName("number"), 10, 64)
|
num, _ = strconv.ParseInt(c.Params.ByName("number"), 10, 64)
|
||||||
)
|
)
|
||||||
|
|
||||||
build, err := _store.GetBuildNumber(repo, num)
|
pl, err := _store.GetPipelineNumber(repo, num)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.String(http.StatusNotFound, "%v", err)
|
c.String(http.StatusNotFound, "%v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
build, err = pipeline.Decline(c, _store, build, user, repo)
|
pl, err = pipeline.Decline(c, _store, pl, user, repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
handlePipelineErr(c, err)
|
handlePipelineErr(c, err)
|
||||||
} else {
|
} else {
|
||||||
c.JSON(200, build)
|
c.JSON(200, pl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetBuildQueue(c *gin.Context) {
|
func GetPipelineQueue(c *gin.Context) {
|
||||||
out, err := store.FromContext(c).GetBuildQueue()
|
out, err := store.FromContext(c).GetPipelineQueue()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.String(500, "Error getting build queue. %s", err)
|
c.String(500, "Error getting pipeline queue. %s", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.JSON(200, out)
|
c.JSON(200, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PostBuild restarts a build optional with altered event, deploy or environment
|
// PostPipeline restarts a pipeline optional with altered event, deploy or environment
|
||||||
func PostBuild(c *gin.Context) {
|
func PostPipeline(c *gin.Context) {
|
||||||
_store := store.FromContext(c)
|
_store := store.FromContext(c)
|
||||||
repo := session.Repo(c)
|
repo := session.Repo(c)
|
||||||
|
|
||||||
|
@ -340,9 +341,9 @@ func PostBuild(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
build, err := _store.GetBuildNumber(repo, num)
|
pl, err := _store.GetPipelineNumber(repo, num)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Msgf("failure to get build %d. %s", num, err)
|
log.Error().Msgf("failure to get pipeline %d. %s", num, err)
|
||||||
_ = c.AbortWithError(404, err)
|
_ = c.AbortWithError(404, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -351,20 +352,20 @@ func PostBuild(c *gin.Context) {
|
||||||
refreshUserToken(c, user)
|
refreshUserToken(c, user)
|
||||||
|
|
||||||
// make Deploy overridable
|
// make Deploy overridable
|
||||||
build.Deploy = c.DefaultQuery("deploy_to", build.Deploy)
|
pl.Deploy = c.DefaultQuery("deploy_to", pl.Deploy)
|
||||||
|
|
||||||
// make Event overridable
|
// make Event overridable
|
||||||
if event, ok := c.GetQuery("event"); ok {
|
if event, ok := c.GetQuery("event"); ok {
|
||||||
build.Event = model.WebhookEvent(event)
|
pl.Event = model.WebhookEvent(event)
|
||||||
|
|
||||||
if !model.ValidateWebhookEvent(build.Event) {
|
if !model.ValidateWebhookEvent(pl.Event) {
|
||||||
msg := fmt.Sprintf("build event '%s' is invalid", event)
|
msg := fmt.Sprintf("pipeline event '%s' is invalid", event)
|
||||||
c.String(http.StatusBadRequest, msg)
|
c.String(http.StatusBadRequest, msg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read query string parameters into buildParams, exclude reserved params
|
// Read query string parameters into pipelineParams, exclude reserved params
|
||||||
envs := map[string]string{}
|
envs := map[string]string{}
|
||||||
for key, val := range c.Request.URL.Query() {
|
for key, val := range c.Request.URL.Query() {
|
||||||
switch key {
|
switch key {
|
||||||
|
@ -372,43 +373,43 @@ func PostBuild(c *gin.Context) {
|
||||||
case "fork", "event", "deploy_to":
|
case "fork", "event", "deploy_to":
|
||||||
continue
|
continue
|
||||||
default:
|
default:
|
||||||
// We only accept string literals, because build parameters will be
|
// We only accept string literals, because pipeline parameters will be
|
||||||
// injected as environment variables
|
// injected as environment variables
|
||||||
// TODO: sanitize the value
|
// TODO: sanitize the value
|
||||||
envs[key] = val[0]
|
envs[key] = val[0]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
newBuild, err := pipeline.Restart(c, _store, build, user, repo, envs)
|
newpipeline, err := pipeline.Restart(c, _store, pl, user, repo, envs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
handlePipelineErr(c, err)
|
handlePipelineErr(c, err)
|
||||||
} else {
|
} else {
|
||||||
c.JSON(200, newBuild)
|
c.JSON(200, newpipeline)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteBuildLogs(c *gin.Context) {
|
func DeletePipelineLogs(c *gin.Context) {
|
||||||
_store := store.FromContext(c)
|
_store := store.FromContext(c)
|
||||||
|
|
||||||
repo := session.Repo(c)
|
repo := session.Repo(c)
|
||||||
user := session.User(c)
|
user := session.User(c)
|
||||||
num, _ := strconv.ParseInt(c.Params.ByName("number"), 10, 64)
|
num, _ := strconv.ParseInt(c.Params.ByName("number"), 10, 64)
|
||||||
|
|
||||||
build, err := _store.GetBuildNumber(repo, num)
|
pl, err := _store.GetPipelineNumber(repo, num)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = c.AbortWithError(404, err)
|
_ = c.AbortWithError(404, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
procs, err := _store.ProcList(build)
|
procs, err := _store.ProcList(pl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = c.AbortWithError(404, err)
|
_ = c.AbortWithError(404, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
switch build.Status {
|
switch pl.Status {
|
||||||
case model.StatusRunning, model.StatusPending:
|
case model.StatusRunning, model.StatusPending:
|
||||||
c.String(400, "Cannot delete logs for a pending or running build")
|
c.String(400, "Cannot delete logs for a pending or running pipeline")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// Copyright 2022 Woodpecker Authors
|
||||||
// Copyright 2018 Drone.IO Inc.
|
// Copyright 2018 Drone.IO Inc.
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@ -33,7 +34,7 @@ import (
|
||||||
|
|
||||||
// TODO: make it set system wide via environment variables
|
// TODO: make it set system wide via environment variables
|
||||||
const (
|
const (
|
||||||
defaultTimeout int64 = 60 // 1 hour default build time
|
defaultTimeout int64 = 60 // 1 hour default pipeline time
|
||||||
maxTimeout int64 = defaultTimeout * 2
|
maxTimeout int64 = defaultTimeout * 2
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// Copyright 2022 Woodpecker Authors
|
||||||
// Copyright 2018 Drone.IO Inc.
|
// Copyright 2018 Drone.IO Inc.
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@ -140,18 +141,18 @@ func LogStreamSSE(c *gin.Context) {
|
||||||
repo := session.Repo(c)
|
repo := session.Repo(c)
|
||||||
_store := store.FromContext(c)
|
_store := store.FromContext(c)
|
||||||
|
|
||||||
// // parse the build number and job sequence number from
|
// // parse the pipeline number and job sequence number from
|
||||||
// // the repquest parameter.
|
// // the repquest parameter.
|
||||||
buildn, _ := strconv.ParseInt(c.Param("build"), 10, 64)
|
pipelinen, _ := strconv.ParseInt(c.Param("pipeline"), 10, 64)
|
||||||
jobn, _ := strconv.Atoi(c.Param("number"))
|
jobn, _ := strconv.Atoi(c.Param("number"))
|
||||||
|
|
||||||
build, err := _store.GetBuildNumber(repo, buildn)
|
pipeline, err := _store.GetPipelineNumber(repo, pipelinen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug().Msgf("stream cannot get build number: %v", err)
|
log.Debug().Msgf("stream cannot get pipeline number: %v", err)
|
||||||
logWriteStringErr(io.WriteString(rw, "event: error\ndata: build not found\n\n"))
|
logWriteStringErr(io.WriteString(rw, "event: error\ndata: pipeline not found\n\n"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
proc, err := _store.ProcFind(build, jobn)
|
proc, err := _store.ProcFind(pipeline, jobn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug().Msgf("stream cannot get proc number: %v", err)
|
log.Debug().Msgf("stream cannot get proc number: %v", err)
|
||||||
logWriteStringErr(io.WriteString(rw, "event: error\ndata: process not found\n\n"))
|
logWriteStringErr(io.WriteString(rw, "event: error\ndata: process not found\n\n"))
|
||||||
|
|
|
@ -25,7 +25,7 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Generate an SVG badge based on a pipeline
|
// Generate an SVG badge based on a pipeline
|
||||||
func Generate(pipeline *model.Build) string {
|
func Generate(pipeline *model.Pipeline) string {
|
||||||
if pipeline == nil {
|
if pipeline == nil {
|
||||||
return badgeNone
|
return badgeNone
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ import (
|
||||||
"github.com/woodpecker-ci/woodpecker/server/model"
|
"github.com/woodpecker-ci/woodpecker/server/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CCMenu displays the build status of projects on a ci server as an item in the Mac's menu bar.
|
// CCMenu displays the pipeline status of projects on a ci server as an item in the Mac's menu bar.
|
||||||
// It started as part of the CruiseControl project that built the first continuous integration server.
|
// It started as part of the CruiseControl project that built the first continuous integration server.
|
||||||
//
|
//
|
||||||
// http://ccmenu.org/
|
// http://ccmenu.org/
|
||||||
|
@ -43,7 +43,7 @@ type CCProject struct {
|
||||||
WebURL string `xml:"webUrl,attr"`
|
WebURL string `xml:"webUrl,attr"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(r *model.Repo, b *model.Build, link string) *CCProjects {
|
func New(r *model.Repo, b *model.Pipeline, link string) *CCProjects {
|
||||||
proj := &CCProject{
|
proj := &CCProject{
|
||||||
Name: r.FullName,
|
Name: r.FullName,
|
||||||
WebURL: link,
|
WebURL: link,
|
||||||
|
@ -52,8 +52,8 @@ func New(r *model.Repo, b *model.Build, link string) *CCProjects {
|
||||||
LastBuildLabel: "Unknown",
|
LastBuildLabel: "Unknown",
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the build is not currently running then
|
// if the pipeline is not currently running then
|
||||||
// we can return the latest build status.
|
// we can return the latest pipeline status.
|
||||||
if b.Status != model.StatusPending &&
|
if b.Status != model.StatusPending &&
|
||||||
b.Status != model.StatusRunning {
|
b.Status != model.StatusRunning {
|
||||||
proj.Activity = "Sleeping"
|
proj.Activity = "Sleeping"
|
||||||
|
@ -61,7 +61,7 @@ func New(r *model.Repo, b *model.Build, link string) *CCProjects {
|
||||||
proj.LastBuildLabel = strconv.FormatInt(b.Number, 10)
|
proj.LastBuildLabel = strconv.FormatInt(b.Number, 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ensure the last build Status accepts a valid
|
// ensure the last pipeline status accepts a valid
|
||||||
// ccmenu enumeration
|
// ccmenu enumeration
|
||||||
switch b.Status {
|
switch b.Status {
|
||||||
case model.StatusError, model.StatusKilled:
|
case model.StatusError, model.StatusKilled:
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// Copyright 2022 Woodpecker Authors
|
||||||
// Copyright 2018 Drone.IO Inc.
|
// Copyright 2018 Drone.IO Inc.
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@ -32,7 +33,7 @@ func TestCC(t *testing.T) {
|
||||||
r := &model.Repo{
|
r := &model.Repo{
|
||||||
FullName: "foo/bar",
|
FullName: "foo/bar",
|
||||||
}
|
}
|
||||||
b := &model.Build{
|
b := &model.Pipeline{
|
||||||
Status: model.StatusSuccess,
|
Status: model.StatusSuccess,
|
||||||
Number: 1,
|
Number: 1,
|
||||||
Started: now,
|
Started: now,
|
||||||
|
@ -49,7 +50,7 @@ func TestCC(t *testing.T) {
|
||||||
|
|
||||||
g.It("Should properly label exceptions", func() {
|
g.It("Should properly label exceptions", func() {
|
||||||
r := &model.Repo{FullName: "foo/bar"}
|
r := &model.Repo{FullName: "foo/bar"}
|
||||||
b := &model.Build{
|
b := &model.Pipeline{
|
||||||
Status: model.StatusError,
|
Status: model.StatusError,
|
||||||
Number: 1,
|
Number: 1,
|
||||||
Started: 1257894000,
|
Started: 1257894000,
|
||||||
|
@ -61,7 +62,7 @@ func TestCC(t *testing.T) {
|
||||||
|
|
||||||
g.It("Should properly label success", func() {
|
g.It("Should properly label success", func() {
|
||||||
r := &model.Repo{FullName: "foo/bar"}
|
r := &model.Repo{FullName: "foo/bar"}
|
||||||
b := &model.Build{
|
b := &model.Pipeline{
|
||||||
Status: model.StatusSuccess,
|
Status: model.StatusSuccess,
|
||||||
Number: 1,
|
Number: 1,
|
||||||
Started: 1257894000,
|
Started: 1257894000,
|
||||||
|
@ -73,7 +74,7 @@ func TestCC(t *testing.T) {
|
||||||
|
|
||||||
g.It("Should properly label failure", func() {
|
g.It("Should properly label failure", func() {
|
||||||
r := &model.Repo{FullName: "foo/bar"}
|
r := &model.Repo{FullName: "foo/bar"}
|
||||||
b := &model.Build{
|
b := &model.Pipeline{
|
||||||
Status: model.StatusFailure,
|
Status: model.StatusFailure,
|
||||||
Number: 1,
|
Number: 1,
|
||||||
Started: 1257894000,
|
Started: 1257894000,
|
||||||
|
@ -85,7 +86,7 @@ func TestCC(t *testing.T) {
|
||||||
|
|
||||||
g.It("Should properly label running", func() {
|
g.It("Should properly label running", func() {
|
||||||
r := &model.Repo{FullName: "foo/bar"}
|
r := &model.Repo{FullName: "foo/bar"}
|
||||||
b := &model.Build{
|
b := &model.Pipeline{
|
||||||
Status: model.StatusRunning,
|
Status: model.StatusRunning,
|
||||||
Number: 1,
|
Number: 1,
|
||||||
Started: 1257894000,
|
Started: 1257894000,
|
||||||
|
|
|
@ -105,7 +105,7 @@ func runCron(store store.Store, remote remote.Remote, cron *model.Cron, now time
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func createBuild(ctx context.Context, store store.Store, remote remote.Remote, cron *model.Cron) (*model.Repo, *model.Build, error) {
|
func createBuild(ctx context.Context, store store.Store, remote remote.Remote, cron *model.Cron) (*model.Repo, *model.Pipeline, error) {
|
||||||
repo, err := store.GetRepo(cron.RepoID)
|
repo, err := store.GetRepo(cron.RepoID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
|
@ -126,7 +126,7 @@ func createBuild(ctx context.Context, store store.Store, remote remote.Remote, c
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return repo, &model.Build{
|
return repo, &model.Pipeline{
|
||||||
Event: model.EventCron,
|
Event: model.EventCron,
|
||||||
Commit: commit,
|
Commit: commit,
|
||||||
Ref: "refs/heads/" + cron.Branch,
|
Ref: "refs/heads/" + cron.Branch,
|
||||||
|
|
|
@ -49,18 +49,18 @@ func TestCreateBuild(t *testing.T) {
|
||||||
store.On("GetUser", mock.Anything).Return(creator, nil)
|
store.On("GetUser", mock.Anything).Return(creator, nil)
|
||||||
remote.On("BranchHead", mock.Anything, creator, repo1, "default").Return("sha1", nil)
|
remote.On("BranchHead", mock.Anything, creator, repo1, "default").Return("sha1", nil)
|
||||||
|
|
||||||
_, build, err := createBuild(ctx, store, remote, &model.Cron{
|
_, pipeline, err := createBuild(ctx, store, remote, &model.Cron{
|
||||||
Name: "test",
|
Name: "test",
|
||||||
})
|
})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.EqualValues(t, &model.Build{
|
assert.EqualValues(t, &model.Pipeline{
|
||||||
Event: "cron",
|
Event: "cron",
|
||||||
Commit: "sha1",
|
Commit: "sha1",
|
||||||
Branch: "default",
|
Branch: "default",
|
||||||
Ref: "refs/heads/default",
|
Ref: "refs/heads/default",
|
||||||
Message: "test",
|
Message: "test",
|
||||||
Sender: "test",
|
Sender: "test",
|
||||||
}, build)
|
}, pipeline)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCalcNewNext(t *testing.T) {
|
func TestCalcNewNext(t *testing.T) {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// Copyright 2018 Drone.IO Inc.
|
// Copyright 2022 Woodpecker Authors
|
||||||
// Copyright 2021 Informatyka Boguslawski sp. z o.o. sp.k., http://www.ib.pl/
|
// Copyright 2021 Informatyka Boguslawski sp. z o.o. sp.k., http://www.ib.pl/
|
||||||
|
// Copyright 2018 Drone.IO Inc.
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
|
@ -47,8 +48,8 @@ type RPC struct {
|
||||||
logger logging.Log
|
logger logging.Log
|
||||||
store store.Store
|
store store.Store
|
||||||
host string
|
host string
|
||||||
buildTime *prometheus.GaugeVec
|
pipelineTime *prometheus.GaugeVec
|
||||||
buildCount *prometheus.CounterVec
|
pipelineCount *prometheus.CounterVec
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next implements the rpc.Next function
|
// Next implements the rpc.Next function
|
||||||
|
@ -107,13 +108,13 @@ func (s *RPC) Update(c context.Context, id string, state rpc.State) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
build, err := s.store.GetBuild(pproc.BuildID)
|
pipeline, err := s.store.GetPipeline(pproc.PipelineID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Msgf("error: cannot find build with id %d: %s", pproc.BuildID, err)
|
log.Error().Msgf("error: cannot find pipeline with id %d: %s", pproc.PipelineID, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
proc, err := s.store.ProcChild(build, pproc.PID, state.Proc)
|
proc, err := s.store.ProcChild(pipeline, pproc.PID, state.Proc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Msgf("error: cannot find proc with name %s: %s", state.Proc, err)
|
log.Error().Msgf("error: cannot find proc with name %s: %s", state.Proc, err)
|
||||||
return err
|
return err
|
||||||
|
@ -127,20 +128,20 @@ func (s *RPC) Update(c context.Context, id string, state rpc.State) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
repo, err := s.store.GetRepo(build.RepoID)
|
repo, err := s.store.GetRepo(pipeline.RepoID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Msgf("error: cannot find repo with id %d: %s", build.RepoID, err)
|
log.Error().Msgf("error: cannot find repo with id %d: %s", pipeline.RepoID, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = shared.UpdateProcStatus(s.store, *proc, state, build.Started); err != nil {
|
if _, err = shared.UpdateProcStatus(s.store, *proc, state, pipeline.Started); err != nil {
|
||||||
log.Error().Err(err).Msg("rpc.update: cannot update proc")
|
log.Error().Err(err).Msg("rpc.update: cannot update proc")
|
||||||
}
|
}
|
||||||
|
|
||||||
if build.Procs, err = s.store.ProcList(build); err != nil {
|
if pipeline.Procs, err = s.store.ProcList(pipeline); err != nil {
|
||||||
log.Error().Err(err).Msg("can not get proc list from store")
|
log.Error().Err(err).Msg("can not get proc list from store")
|
||||||
}
|
}
|
||||||
if build.Procs, err = model.Tree(build.Procs); err != nil {
|
if pipeline.Procs, err = model.Tree(pipeline.Procs); err != nil {
|
||||||
log.Error().Err(err).Msg("can not build tree from proc list")
|
log.Error().Err(err).Msg("can not build tree from proc list")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -152,7 +153,7 @@ func (s *RPC) Update(c context.Context, id string, state rpc.State) error {
|
||||||
}
|
}
|
||||||
message.Data, _ = json.Marshal(model.Event{
|
message.Data, _ = json.Marshal(model.Event{
|
||||||
Repo: *repo,
|
Repo: *repo,
|
||||||
Build: *build,
|
Pipeline: *pipeline,
|
||||||
})
|
})
|
||||||
if err := s.pubsub.Publish(c, "topic/events", message); err != nil {
|
if err := s.pubsub.Publish(c, "topic/events", message); err != nil {
|
||||||
log.Error().Err(err).Msg("can not publish proc list to")
|
log.Error().Err(err).Msg("can not publish proc list to")
|
||||||
|
@ -174,13 +175,13 @@ func (s *RPC) Upload(c context.Context, id string, file *rpc.File) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
build, err := s.store.GetBuild(pproc.BuildID)
|
pipeline, err := s.store.GetPipeline(pproc.PipelineID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Msgf("error: cannot find build with id %d: %s", pproc.BuildID, err)
|
log.Error().Msgf("error: cannot find pipeline with id %d: %s", pproc.PipelineID, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
proc, err := s.store.ProcChild(build, pproc.PID, file.Proc)
|
proc, err := s.store.ProcChild(pipeline, pproc.PID, file.Proc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Msgf("error: cannot find child proc with name %s: %s", file.Proc, err)
|
log.Error().Msgf("error: cannot find child proc with name %s: %s", file.Proc, err)
|
||||||
return err
|
return err
|
||||||
|
@ -194,7 +195,7 @@ func (s *RPC) Upload(c context.Context, id string, file *rpc.File) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
report := &model.File{
|
report := &model.File{
|
||||||
BuildID: proc.BuildID,
|
PipelineID: proc.PipelineID,
|
||||||
ProcID: proc.ID,
|
ProcID: proc.ID,
|
||||||
PID: proc.PID,
|
PID: proc.PID,
|
||||||
Mime: file.Mime,
|
Mime: file.Mime,
|
||||||
|
@ -254,26 +255,26 @@ func (s *RPC) Init(c context.Context, id string, state rpc.State) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
build, err := s.store.GetBuild(proc.BuildID)
|
pipeline, err := s.store.GetPipeline(proc.PipelineID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Msgf("error: cannot find build with id %d: %s", proc.BuildID, err)
|
log.Error().Msgf("error: cannot find pipeline with id %d: %s", proc.PipelineID, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
repo, err := s.store.GetRepo(build.RepoID)
|
repo, err := s.store.GetRepo(pipeline.RepoID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Msgf("error: cannot find repo with id %d: %s", build.RepoID, err)
|
log.Error().Msgf("error: cannot find repo with id %d: %s", pipeline.RepoID, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if build.Status == model.StatusPending {
|
if pipeline.Status == model.StatusPending {
|
||||||
if build, err = shared.UpdateToStatusRunning(s.store, *build, state.Started); err != nil {
|
if pipeline, err = shared.UpdateToStatusRunning(s.store, *pipeline, state.Started); err != nil {
|
||||||
log.Error().Msgf("error: init: cannot update build_id %d state: %s", build.ID, err)
|
log.Error().Msgf("error: init: cannot update build_id %d state: %s", pipeline.ID, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
build.Procs, _ = s.store.ProcList(build)
|
pipeline.Procs, _ = s.store.ProcList(pipeline)
|
||||||
message := pubsub.Message{
|
message := pubsub.Message{
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
"repo": repo.FullName,
|
"repo": repo.FullName,
|
||||||
|
@ -282,7 +283,7 @@ func (s *RPC) Init(c context.Context, id string, state rpc.State) error {
|
||||||
}
|
}
|
||||||
message.Data, _ = json.Marshal(model.Event{
|
message.Data, _ = json.Marshal(model.Event{
|
||||||
Repo: *repo,
|
Repo: *repo,
|
||||||
Build: *build,
|
Pipeline: *pipeline,
|
||||||
})
|
})
|
||||||
if err := s.pubsub.Publish(c, "topic/events", message); err != nil {
|
if err := s.pubsub.Publish(c, "topic/events", message); err != nil {
|
||||||
log.Error().Err(err).Msg("can not publish proc list to")
|
log.Error().Err(err).Msg("can not publish proc list to")
|
||||||
|
@ -306,21 +307,21 @@ func (s *RPC) Done(c context.Context, id string, state rpc.State) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
build, err := s.store.GetBuild(proc.BuildID)
|
pipeline, err := s.store.GetPipeline(proc.PipelineID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Msgf("error: cannot find build with id %d: %s", proc.BuildID, err)
|
log.Error().Msgf("error: cannot find pipeline with id %d: %s", proc.PipelineID, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
repo, err := s.store.GetRepo(build.RepoID)
|
repo, err := s.store.GetRepo(pipeline.RepoID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Msgf("error: cannot find repo with id %d: %s", build.RepoID, err)
|
log.Error().Msgf("error: cannot find repo with id %d: %s", pipeline.RepoID, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Trace().
|
log.Trace().
|
||||||
Str("repo_id", fmt.Sprint(repo.ID)).
|
Str("repo_id", fmt.Sprint(repo.ID)).
|
||||||
Str("build_id", fmt.Sprint(build.ID)).
|
Str("build_id", fmt.Sprint(pipeline.ID)).
|
||||||
Str("proc_id", id).
|
Str("proc_id", id).
|
||||||
Msgf("gRPC Done with state: %#v", state)
|
Msgf("gRPC Done with state: %#v", state)
|
||||||
|
|
||||||
|
@ -338,34 +339,34 @@ func (s *RPC) Done(c context.Context, id string, state rpc.State) error {
|
||||||
log.Error().Msgf("error: done: cannot ack proc_id %d: %s", procID, err)
|
log.Error().Msgf("error: done: cannot ack proc_id %d: %s", procID, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
procs, err := s.store.ProcList(build)
|
procs, err := s.store.ProcList(pipeline)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
s.completeChildrenIfParentCompleted(procs, proc)
|
s.completeChildrenIfParentCompleted(procs, proc)
|
||||||
|
|
||||||
if !model.IsThereRunningStage(procs) {
|
if !model.IsThereRunningStage(procs) {
|
||||||
if build, err = shared.UpdateStatusToDone(s.store, *build, model.BuildStatus(procs), proc.Stopped); err != nil {
|
if pipeline, err = shared.UpdateStatusToDone(s.store, *pipeline, model.PipelineStatus(procs), proc.Stopped); err != nil {
|
||||||
log.Error().Err(err).Msgf("error: done: cannot update build_id %d final state", build.ID)
|
log.Error().Err(err).Msgf("error: done: cannot update build_id %d final state", pipeline.ID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s.updateRemoteStatus(c, repo, build, proc)
|
s.updateRemoteStatus(c, repo, pipeline, proc)
|
||||||
|
|
||||||
if err := s.logger.Close(c, id); err != nil {
|
if err := s.logger.Close(c, id); err != nil {
|
||||||
log.Error().Err(err).Msgf("done: cannot close build_id %d logger", proc.ID)
|
log.Error().Err(err).Msgf("done: cannot close build_id %d logger", proc.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.notify(c, repo, build, procs); err != nil {
|
if err := s.notify(c, repo, pipeline, procs); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if build.Status == model.StatusSuccess || build.Status == model.StatusFailure {
|
if pipeline.Status == model.StatusSuccess || pipeline.Status == model.StatusFailure {
|
||||||
s.buildCount.WithLabelValues(repo.FullName, build.Branch, string(build.Status), "total").Inc()
|
s.pipelineCount.WithLabelValues(repo.FullName, pipeline.Branch, string(pipeline.Status), "total").Inc()
|
||||||
s.buildTime.WithLabelValues(repo.FullName, build.Branch, string(build.Status), "total").Set(float64(build.Finished - build.Started))
|
s.pipelineTime.WithLabelValues(repo.FullName, pipeline.Branch, string(pipeline.Status), "total").Set(float64(pipeline.Finished - pipeline.Started))
|
||||||
}
|
}
|
||||||
if model.IsMultiPipeline(procs) {
|
if model.IsMultiPipeline(procs) {
|
||||||
s.buildTime.WithLabelValues(repo.FullName, build.Branch, string(proc.State), proc.Name).Set(float64(proc.Stopped - proc.Started))
|
s.pipelineTime.WithLabelValues(repo.FullName, pipeline.Branch, string(proc.State), proc.Name).Set(float64(proc.Stopped - proc.Started))
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -391,7 +392,7 @@ func (s *RPC) completeChildrenIfParentCompleted(procs []*model.Proc, completedPr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *RPC) updateRemoteStatus(ctx context.Context, repo *model.Repo, build *model.Build, proc *model.Proc) {
|
func (s *RPC) updateRemoteStatus(ctx context.Context, repo *model.Repo, pipeline *model.Pipeline, proc *model.Proc) {
|
||||||
user, err := s.store.GetUser(repo.UserID)
|
user, err := s.store.GetUser(repo.UserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msgf("can not get user with id '%d'", repo.UserID)
|
log.Error().Err(err).Msgf("can not get user with id '%d'", repo.UserID)
|
||||||
|
@ -411,15 +412,15 @@ func (s *RPC) updateRemoteStatus(ctx context.Context, repo *model.Repo, build *m
|
||||||
|
|
||||||
// only do status updates for parent procs
|
// only do status updates for parent procs
|
||||||
if proc != nil && proc.IsParent() {
|
if proc != nil && proc.IsParent() {
|
||||||
err = s.remote.Status(ctx, user, repo, build, proc)
|
err = s.remote.Status(ctx, user, repo, pipeline, proc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msgf("error setting commit status for %s/%d", repo.FullName, build.Number)
|
log.Error().Err(err).Msgf("error setting commit status for %s/%d", repo.FullName, pipeline.Number)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *RPC) notify(c context.Context, repo *model.Repo, build *model.Build, procs []*model.Proc) (err error) {
|
func (s *RPC) notify(c context.Context, repo *model.Repo, pipeline *model.Pipeline, procs []*model.Proc) (err error) {
|
||||||
if build.Procs, err = model.Tree(procs); err != nil {
|
if pipeline.Procs, err = model.Tree(procs); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
message := pubsub.Message{
|
message := pubsub.Message{
|
||||||
|
@ -430,7 +431,7 @@ func (s *RPC) notify(c context.Context, repo *model.Repo, build *model.Build, pr
|
||||||
}
|
}
|
||||||
message.Data, _ = json.Marshal(model.Event{
|
message.Data, _ = json.Marshal(model.Event{
|
||||||
Repo: *repo,
|
Repo: *repo,
|
||||||
Build: *build,
|
Pipeline: *pipeline,
|
||||||
})
|
})
|
||||||
if err := s.pubsub.Publish(c, "topic/events", message); err != nil {
|
if err := s.pubsub.Publish(c, "topic/events", message); err != nil {
|
||||||
log.Error().Err(err).Msgf("grpc could not notify event: '%v'", message)
|
log.Error().Err(err).Msgf("grpc could not notify event: '%v'", message)
|
||||||
|
|
|
@ -37,15 +37,15 @@ type WoodpeckerServer struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWoodpeckerServer(remote remote.Remote, queue queue.Queue, logger logging.Log, pubsub pubsub.Publisher, store store.Store, host string) *WoodpeckerServer {
|
func NewWoodpeckerServer(remote remote.Remote, queue queue.Queue, logger logging.Log, pubsub pubsub.Publisher, store store.Store, host string) *WoodpeckerServer {
|
||||||
buildTime := promauto.NewGaugeVec(prometheus.GaugeOpts{
|
pipelineTime := promauto.NewGaugeVec(prometheus.GaugeOpts{
|
||||||
Namespace: "woodpecker",
|
Namespace: "woodpecker",
|
||||||
Name: "build_time",
|
Name: "pipeline_time",
|
||||||
Help: "Build time.",
|
Help: "Pipeline time.",
|
||||||
}, []string{"repo", "branch", "status", "pipeline"})
|
}, []string{"repo", "branch", "status", "pipeline"})
|
||||||
buildCount := promauto.NewCounterVec(prometheus.CounterOpts{
|
pipelineCount := promauto.NewCounterVec(prometheus.CounterOpts{
|
||||||
Namespace: "woodpecker",
|
Namespace: "woodpecker",
|
||||||
Name: "build_count",
|
Name: "pipeline_count",
|
||||||
Help: "Build count.",
|
Help: "Pipeline count.",
|
||||||
}, []string{"repo", "branch", "status", "pipeline"})
|
}, []string{"repo", "branch", "status", "pipeline"})
|
||||||
peer := RPC{
|
peer := RPC{
|
||||||
remote: remote,
|
remote: remote,
|
||||||
|
@ -54,8 +54,8 @@ func NewWoodpeckerServer(remote remote.Remote, queue queue.Queue, logger logging
|
||||||
pubsub: pubsub,
|
pubsub: pubsub,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
host: host,
|
host: host,
|
||||||
buildTime: buildTime,
|
pipelineTime: pipelineTime,
|
||||||
buildCount: buildCount,
|
pipelineCount: pipelineCount,
|
||||||
}
|
}
|
||||||
return &WoodpeckerServer{peer: peer}
|
return &WoodpeckerServer{peer: peer}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,11 +17,11 @@ package model
|
||||||
|
|
||||||
// ConfigStore persists pipeline configuration to storage.
|
// ConfigStore persists pipeline configuration to storage.
|
||||||
type ConfigStore interface {
|
type ConfigStore interface {
|
||||||
ConfigsForBuild(buildID int64) ([]*Config, error)
|
ConfigsForPipeline(pipelineID int64) ([]*Config, error)
|
||||||
ConfigFindIdentical(repoID int64, hash string) (*Config, error)
|
ConfigFindIdentical(repoID int64, hash string) (*Config, error)
|
||||||
ConfigFindApproved(*Config) (bool, error)
|
ConfigFindApproved(*Config) (bool, error)
|
||||||
ConfigCreate(*Config) error
|
ConfigCreate(*Config) error
|
||||||
BuildConfigCreate(*BuildConfig) error
|
PipelineConfigCreate(*PipelineConfig) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config represents a pipeline configuration.
|
// Config represents a pipeline configuration.
|
||||||
|
@ -33,8 +33,8 @@ type Config struct {
|
||||||
Data []byte `json:"data" xorm:"config_data"`
|
Data []byte `json:"data" xorm:"config_data"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// BuildConfig is the n:n relation between Build and Config
|
// PipelineConfig is the n:n relation between Pipeline and Config
|
||||||
type BuildConfig struct {
|
type PipelineConfig struct {
|
||||||
ConfigID int64 `json:"-" xorm:"UNIQUE(s) NOT NULL 'config_id'"`
|
ConfigID int64 `json:"-" xorm:"UNIQUE(s) NOT NULL 'config_id'"`
|
||||||
BuildID int64 `json:"-" xorm:"UNIQUE(s) NOT NULL 'build_id'"`
|
PipelineID int64 `json:"-" xorm:"UNIQUE(s) NOT NULL 'build_id'"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// Copyright 2022 Woodpecker Authors
|
||||||
// Copyright 2018 Drone.IO Inc.
|
// Copyright 2018 Drone.IO Inc.
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// Copyright 2022 Woodpecker Authors
|
||||||
// Copyright 2018 Drone.IO Inc.
|
// Copyright 2018 Drone.IO Inc.
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@ -14,11 +15,11 @@
|
||||||
|
|
||||||
package model
|
package model
|
||||||
|
|
||||||
// EventType defines the possible types of build events.
|
// EventType defines the possible types of pipeline events.
|
||||||
type EventType string
|
type EventType string
|
||||||
|
|
||||||
// Event represents a build event.
|
// Event represents a pipeline event.
|
||||||
type Event struct {
|
type Event struct {
|
||||||
Repo Repo `json:"repo"`
|
Repo Repo `json:"repo"`
|
||||||
Build Build `json:"build"`
|
Pipeline Pipeline `json:"build"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ import "io"
|
||||||
|
|
||||||
// FileStore persists pipeline artifacts to storage.
|
// FileStore persists pipeline artifacts to storage.
|
||||||
type FileStore interface {
|
type FileStore interface {
|
||||||
FileList(*Build) ([]*File, error)
|
FileList(*Pipeline) ([]*File, error)
|
||||||
FileFind(*Proc, string) (*File, error)
|
FileFind(*Proc, string) (*File, error)
|
||||||
FileRead(*Proc, string) (io.ReadCloser, error)
|
FileRead(*Proc, string) (io.ReadCloser, error)
|
||||||
FileCreate(*File, io.Reader) error
|
FileCreate(*File, io.Reader) error
|
||||||
|
@ -28,7 +28,7 @@ type FileStore interface {
|
||||||
// File represents a pipeline artifact.
|
// File represents a pipeline artifact.
|
||||||
type File struct {
|
type File struct {
|
||||||
ID int64 `json:"id" xorm:"pk autoincr 'file_id'"`
|
ID int64 `json:"id" xorm:"pk autoincr 'file_id'"`
|
||||||
BuildID int64 `json:"-" xorm:"INDEX 'file_build_id'"`
|
PipelineID int64 `json:"-" xorm:"INDEX 'file_build_id'"`
|
||||||
ProcID int64 `json:"proc_id" xorm:"UNIQUE(s) INDEX 'file_proc_id'"`
|
ProcID int64 `json:"proc_id" xorm:"UNIQUE(s) INDEX 'file_proc_id'"`
|
||||||
PID int `json:"pid" xorm:"file_pid"`
|
PID int `json:"pid" xorm:"file_pid"`
|
||||||
Name string `json:"name" xorm:"UNIQUE(s) file_name"`
|
Name string `json:"name" xorm:"UNIQUE(s) file_name"`
|
||||||
|
@ -38,7 +38,7 @@ type File struct {
|
||||||
Passed int `json:"passed" xorm:"file_meta_passed"`
|
Passed int `json:"passed" xorm:"file_meta_passed"`
|
||||||
Failed int `json:"failed" xorm:"file_meta_failed"`
|
Failed int `json:"failed" xorm:"file_meta_failed"`
|
||||||
Skipped int `json:"skipped" xorm:"file_meta_skipped"`
|
Skipped int `json:"skipped" xorm:"file_meta_skipped"`
|
||||||
Data []byte `json:"-" xorm:"file_data"` // TODO: dont store in db but object storage?
|
Data []byte `json:"-" xorm:"file_data"` // TODO: don't store in db but object storage?
|
||||||
}
|
}
|
||||||
|
|
||||||
// TableName return database table name for xorm
|
// TableName return database table name for xorm
|
||||||
|
|
|
@ -15,8 +15,8 @@
|
||||||
|
|
||||||
package model
|
package model
|
||||||
|
|
||||||
// swagger:model build
|
// swagger:model pipeline
|
||||||
type Build struct {
|
type Pipeline struct {
|
||||||
ID int64 `json:"id" xorm:"pk autoincr 'build_id'"`
|
ID int64 `json:"id" xorm:"pk autoincr 'build_id'"`
|
||||||
RepoID int64 `json:"-" xorm:"UNIQUE(s) INDEX 'build_repo_id'"`
|
RepoID int64 `json:"-" xorm:"UNIQUE(s) INDEX 'build_repo_id'"`
|
||||||
Number int64 `json:"number" xorm:"UNIQUE(s) 'build_number'"`
|
Number int64 `json:"number" xorm:"UNIQUE(s) 'build_number'"`
|
||||||
|
@ -55,15 +55,15 @@ type Build struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TableName return database table name for xorm
|
// TableName return database table name for xorm
|
||||||
func (Build) TableName() string {
|
func (Pipeline) TableName() string {
|
||||||
return "builds"
|
return "pipelines"
|
||||||
}
|
}
|
||||||
|
|
||||||
type UpdateBuildStore interface {
|
type UpdatePipelineStore interface {
|
||||||
UpdateBuild(*Build) error
|
UpdatePipeline(*Pipeline) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type BuildOptions struct {
|
type PipelineOptions struct {
|
||||||
Branch string `json:"branch"`
|
Branch string `json:"branch"`
|
||||||
Variables map[string]string `json:"variables"`
|
Variables map[string]string `json:"variables"`
|
||||||
}
|
}
|
|
@ -20,19 +20,19 @@ import "fmt"
|
||||||
// ProcStore persists process information to storage.
|
// ProcStore persists process information to storage.
|
||||||
type ProcStore interface {
|
type ProcStore interface {
|
||||||
ProcLoad(int64) (*Proc, error)
|
ProcLoad(int64) (*Proc, error)
|
||||||
ProcFind(*Build, int) (*Proc, error)
|
ProcFind(*Pipeline, int) (*Proc, error)
|
||||||
ProcChild(*Build, int, string) (*Proc, error)
|
ProcChild(*Pipeline, int, string) (*Proc, error)
|
||||||
ProcList(*Build) ([]*Proc, error)
|
ProcList(*Pipeline) ([]*Proc, error)
|
||||||
ProcCreate([]*Proc) error
|
ProcCreate([]*Proc) error
|
||||||
ProcUpdate(*Proc) error
|
ProcUpdate(*Proc) error
|
||||||
ProcClear(*Build) error
|
ProcClear(*Pipeline) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Proc represents a process in the build pipeline.
|
// Proc represents a process in the pipeline.
|
||||||
// swagger:model proc
|
// swagger:model proc
|
||||||
type Proc struct {
|
type Proc struct {
|
||||||
ID int64 `json:"id" xorm:"pk autoincr 'proc_id'"`
|
ID int64 `json:"id" xorm:"pk autoincr 'proc_id'"`
|
||||||
BuildID int64 `json:"build_id" xorm:"UNIQUE(s) INDEX 'proc_build_id'"`
|
PipelineID int64 `json:"build_id" xorm:"UNIQUE(s) INDEX 'proc_build_id'"`
|
||||||
PID int `json:"pid" xorm:"UNIQUE(s) 'proc_pid'"`
|
PID int `json:"pid" xorm:"UNIQUE(s) 'proc_pid'"`
|
||||||
PPID int `json:"ppid" xorm:"proc_ppid"`
|
PPID int `json:"ppid" xorm:"proc_ppid"`
|
||||||
PGID int `json:"pgid" xorm:"proc_pgid"`
|
PGID int `json:"pgid" xorm:"proc_pgid"`
|
||||||
|
@ -111,8 +111,8 @@ func Tree(procs []*Proc) ([]*Proc, error) {
|
||||||
return nodes, nil
|
return nodes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// BuildStatus determine build status based on corresponding proc list
|
// PipelineStatus determine pipeline status based on corresponding proc list
|
||||||
func BuildStatus(procs []*Proc) StatusValue {
|
func PipelineStatus(procs []*Proc) StatusValue {
|
||||||
status := StatusSuccess
|
status := StatusSuccess
|
||||||
|
|
||||||
for _, p := range procs {
|
for _, p := range procs {
|
||||||
|
|
|
@ -24,7 +24,7 @@ func TestTree(t *testing.T) {
|
||||||
procs := []*Proc{{
|
procs := []*Proc{{
|
||||||
ID: 25,
|
ID: 25,
|
||||||
PID: 2,
|
PID: 2,
|
||||||
BuildID: 6,
|
PipelineID: 6,
|
||||||
PPID: 1,
|
PPID: 1,
|
||||||
PGID: 2,
|
PGID: 2,
|
||||||
Name: "clone",
|
Name: "clone",
|
||||||
|
@ -32,7 +32,7 @@ func TestTree(t *testing.T) {
|
||||||
Error: "0",
|
Error: "0",
|
||||||
}, {
|
}, {
|
||||||
ID: 24,
|
ID: 24,
|
||||||
BuildID: 6,
|
PipelineID: 6,
|
||||||
PID: 1,
|
PID: 1,
|
||||||
PPID: 0,
|
PPID: 0,
|
||||||
PGID: 1,
|
PGID: 1,
|
||||||
|
@ -41,7 +41,7 @@ func TestTree(t *testing.T) {
|
||||||
Error: "1",
|
Error: "1",
|
||||||
}, {
|
}, {
|
||||||
ID: 26,
|
ID: 26,
|
||||||
BuildID: 6,
|
PipelineID: 6,
|
||||||
PID: 3,
|
PID: 3,
|
||||||
PPID: 1,
|
PPID: 1,
|
||||||
PGID: 3,
|
PGID: 3,
|
||||||
|
@ -57,7 +57,7 @@ func TestTree(t *testing.T) {
|
||||||
procs = []*Proc{{
|
procs = []*Proc{{
|
||||||
ID: 25,
|
ID: 25,
|
||||||
PID: 2,
|
PID: 2,
|
||||||
BuildID: 6,
|
PipelineID: 6,
|
||||||
PPID: 1,
|
PPID: 1,
|
||||||
PGID: 2,
|
PGID: 2,
|
||||||
Name: "clone",
|
Name: "clone",
|
||||||
|
|
|
@ -1,3 +1,17 @@
|
||||||
|
// Copyright 2022 Woodpecker Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
package model
|
package model
|
||||||
|
|
||||||
type Redirection struct {
|
type Redirection struct {
|
||||||
|
|
|
@ -31,7 +31,7 @@ var (
|
||||||
|
|
||||||
// SecretService defines a service for managing secrets.
|
// SecretService defines a service for managing secrets.
|
||||||
type SecretService interface {
|
type SecretService interface {
|
||||||
SecretListBuild(*Repo, *Build) ([]*Secret, error)
|
SecretListPipeline(*Repo, *Pipeline) ([]*Secret, error)
|
||||||
// Repository secrets
|
// Repository secrets
|
||||||
SecretFind(*Repo, string) (*Secret, error)
|
SecretFind(*Repo, string) (*Secret, error)
|
||||||
SecretList(*Repo) ([]*Secret, error)
|
SecretList(*Repo) ([]*Secret, error)
|
||||||
|
|
|
@ -26,23 +26,23 @@ import (
|
||||||
"github.com/woodpecker-ci/woodpecker/server/store"
|
"github.com/woodpecker-ci/woodpecker/server/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Approve update the status to pending for blocked build because of a gated repo
|
// Approve update the status to pending for blocked pipeline because of a gated repo
|
||||||
// and start them afterwards
|
// and start them afterwards
|
||||||
func Approve(ctx context.Context, store store.Store, build *model.Build, user *model.User, repo *model.Repo) (*model.Build, error) {
|
func Approve(ctx context.Context, store store.Store, pipeline *model.Pipeline, user *model.User, repo *model.Repo) (*model.Pipeline, error) {
|
||||||
if build.Status != model.StatusBlocked {
|
if pipeline.Status != model.StatusBlocked {
|
||||||
return nil, ErrBadRequest{Msg: fmt.Sprintf("cannot decline a build with status %s", build.Status)}
|
return nil, ErrBadRequest{Msg: fmt.Sprintf("cannot decline a pipeline with status %s", pipeline.Status)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// fetch the build file from the database
|
// fetch the pipeline file from the database
|
||||||
configs, err := store.ConfigsForBuild(build.ID)
|
configs, err := store.ConfigsForPipeline(pipeline.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
msg := fmt.Sprintf("failure to get build config for %s. %s", repo.FullName, err)
|
msg := fmt.Sprintf("failure to get pipeline config for %s. %s", repo.FullName, err)
|
||||||
log.Error().Msg(msg)
|
log.Error().Msg(msg)
|
||||||
return nil, ErrNotFound{Msg: msg}
|
return nil, ErrNotFound{Msg: msg}
|
||||||
}
|
}
|
||||||
|
|
||||||
if build, err = shared.UpdateToStatusPending(store, *build, user.Login); err != nil {
|
if pipeline, err = shared.UpdateToStatusPending(store, *pipeline, user.Login); err != nil {
|
||||||
return nil, fmt.Errorf("error updating build. %s", err)
|
return nil, fmt.Errorf("error updating pipeline. %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var yamls []*remote.FileMeta
|
var yamls []*remote.FileMeta
|
||||||
|
@ -50,19 +50,19 @@ func Approve(ctx context.Context, store store.Store, build *model.Build, user *m
|
||||||
yamls = append(yamls, &remote.FileMeta{Data: y.Data, Name: y.Name})
|
yamls = append(yamls, &remote.FileMeta{Data: y.Data, Name: y.Name})
|
||||||
}
|
}
|
||||||
|
|
||||||
build, buildItems, err := createBuildItems(ctx, store, build, user, repo, yamls, nil)
|
pipeline, pipelineItems, err := createPipelineItems(ctx, store, pipeline, user, repo, yamls, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
msg := fmt.Sprintf("failure to createBuildItems for %s", repo.FullName)
|
msg := fmt.Sprintf("failure to createBuildItems for %s", repo.FullName)
|
||||||
log.Error().Err(err).Msg(msg)
|
log.Error().Err(err).Msg(msg)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
build, err = start(ctx, store, build, user, repo, buildItems)
|
pipeline, err = start(ctx, store, pipeline, user, repo, pipelineItems)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
msg := fmt.Sprintf("failure to start build for %s: %v", repo.FullName, err)
|
msg := fmt.Sprintf("failure to start pipeline for %s: %v", repo.FullName, err)
|
||||||
log.Error().Err(err).Msg(msg)
|
log.Error().Err(err).Msg(msg)
|
||||||
return nil, fmt.Errorf(msg)
|
return nil, fmt.Errorf(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
return build, nil
|
return pipeline, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,13 +27,13 @@ import (
|
||||||
"github.com/woodpecker-ci/woodpecker/server/store"
|
"github.com/woodpecker-ci/woodpecker/server/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Cancel the build and returns the status.
|
// Cancel the pipeline and returns the status.
|
||||||
func Cancel(ctx context.Context, store store.Store, repo *model.Repo, build *model.Build) error {
|
func Cancel(ctx context.Context, store store.Store, repo *model.Repo, pipeline *model.Pipeline) error {
|
||||||
if build.Status != model.StatusRunning && build.Status != model.StatusPending && build.Status != model.StatusBlocked {
|
if pipeline.Status != model.StatusRunning && pipeline.Status != model.StatusPending && pipeline.Status != model.StatusBlocked {
|
||||||
return ErrBadRequest{Msg: "Cannot cancel a non-running or non-pending or non-blocked build"}
|
return ErrBadRequest{Msg: "Cannot cancel a non-running or non-pending or non-blocked pipeline"}
|
||||||
}
|
}
|
||||||
|
|
||||||
procs, err := store.ProcList(build)
|
procs, err := store.ProcList(pipeline)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ErrNotFound{Msg: err.Error()}
|
return ErrNotFound{Msg: err.Error()}
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,7 @@ func Cancel(ctx context.Context, store store.Store, repo *model.Repo, build *mod
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then update the DB status for pending builds
|
// Then update the DB status for pending pipelines
|
||||||
// Running ones will be set when the agents stop on the cancel signal
|
// Running ones will be set when the agents stop on the cancel signal
|
||||||
for _, proc := range procs {
|
for _, proc := range procs {
|
||||||
if proc.State == model.StatusPending {
|
if proc.State == model.StatusPending {
|
||||||
|
@ -85,9 +85,9 @@ func Cancel(ctx context.Context, store store.Store, repo *model.Repo, build *mod
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
killedBuild, err := shared.UpdateToStatusKilled(store, *build)
|
killedBuild, err := shared.UpdateToStatusKilled(store, *pipeline)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msgf("UpdateToStatusKilled: %v", build)
|
log.Error().Err(err).Msgf("UpdateToStatusKilled: %v", pipeline)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,13 +108,13 @@ func Cancel(ctx context.Context, store store.Store, repo *model.Repo, build *mod
|
||||||
func cancelPreviousPipelines(
|
func cancelPreviousPipelines(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
_store store.Store,
|
_store store.Store,
|
||||||
build *model.Build,
|
pipeline *model.Pipeline,
|
||||||
repo *model.Repo,
|
repo *model.Repo,
|
||||||
) error {
|
) error {
|
||||||
// check this event should cancel previous pipelines
|
// check this event should cancel previous pipelines
|
||||||
eventIncluded := false
|
eventIncluded := false
|
||||||
for _, ev := range repo.CancelPreviousPipelineEvents {
|
for _, ev := range repo.CancelPreviousPipelineEvents {
|
||||||
if ev == build.Event {
|
if ev == pipeline.Event {
|
||||||
eventIncluded = true
|
eventIncluded = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -124,38 +124,38 @@ func cancelPreviousPipelines(
|
||||||
}
|
}
|
||||||
|
|
||||||
// get all active activeBuilds
|
// get all active activeBuilds
|
||||||
activeBuilds, err := _store.GetActiveBuildList(repo, -1)
|
activeBuilds, err := _store.GetActivePipelineList(repo, -1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
buildNeedsCancel := func(active *model.Build) (bool, error) {
|
pipelineNeedsCancel := func(active *model.Pipeline) (bool, error) {
|
||||||
// always filter on same event
|
// always filter on same event
|
||||||
if active.Event != build.Event {
|
if active.Event != pipeline.Event {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// find events for the same context
|
// find events for the same context
|
||||||
switch build.Event {
|
switch pipeline.Event {
|
||||||
case model.EventPush:
|
case model.EventPush:
|
||||||
return build.Branch == active.Branch, nil
|
return pipeline.Branch == active.Branch, nil
|
||||||
default:
|
default:
|
||||||
return build.Refspec == active.Refspec, nil
|
return pipeline.Refspec == active.Refspec, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, active := range activeBuilds {
|
for _, active := range activeBuilds {
|
||||||
if active.ID == build.ID {
|
if active.ID == pipeline.ID {
|
||||||
// same build. e.g. self
|
// same pipeline. e.g. self
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
cancel, err := buildNeedsCancel(active)
|
cancel, err := pipelineNeedsCancel(active)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().
|
log.Error().
|
||||||
Err(err).
|
Err(err).
|
||||||
Str("Ref", active.Ref).
|
Str("Ref", active.Ref).
|
||||||
Msg("Error while trying to cancel build, skipping")
|
Msg("Error while trying to cancel pipeline, skipping")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,7 +168,7 @@ func cancelPreviousPipelines(
|
||||||
Err(err).
|
Err(err).
|
||||||
Str("Ref", active.Ref).
|
Str("Ref", active.Ref).
|
||||||
Int64("ID", active.ID).
|
Int64("ID", active.ID).
|
||||||
Msg("Failed to cancel build")
|
Msg("Failed to cancel pipeline")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,12 +24,12 @@ import (
|
||||||
"github.com/woodpecker-ci/woodpecker/server/store"
|
"github.com/woodpecker-ci/woodpecker/server/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
func findOrPersistPipelineConfig(store store.Store, build *model.Build, remoteYamlConfig *remote.FileMeta) (*model.Config, error) {
|
func findOrPersistPipelineConfig(store store.Store, pipeline *model.Pipeline, remoteYamlConfig *remote.FileMeta) (*model.Config, error) {
|
||||||
sha := fmt.Sprintf("%x", sha256.Sum256(remoteYamlConfig.Data))
|
sha := fmt.Sprintf("%x", sha256.Sum256(remoteYamlConfig.Data))
|
||||||
conf, err := store.ConfigFindIdentical(build.RepoID, sha)
|
conf, err := store.ConfigFindIdentical(pipeline.RepoID, sha)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
conf = &model.Config{
|
conf = &model.Config{
|
||||||
RepoID: build.RepoID,
|
RepoID: pipeline.RepoID,
|
||||||
Data: remoteYamlConfig.Data,
|
Data: remoteYamlConfig.Data,
|
||||||
Hash: sha,
|
Hash: sha,
|
||||||
Name: shared.SanitizePath(remoteYamlConfig.Name),
|
Name: shared.SanitizePath(remoteYamlConfig.Name),
|
||||||
|
@ -37,18 +37,18 @@ func findOrPersistPipelineConfig(store store.Store, build *model.Build, remoteYa
|
||||||
err = store.ConfigCreate(conf)
|
err = store.ConfigCreate(conf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// retry in case we receive two hooks at the same time
|
// retry in case we receive two hooks at the same time
|
||||||
conf, err = store.ConfigFindIdentical(build.RepoID, sha)
|
conf, err = store.ConfigFindIdentical(pipeline.RepoID, sha)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buildConfig := &model.BuildConfig{
|
pipelineConfig := &model.PipelineConfig{
|
||||||
ConfigID: conf.ID,
|
ConfigID: conf.ID,
|
||||||
BuildID: build.ID,
|
PipelineID: pipeline.ID,
|
||||||
}
|
}
|
||||||
if err := store.BuildConfigCreate(buildConfig); err != nil {
|
if err := store.PipelineConfigCreate(pipelineConfig); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,8 +28,8 @@ import (
|
||||||
"github.com/woodpecker-ci/woodpecker/server/store"
|
"github.com/woodpecker-ci/woodpecker/server/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Create a new build and start it
|
// Create a new pipeline and start it
|
||||||
func Create(ctx context.Context, _store store.Store, repo *model.Repo, build *model.Build) (*model.Build, error) {
|
func Create(ctx context.Context, _store store.Store, repo *model.Repo, pipeline *model.Pipeline) (*model.Pipeline, error) {
|
||||||
repoUser, err := _store.GetUser(repo.UserID)
|
repoUser, err := _store.GetUser(repo.UserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
msg := fmt.Sprintf("failure to find repo owner via id '%d'", repo.UserID)
|
msg := fmt.Sprintf("failure to find repo owner via id '%d'", repo.UserID)
|
||||||
|
@ -39,7 +39,7 @@ func Create(ctx context.Context, _store store.Store, repo *model.Repo, build *mo
|
||||||
|
|
||||||
// if the remote has a refresh token, the current access token
|
// if the remote has a refresh token, the current access token
|
||||||
// may be stale. Therefore, we should refresh prior to dispatching
|
// may be stale. Therefore, we should refresh prior to dispatching
|
||||||
// the build.
|
// the pipeline.
|
||||||
if refresher, ok := server.Config.Services.Remote.(remote.Refresher); ok {
|
if refresher, ok := server.Config.Services.Remote.(remote.Refresher); ok {
|
||||||
refreshed, err := refresher.Refresh(ctx, repoUser)
|
refreshed, err := refresher.Refresh(ctx, repoUser)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -59,11 +59,11 @@ func Create(ctx context.Context, _store store.Store, repo *model.Repo, build *mo
|
||||||
parseErr error
|
parseErr error
|
||||||
)
|
)
|
||||||
|
|
||||||
// fetch the build file from the remote
|
// fetch the pipeline file from the remote
|
||||||
configFetcher := shared.NewConfigFetcher(server.Config.Services.Remote, server.Config.Services.ConfigService, repoUser, repo, build)
|
configFetcher := shared.NewConfigFetcher(server.Config.Services.Remote, server.Config.Services.ConfigService, repoUser, repo, pipeline)
|
||||||
remoteYamlConfigs, configFetchErr = configFetcher.Fetch(ctx)
|
remoteYamlConfigs, configFetchErr = configFetcher.Fetch(ctx)
|
||||||
if configFetchErr == nil {
|
if configFetchErr == nil {
|
||||||
filtered, parseErr = checkIfFiltered(build, remoteYamlConfigs)
|
filtered, parseErr = checkIfFiltered(pipeline, remoteYamlConfigs)
|
||||||
if parseErr == nil {
|
if parseErr == nil {
|
||||||
if filtered {
|
if filtered {
|
||||||
err := ErrFiltered{Msg: "branch does not match restrictions defined in yaml"}
|
err := ErrFiltered{Msg: "branch does not match restrictions defined in yaml"}
|
||||||
|
@ -71,7 +71,7 @@ func Create(ctx context.Context, _store store.Store, repo *model.Repo, build *mo
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if zeroSteps(build, remoteYamlConfigs) {
|
if zeroSteps(pipeline, remoteYamlConfigs) {
|
||||||
err := ErrFiltered{Msg: "step conditions yield zero runnable steps"}
|
err := ErrFiltered{Msg: "step conditions yield zero runnable steps"}
|
||||||
log.Debug().Str("repo", repo.FullName).Msgf("%v", err)
|
log.Debug().Str("repo", repo.FullName).Msgf("%v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -79,38 +79,38 @@ func Create(ctx context.Context, _store store.Store, repo *model.Repo, build *mo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// update some build fields
|
// update some pipeline fields
|
||||||
build.RepoID = repo.ID
|
pipeline.RepoID = repo.ID
|
||||||
build.Verified = true
|
pipeline.Verified = true
|
||||||
build.Status = model.StatusPending
|
pipeline.Status = model.StatusPending
|
||||||
|
|
||||||
if configFetchErr != nil {
|
if configFetchErr != nil {
|
||||||
log.Debug().Str("repo", repo.FullName).Err(configFetchErr).Msgf("cannot find config '%s' in '%s' with user: '%s'", repo.Config, build.Ref, repoUser.Login)
|
log.Debug().Str("repo", repo.FullName).Err(configFetchErr).Msgf("cannot find config '%s' in '%s' with user: '%s'", repo.Config, pipeline.Ref, repoUser.Login)
|
||||||
build.Started = time.Now().Unix()
|
pipeline.Started = time.Now().Unix()
|
||||||
build.Finished = build.Started
|
pipeline.Finished = pipeline.Started
|
||||||
build.Status = model.StatusError
|
pipeline.Status = model.StatusError
|
||||||
build.Error = fmt.Sprintf("pipeline definition not found in %s", repo.FullName)
|
pipeline.Error = fmt.Sprintf("pipeline definition not found in %s", repo.FullName)
|
||||||
} else if parseErr != nil {
|
} else if parseErr != nil {
|
||||||
log.Debug().Str("repo", repo.FullName).Err(parseErr).Msg("failed to parse yaml")
|
log.Debug().Str("repo", repo.FullName).Err(parseErr).Msg("failed to parse yaml")
|
||||||
build.Started = time.Now().Unix()
|
pipeline.Started = time.Now().Unix()
|
||||||
build.Finished = build.Started
|
pipeline.Finished = pipeline.Started
|
||||||
build.Status = model.StatusError
|
pipeline.Status = model.StatusError
|
||||||
build.Error = fmt.Sprintf("failed to parse pipeline: %s", parseErr.Error())
|
pipeline.Error = fmt.Sprintf("failed to parse pipeline: %s", parseErr.Error())
|
||||||
} else if repo.IsGated {
|
} else if repo.IsGated {
|
||||||
// TODO(336) extend gated feature with an allow/block List
|
// TODO(336) extend gated feature with an allow/block List
|
||||||
build.Status = model.StatusBlocked
|
pipeline.Status = model.StatusBlocked
|
||||||
}
|
}
|
||||||
|
|
||||||
err = _store.CreateBuild(build, build.Procs...)
|
err = _store.CreatePipeline(pipeline, pipeline.Procs...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
msg := fmt.Sprintf("failure to save build for %s", repo.FullName)
|
msg := fmt.Sprintf("failure to save pipeline for %s", repo.FullName)
|
||||||
log.Error().Err(err).Msg(msg)
|
log.Error().Err(err).Msg(msg)
|
||||||
return nil, fmt.Errorf(msg)
|
return nil, fmt.Errorf(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
// persist the build config for historical correctness, restarts, etc
|
// persist the pipeline config for historical correctness, restarts, etc
|
||||||
for _, remoteYamlConfig := range remoteYamlConfigs {
|
for _, remoteYamlConfig := range remoteYamlConfigs {
|
||||||
_, err := findOrPersistPipelineConfig(_store, build, remoteYamlConfig)
|
_, err := findOrPersistPipelineConfig(_store, pipeline, remoteYamlConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
msg := fmt.Sprintf("failure to find or persist pipeline config for %s", repo.FullName)
|
msg := fmt.Sprintf("failure to find or persist pipeline config for %s", repo.FullName)
|
||||||
log.Error().Err(err).Msg(msg)
|
log.Error().Err(err).Msg(msg)
|
||||||
|
@ -118,43 +118,43 @@ func Create(ctx context.Context, _store store.Store, repo *model.Repo, build *mo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if build.Status == model.StatusError {
|
if pipeline.Status == model.StatusError {
|
||||||
if err := publishToTopic(ctx, build, repo); err != nil {
|
if err := publishToTopic(ctx, pipeline, repo); err != nil {
|
||||||
log.Error().Err(err).Msg("publishToTopic")
|
log.Error().Err(err).Msg("publishToTopic")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := updateBuildStatus(ctx, build, repo, repoUser); err != nil {
|
if err := updatePipelineStatus(ctx, pipeline, repo, repoUser); err != nil {
|
||||||
log.Error().Err(err).Msg("updateBuildStatus")
|
log.Error().Err(err).Msg("updatePipelineStatus")
|
||||||
}
|
}
|
||||||
|
|
||||||
return build, nil
|
return pipeline, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
build, buildItems, err := createBuildItems(ctx, _store, build, repoUser, repo, remoteYamlConfigs, nil)
|
pipeline, pipelineItems, err := createPipelineItems(ctx, _store, pipeline, repoUser, repo, remoteYamlConfigs, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
msg := fmt.Sprintf("failure to createBuildItems for %s", repo.FullName)
|
msg := fmt.Sprintf("failure to createPipelineItems for %s", repo.FullName)
|
||||||
log.Error().Err(err).Msg(msg)
|
log.Error().Err(err).Msg(msg)
|
||||||
return nil, fmt.Errorf(msg)
|
return nil, fmt.Errorf(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
if build.Status == model.StatusBlocked {
|
if pipeline.Status == model.StatusBlocked {
|
||||||
if err := publishToTopic(ctx, build, repo); err != nil {
|
if err := publishToTopic(ctx, pipeline, repo); err != nil {
|
||||||
log.Error().Err(err).Msg("publishToTopic")
|
log.Error().Err(err).Msg("publishToTopic")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := updateBuildStatus(ctx, build, repo, repoUser); err != nil {
|
if err := updatePipelineStatus(ctx, pipeline, repo, repoUser); err != nil {
|
||||||
log.Error().Err(err).Msg("updateBuildStatus")
|
log.Error().Err(err).Msg("updatePipelineStatus")
|
||||||
}
|
}
|
||||||
|
|
||||||
return build, nil
|
return pipeline, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
build, err = start(ctx, _store, build, repoUser, repo, buildItems)
|
pipeline, err = start(ctx, _store, pipeline, repoUser, repo, pipelineItems)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
msg := fmt.Sprintf("failure to start build for %s", repo.FullName)
|
msg := fmt.Sprintf("failure to start pipeline for %s", repo.FullName)
|
||||||
log.Error().Err(err).Msg(msg)
|
log.Error().Err(err).Msg(msg)
|
||||||
return nil, fmt.Errorf(msg)
|
return nil, fmt.Errorf(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
return build, nil
|
return pipeline, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,31 +24,31 @@ import (
|
||||||
"github.com/woodpecker-ci/woodpecker/server/store"
|
"github.com/woodpecker-ci/woodpecker/server/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Decline update the status to declined for blocked build because of a gated repo
|
// Decline update the status to declined for blocked pipeline because of a gated repo
|
||||||
func Decline(ctx context.Context, store store.Store, build *model.Build, user *model.User, repo *model.Repo) (*model.Build, error) {
|
func Decline(ctx context.Context, store store.Store, pipeline *model.Pipeline, user *model.User, repo *model.Repo) (*model.Pipeline, error) {
|
||||||
if build.Status != model.StatusBlocked {
|
if pipeline.Status != model.StatusBlocked {
|
||||||
return nil, fmt.Errorf("cannot decline a build with status %s", build.Status)
|
return nil, fmt.Errorf("cannot decline a pipeline with status %s", pipeline.Status)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := shared.UpdateToStatusDeclined(store, *build, user.Login)
|
_, err := shared.UpdateToStatusDeclined(store, *pipeline, user.Login)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error updating build. %s", err)
|
return nil, fmt.Errorf("error updating pipeline. %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if build.Procs, err = store.ProcList(build); err != nil {
|
if pipeline.Procs, err = store.ProcList(pipeline); err != nil {
|
||||||
log.Error().Err(err).Msg("can not get proc list from store")
|
log.Error().Err(err).Msg("can not get proc list from store")
|
||||||
}
|
}
|
||||||
if build.Procs, err = model.Tree(build.Procs); err != nil {
|
if pipeline.Procs, err = model.Tree(pipeline.Procs); err != nil {
|
||||||
log.Error().Err(err).Msg("can not build tree from proc list")
|
log.Error().Err(err).Msg("can not build tree from proc list")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := updateBuildStatus(ctx, build, repo, user); err != nil {
|
if err := updatePipelineStatus(ctx, pipeline, repo, user); err != nil {
|
||||||
log.Error().Err(err).Msg("updateBuildStatus")
|
log.Error().Err(err).Msg("updateBuildStatus")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := publishToTopic(ctx, build, repo); err != nil {
|
if err := publishToTopic(ctx, pipeline, repo); err != nil {
|
||||||
log.Error().Err(err).Msg("publishToTopic")
|
log.Error().Err(err).Msg("publishToTopic")
|
||||||
}
|
}
|
||||||
|
|
||||||
return build, nil
|
return pipeline, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,11 +26,11 @@ import (
|
||||||
"github.com/woodpecker-ci/woodpecker/server/shared"
|
"github.com/woodpecker-ci/woodpecker/server/shared"
|
||||||
)
|
)
|
||||||
|
|
||||||
func zeroSteps(build *model.Build, remoteYamlConfigs []*remote.FileMeta) bool {
|
func zeroSteps(pipeline *model.Pipeline, remoteYamlConfigs []*remote.FileMeta) bool {
|
||||||
b := shared.ProcBuilder{
|
b := shared.ProcBuilder{
|
||||||
Repo: &model.Repo{},
|
Repo: &model.Repo{},
|
||||||
Curr: build,
|
Curr: pipeline,
|
||||||
Last: &model.Build{},
|
Last: &model.Pipeline{},
|
||||||
Netrc: &model.Netrc{},
|
Netrc: &model.Netrc{},
|
||||||
Secs: []*model.Secret{},
|
Secs: []*model.Secret{},
|
||||||
Regs: []*model.Registry{},
|
Regs: []*model.Registry{},
|
||||||
|
@ -38,11 +38,11 @@ func zeroSteps(build *model.Build, remoteYamlConfigs []*remote.FileMeta) bool {
|
||||||
Yamls: remoteYamlConfigs,
|
Yamls: remoteYamlConfigs,
|
||||||
}
|
}
|
||||||
|
|
||||||
buildItems, err := b.Build()
|
pipelineItems, err := b.Build()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if len(buildItems) == 0 {
|
if len(pipelineItems) == 0 {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,14 +51,14 @@ func zeroSteps(build *model.Build, remoteYamlConfigs []*remote.FileMeta) bool {
|
||||||
|
|
||||||
// TODO: parse yaml once and not for each filter function
|
// TODO: parse yaml once and not for each filter function
|
||||||
// Check if at least one pipeline step will be execute otherwise we will just ignore this webhook
|
// Check if at least one pipeline step will be execute otherwise we will just ignore this webhook
|
||||||
func checkIfFiltered(build *model.Build, remoteYamlConfigs []*remote.FileMeta) (bool, error) {
|
func checkIfFiltered(pipeline *model.Pipeline, remoteYamlConfigs []*remote.FileMeta) (bool, error) {
|
||||||
log.Trace().Msgf("hook.branchFiltered(): build branch: '%s' build event: '%s' config count: %d", build.Branch, build.Event, len(remoteYamlConfigs))
|
log.Trace().Msgf("hook.branchFiltered(): pipeline branch: '%s' pipeline event: '%s' config count: %d", pipeline.Branch, pipeline.Event, len(remoteYamlConfigs))
|
||||||
|
|
||||||
matchMetadata := frontend.Metadata{
|
matchMetadata := frontend.Metadata{
|
||||||
Curr: frontend.Build{
|
Curr: frontend.Pipeline{
|
||||||
Event: string(build.Event),
|
Event: string(pipeline.Event),
|
||||||
Commit: frontend.Commit{
|
Commit: frontend.Commit{
|
||||||
Branch: build.Branch,
|
Branch: pipeline.Branch,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -79,7 +79,7 @@ func checkIfFiltered(build *model.Build, remoteYamlConfigs []*remote.FileMeta) (
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore if the pipeline was filtered by the branch (legacy)
|
// ignore if the pipeline was filtered by the branch (legacy)
|
||||||
if !parsedPipelineConfig.Branches.Match(build.Branch) {
|
if !parsedPipelineConfig.Branches.Match(pipeline.Branch) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,16 +23,16 @@ import (
|
||||||
"github.com/woodpecker-ci/woodpecker/server/model"
|
"github.com/woodpecker-ci/woodpecker/server/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
func updateBuildStatus(ctx context.Context, build *model.Build, repo *model.Repo, user *model.User) error {
|
func updatePipelineStatus(ctx context.Context, pipeline *model.Pipeline, repo *model.Repo, user *model.User) error {
|
||||||
for _, proc := range build.Procs {
|
for _, proc := range pipeline.Procs {
|
||||||
// skip child procs
|
// skip child procs
|
||||||
if !proc.IsParent() {
|
if !proc.IsParent() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
err := server.Config.Services.Remote.Status(ctx, user, repo, build, proc)
|
err := server.Config.Services.Remote.Status(ctx, user, repo, pipeline, proc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msgf("error setting commit status for %s/%d", repo.FullName, build.Number)
|
log.Error().Err(err).Msgf("error setting commit status for %s/%d", repo.FullName, pipeline.Number)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,26 +28,26 @@ import (
|
||||||
"github.com/woodpecker-ci/woodpecker/server/store"
|
"github.com/woodpecker-ci/woodpecker/server/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
func createBuildItems(ctx context.Context, store store.Store, build *model.Build, user *model.User, repo *model.Repo, yamls []*remote.FileMeta, envs map[string]string) (*model.Build, []*shared.BuildItem, error) {
|
func createPipelineItems(ctx context.Context, store store.Store, pipeline *model.Pipeline, user *model.User, repo *model.Repo, yamls []*remote.FileMeta, envs map[string]string) (*model.Pipeline, []*shared.PipelineItem, error) {
|
||||||
netrc, err := server.Config.Services.Remote.Netrc(user, repo)
|
netrc, err := server.Config.Services.Remote.Netrc(user, repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("Failed to generate netrc file")
|
log.Error().Err(err).Msg("Failed to generate netrc file")
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the previous build so that we can send status change notifications
|
// get the previous pipeline so that we can send status change notifications
|
||||||
last, err := store.GetBuildLastBefore(repo, build.Branch, build.ID)
|
last, err := store.GetPipelineLastBefore(repo, pipeline.Branch, pipeline.ID)
|
||||||
if err != nil && !errors.Is(err, sql.ErrNoRows) {
|
if err != nil && !errors.Is(err, sql.ErrNoRows) {
|
||||||
log.Error().Err(err).Str("repo", repo.FullName).Msgf("Error getting last build before build number '%d'", build.Number)
|
log.Error().Err(err).Str("repo", repo.FullName).Msgf("Error getting last pipeline before pipeline number '%d'", pipeline.Number)
|
||||||
}
|
}
|
||||||
|
|
||||||
secs, err := server.Config.Services.Secrets.SecretListBuild(repo, build)
|
secs, err := server.Config.Services.Secrets.SecretListPipeline(repo, pipeline)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msgf("Error getting secrets for %s#%d", repo.FullName, build.Number)
|
log.Error().Err(err).Msgf("Error getting secrets for %s#%d", repo.FullName, pipeline.Number)
|
||||||
}
|
}
|
||||||
|
|
||||||
regs, err := server.Config.Services.Registries.RegistryList(repo)
|
regs, err := server.Config.Services.Registries.RegistryList(repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msgf("Error getting registry credentials for %s#%d", repo.FullName, build.Number)
|
log.Error().Err(err).Msgf("Error getting registry credentials for %s#%d", repo.FullName, pipeline.Number)
|
||||||
}
|
}
|
||||||
|
|
||||||
if envs == nil {
|
if envs == nil {
|
||||||
|
@ -60,13 +60,13 @@ func createBuildItems(ctx context.Context, store store.Store, build *model.Build
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for k, v := range build.AdditionalVariables {
|
for k, v := range pipeline.AdditionalVariables {
|
||||||
envs[k] = v
|
envs[k] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
b := shared.ProcBuilder{
|
b := shared.ProcBuilder{
|
||||||
Repo: repo,
|
Repo: repo,
|
||||||
Curr: build,
|
Curr: pipeline,
|
||||||
Last: last,
|
Last: last,
|
||||||
Netrc: netrc,
|
Netrc: netrc,
|
||||||
Secs: secs,
|
Secs: secs,
|
||||||
|
@ -75,16 +75,16 @@ func createBuildItems(ctx context.Context, store store.Store, build *model.Build
|
||||||
Link: server.Config.Server.Host,
|
Link: server.Config.Server.Host,
|
||||||
Yamls: yamls,
|
Yamls: yamls,
|
||||||
}
|
}
|
||||||
buildItems, err := b.Build()
|
pipelineItems, err := b.Build()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
build, uerr := shared.UpdateToStatusError(store, *build, err)
|
pipeline, uerr := shared.UpdateToStatusError(store, *pipeline, err)
|
||||||
if uerr != nil {
|
if uerr != nil {
|
||||||
log.Error().Err(err).Msgf("Error setting error status of build for %s#%d", repo.FullName, build.Number)
|
log.Error().Err(err).Msgf("Error setting error status of pipeline for %s#%d", repo.FullName, pipeline.Number)
|
||||||
}
|
}
|
||||||
return build, nil, err
|
return pipeline, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
build = shared.SetBuildStepsOnBuild(b.Curr, buildItems)
|
pipeline = shared.SetPipelineStepsOnPipeline(b.Curr, pipelineItems)
|
||||||
|
|
||||||
return build, buildItems, nil
|
return pipeline, pipelineItems, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,9 +26,9 @@ import (
|
||||||
"github.com/woodpecker-ci/woodpecker/server/shared"
|
"github.com/woodpecker-ci/woodpecker/server/shared"
|
||||||
)
|
)
|
||||||
|
|
||||||
func queueBuild(build *model.Build, repo *model.Repo, buildItems []*shared.BuildItem) error {
|
func queueBuild(pipeline *model.Pipeline, repo *model.Repo, pipelineItems []*shared.PipelineItem) error {
|
||||||
var tasks []*queue.Task
|
var tasks []*queue.Task
|
||||||
for _, item := range buildItems {
|
for _, item := range pipelineItems {
|
||||||
if item.Proc.State == model.StatusSkipped {
|
if item.Proc.State == model.StatusSkipped {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ func queueBuild(build *model.Build, repo *model.Repo, buildItems []*shared.Build
|
||||||
}
|
}
|
||||||
task.Labels["platform"] = item.Platform
|
task.Labels["platform"] = item.Platform
|
||||||
task.Labels["repo"] = repo.FullName
|
task.Labels["repo"] = repo.FullName
|
||||||
task.Dependencies = taskIds(item.DependsOn, buildItems)
|
task.Dependencies = taskIds(item.DependsOn, pipelineItems)
|
||||||
task.RunOn = item.RunsOn
|
task.RunOn = item.RunsOn
|
||||||
task.DepStatus = make(map[string]string)
|
task.DepStatus = make(map[string]string)
|
||||||
|
|
||||||
|
@ -58,11 +58,11 @@ func queueBuild(build *model.Build, repo *model.Repo, buildItems []*shared.Build
|
||||||
return server.Config.Services.Queue.PushAtOnce(context.Background(), tasks)
|
return server.Config.Services.Queue.PushAtOnce(context.Background(), tasks)
|
||||||
}
|
}
|
||||||
|
|
||||||
func taskIds(dependsOn []string, buildItems []*shared.BuildItem) (taskIds []string) {
|
func taskIds(dependsOn []string, pipelineItems []*shared.PipelineItem) (taskIds []string) {
|
||||||
for _, dep := range dependsOn {
|
for _, dep := range dependsOn {
|
||||||
for _, buildItem := range buildItems {
|
for _, pipelineItem := range pipelineItems {
|
||||||
if buildItem.Proc.Name == dep {
|
if pipelineItem.Proc.Name == dep {
|
||||||
taskIds = append(taskIds, fmt.Sprint(buildItem.Proc.ID))
|
taskIds = append(taskIds, fmt.Sprint(pipelineItem.Proc.ID))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,20 +30,20 @@ import (
|
||||||
"github.com/woodpecker-ci/woodpecker/server/store"
|
"github.com/woodpecker-ci/woodpecker/server/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Restart a build by creating a new one out of the old and start it
|
// Restart a pipeline by creating a new one out of the old and start it
|
||||||
func Restart(ctx context.Context, store store.Store, lastBuild *model.Build, user *model.User, repo *model.Repo, envs map[string]string) (*model.Build, error) {
|
func Restart(ctx context.Context, store store.Store, lastBuild *model.Pipeline, user *model.User, repo *model.Repo, envs map[string]string) (*model.Pipeline, error) {
|
||||||
switch lastBuild.Status {
|
switch lastBuild.Status {
|
||||||
case model.StatusDeclined,
|
case model.StatusDeclined,
|
||||||
model.StatusBlocked:
|
model.StatusBlocked:
|
||||||
return nil, ErrBadRequest{Msg: fmt.Sprintf("cannot restart a build with status %s", lastBuild.Status)}
|
return nil, ErrBadRequest{Msg: fmt.Sprintf("cannot restart a pipeline with status %s", lastBuild.Status)}
|
||||||
}
|
}
|
||||||
|
|
||||||
var pipelineFiles []*remote.FileMeta
|
var pipelineFiles []*remote.FileMeta
|
||||||
|
|
||||||
// fetch the old pipeline config from database
|
// fetch the old pipeline config from database
|
||||||
configs, err := store.ConfigsForBuild(lastBuild.ID)
|
configs, err := store.ConfigsForPipeline(lastBuild.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
msg := fmt.Sprintf("failure to get build config for %s. %s", repo.FullName, err)
|
msg := fmt.Sprintf("failure to get pipeline config for %s. %s", repo.FullName, err)
|
||||||
log.Error().Msgf(msg)
|
log.Error().Msgf(msg)
|
||||||
return nil, ErrNotFound{Msg: msg}
|
return nil, ErrNotFound{Msg: msg}
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ func Restart(ctx context.Context, store store.Store, lastBuild *model.Build, use
|
||||||
newConfig, useOld, err := server.Config.Services.ConfigService.FetchConfig(ctx, repo, lastBuild, currentFileMeta)
|
newConfig, useOld, err := server.Config.Services.ConfigService.FetchConfig(ctx, repo, lastBuild, currentFileMeta)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, ErrBadRequest{
|
return nil, ErrBadRequest{
|
||||||
Msg: fmt.Sprintf("On fetching external build config: %s", err),
|
Msg: fmt.Sprintf("On fetching external pipeline config: %s", err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !useOld {
|
if !useOld {
|
||||||
|
@ -70,12 +70,12 @@ func Restart(ctx context.Context, store store.Store, lastBuild *model.Build, use
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
newBuild := createNewBuildOutOfOld(lastBuild)
|
newBuild := createNewOutOfOld(lastBuild)
|
||||||
newBuild.Parent = lastBuild.ID
|
newBuild.Parent = lastBuild.ID
|
||||||
|
|
||||||
err = store.CreateBuild(newBuild)
|
err = store.CreatePipeline(newBuild)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
msg := fmt.Sprintf("failure to save build for %s", repo.FullName)
|
msg := fmt.Sprintf("failure to save pipeline for %s", repo.FullName)
|
||||||
log.Error().Err(err).Msg(msg)
|
log.Error().Err(err).Msg(msg)
|
||||||
return nil, fmt.Errorf(msg)
|
return nil, fmt.Errorf(msg)
|
||||||
}
|
}
|
||||||
|
@ -87,13 +87,13 @@ func Restart(ctx context.Context, store store.Store, lastBuild *model.Build, use
|
||||||
}
|
}
|
||||||
return newBuild, nil
|
return newBuild, nil
|
||||||
}
|
}
|
||||||
if err := persistBuildConfigs(store, configs, newBuild.ID); err != nil {
|
if err := persistPipelineConfigs(store, configs, newBuild.ID); err != nil {
|
||||||
msg := fmt.Sprintf("failure to persist build config for %s.", repo.FullName)
|
msg := fmt.Sprintf("failure to persist pipeline config for %s.", repo.FullName)
|
||||||
log.Error().Err(err).Msg(msg)
|
log.Error().Err(err).Msg(msg)
|
||||||
return nil, fmt.Errorf(msg)
|
return nil, fmt.Errorf(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
newBuild, buildItems, err := createBuildItems(ctx, store, newBuild, user, repo, pipelineFiles, envs)
|
newBuild, pipelineItems, err := createPipelineItems(ctx, store, newBuild, user, repo, pipelineFiles, envs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, &yaml.PipelineParseError{}) {
|
if errors.Is(err, &yaml.PipelineParseError{}) {
|
||||||
return newBuild, nil
|
return newBuild, nil
|
||||||
|
@ -103,9 +103,9 @@ func Restart(ctx context.Context, store store.Store, lastBuild *model.Build, use
|
||||||
return nil, fmt.Errorf(msg)
|
return nil, fmt.Errorf(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
newBuild, err = start(ctx, store, newBuild, user, repo, buildItems)
|
newBuild, err = start(ctx, store, newBuild, user, repo, pipelineItems)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
msg := fmt.Sprintf("failure to start build for %s", repo.FullName)
|
msg := fmt.Sprintf("failure to start pipeline for %s", repo.FullName)
|
||||||
log.Error().Err(err).Msg(msg)
|
log.Error().Err(err).Msg(msg)
|
||||||
return nil, fmt.Errorf(msg)
|
return nil, fmt.Errorf(msg)
|
||||||
}
|
}
|
||||||
|
@ -114,13 +114,13 @@ func Restart(ctx context.Context, store store.Store, lastBuild *model.Build, use
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: reuse at create.go too
|
// TODO: reuse at create.go too
|
||||||
func persistBuildConfigs(store store.Store, configs []*model.Config, buildID int64) error {
|
func persistPipelineConfigs(store store.Store, configs []*model.Config, pipelineID int64) error {
|
||||||
for _, conf := range configs {
|
for _, conf := range configs {
|
||||||
buildConfig := &model.BuildConfig{
|
pipelineConfig := &model.PipelineConfig{
|
||||||
ConfigID: conf.ID,
|
ConfigID: conf.ID,
|
||||||
BuildID: buildID,
|
PipelineID: pipelineID,
|
||||||
}
|
}
|
||||||
err := store.BuildConfigCreate(buildConfig)
|
err := store.PipelineConfigCreate(pipelineConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -128,7 +128,7 @@ func persistBuildConfigs(store store.Store, configs []*model.Config, buildID int
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createNewBuildOutOfOld(old *model.Build) *model.Build {
|
func createNewOutOfOld(old *model.Pipeline) *model.Pipeline {
|
||||||
new := *old
|
new := *old
|
||||||
new.ID = 0
|
new.ID = 0
|
||||||
new.Number = 0
|
new.Number = 0
|
||||||
|
|
|
@ -24,31 +24,31 @@ import (
|
||||||
"github.com/woodpecker-ci/woodpecker/server/store"
|
"github.com/woodpecker-ci/woodpecker/server/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
// start a build, make sure it was stored persistent in the store before
|
// start a pipeline, make sure it was stored persistent in the store before
|
||||||
func start(ctx context.Context, store store.Store, activeBuild *model.Build, user *model.User, repo *model.Repo, buildItems []*shared.BuildItem) (*model.Build, error) {
|
func start(ctx context.Context, store store.Store, activePipeline *model.Pipeline, user *model.User, repo *model.Repo, pipelineItems []*shared.PipelineItem) (*model.Pipeline, error) {
|
||||||
// call to cancel previous builds if needed
|
// call to cancel previous pipelines if needed
|
||||||
if err := cancelPreviousPipelines(ctx, store, activeBuild, repo); err != nil {
|
if err := cancelPreviousPipelines(ctx, store, activePipeline, repo); err != nil {
|
||||||
// should be not breaking
|
// should be not breaking
|
||||||
log.Error().Err(err).Msg("Failed to cancel previous builds")
|
log.Error().Err(err).Msg("Failed to cancel previous pipelines")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := store.ProcCreate(activeBuild.Procs); err != nil {
|
if err := store.ProcCreate(activePipeline.Procs); err != nil {
|
||||||
log.Error().Err(err).Str("repo", repo.FullName).Msgf("error persisting procs for %s#%d", repo.FullName, activeBuild.Number)
|
log.Error().Err(err).Str("repo", repo.FullName).Msgf("error persisting procs for %s#%d", repo.FullName, activePipeline.Number)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := publishToTopic(ctx, activeBuild, repo); err != nil {
|
if err := publishToTopic(ctx, activePipeline, repo); err != nil {
|
||||||
log.Error().Err(err).Msg("publishToTopic")
|
log.Error().Err(err).Msg("publishToTopic")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := queueBuild(activeBuild, repo, buildItems); err != nil {
|
if err := queueBuild(activePipeline, repo, pipelineItems); err != nil {
|
||||||
log.Error().Err(err).Msg("queueBuild")
|
log.Error().Err(err).Msg("queueBuild")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := updateBuildStatus(ctx, activeBuild, repo, user); err != nil {
|
if err := updatePipelineStatus(ctx, activePipeline, repo, user); err != nil {
|
||||||
log.Error().Err(err).Msg("updateBuildStatus")
|
log.Error().Err(err).Msg("updateBuildStatus")
|
||||||
}
|
}
|
||||||
|
|
||||||
return activeBuild, nil
|
return activePipeline, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,21 +25,21 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// publishToTopic publishes message to UI clients
|
// publishToTopic publishes message to UI clients
|
||||||
func publishToTopic(c context.Context, build *model.Build, repo *model.Repo) (err error) {
|
func publishToTopic(c context.Context, pipeline *model.Pipeline, repo *model.Repo) (err error) {
|
||||||
message := pubsub.Message{
|
message := pubsub.Message{
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
"repo": repo.FullName,
|
"repo": repo.FullName,
|
||||||
"private": strconv.FormatBool(repo.IsSCMPrivate),
|
"private": strconv.FormatBool(repo.IsSCMPrivate),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
buildCopy := *build
|
pipelineCopy := *pipeline
|
||||||
if buildCopy.Procs, err = model.Tree(buildCopy.Procs); err != nil {
|
if pipelineCopy.Procs, err = model.Tree(pipelineCopy.Procs); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
message.Data, _ = json.Marshal(model.Event{
|
message.Data, _ = json.Marshal(model.Event{
|
||||||
Repo: *repo,
|
Repo: *repo,
|
||||||
Build: buildCopy,
|
Pipeline: pipelineCopy,
|
||||||
})
|
})
|
||||||
return server.Config.Services.Pubsub.Publish(c, "topic/events", message)
|
return server.Config.Services.Pubsub.Publish(c, "topic/events", message)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,17 @@
|
||||||
|
// Copyright 2022 Woodpecker Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -9,5 +23,5 @@ import (
|
||||||
|
|
||||||
type Extension interface {
|
type Extension interface {
|
||||||
IsConfigured() bool
|
IsConfigured() bool
|
||||||
FetchConfig(ctx context.Context, repo *model.Repo, build *model.Build, currentFileMeta []*remote.FileMeta) (configData []*remote.FileMeta, useOld bool, err error)
|
FetchConfig(ctx context.Context, repo *model.Repo, pipeline *model.Pipeline, currentFileMeta []*remote.FileMeta) (configData []*remote.FileMeta, useOld bool, err error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,17 @@
|
||||||
|
// Copyright 2022 Woodpecker Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -23,7 +37,7 @@ type config struct {
|
||||||
|
|
||||||
type requestStructure struct {
|
type requestStructure struct {
|
||||||
Repo *model.Repo `json:"repo"`
|
Repo *model.Repo `json:"repo"`
|
||||||
Build *model.Build `json:"build"`
|
Pipeline *model.Pipeline `json:"build"`
|
||||||
Configuration []*config `json:"configs"`
|
Configuration []*config `json:"configs"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,14 +53,14 @@ func (cp *http) IsConfigured() bool {
|
||||||
return cp.endpoint != ""
|
return cp.endpoint != ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cp *http) FetchConfig(ctx context.Context, repo *model.Repo, build *model.Build, currentFileMeta []*remote.FileMeta) (configData []*remote.FileMeta, useOld bool, err error) {
|
func (cp *http) FetchConfig(ctx context.Context, repo *model.Repo, pipeline *model.Pipeline, currentFileMeta []*remote.FileMeta) (configData []*remote.FileMeta, useOld bool, err error) {
|
||||||
currentConfigs := make([]*config, len(currentFileMeta))
|
currentConfigs := make([]*config, len(currentFileMeta))
|
||||||
for i, pipe := range currentFileMeta {
|
for i, pipe := range currentFileMeta {
|
||||||
currentConfigs[i] = &config{Name: pipe.Name, Data: string(pipe.Data)}
|
currentConfigs[i] = &config{Name: pipe.Name, Data: string(pipe.Data)}
|
||||||
}
|
}
|
||||||
|
|
||||||
response := new(responseStructure)
|
response := new(responseStructure)
|
||||||
body := requestStructure{Repo: repo, Build: build, Configuration: currentConfigs}
|
body := requestStructure{Repo: repo, Pipeline: pipeline, Configuration: currentConfigs}
|
||||||
status, err := utils.Send(ctx, "POST", cp.endpoint, cp.privateKey, body, response)
|
status, err := utils.Send(ctx, "POST", cp.endpoint, cp.privateKey, body, response)
|
||||||
if err != nil && status != 204 {
|
if err != nil && status != 204 {
|
||||||
return nil, false, fmt.Errorf("Failed to fetch config via http (%d) %w", status, err)
|
return nil, false, fmt.Errorf("Failed to fetch config via http (%d) %w", status, err)
|
||||||
|
|
|
@ -1,3 +1,17 @@
|
||||||
|
// Copyright 2022 Woodpecker Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
package secrets
|
package secrets
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -24,7 +38,7 @@ func (b *builtin) SecretList(repo *model.Repo) ([]*model.Secret, error) {
|
||||||
return b.store.SecretList(repo, false)
|
return b.store.SecretList(repo, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *builtin) SecretListBuild(repo *model.Repo, build *model.Build) ([]*model.Secret, error) {
|
func (b *builtin) SecretListPipeline(repo *model.Repo, pipeline *model.Pipeline) ([]*model.Secret, error) {
|
||||||
s, err := b.store.SecretList(repo, true)
|
s, err := b.store.SecretList(repo, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -1,3 +1,17 @@
|
||||||
|
// Copyright 2022 Woodpecker Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
package queue
|
package queue
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -241,7 +255,7 @@ func (q *fifo) process() {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
q.resubmitExpiredBuilds()
|
q.resubmitExpiredPipelines()
|
||||||
q.filterWaiting()
|
q.filterWaiting()
|
||||||
for pending, worker := q.assignToWorker(); pending != nil && worker != nil; pending, worker = q.assignToWorker() {
|
for pending, worker := q.assignToWorker(); pending != nil && worker != nil; pending, worker = q.assignToWorker() {
|
||||||
task := pending.Value.(*Task)
|
task := pending.Value.(*Task)
|
||||||
|
@ -303,7 +317,7 @@ func (q *fifo) assignToWorker() (*list.Element, *worker) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *fifo) resubmitExpiredBuilds() {
|
func (q *fifo) resubmitExpiredPipelines() {
|
||||||
for id, state := range q.running {
|
for id, state := range q.running {
|
||||||
if time.Now().After(state.deadline) {
|
if time.Now().After(state.deadline) {
|
||||||
q.pending.PushFront(state.item)
|
q.pending.PushFront(state.item)
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// Copyright 2022 Woodpecker Authors
|
||||||
// Copyright 2018 Drone.IO Inc.
|
// Copyright 2018 Drone.IO Inc.
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@ -213,27 +214,27 @@ func (c *config) Perm(ctx context.Context, u *model.User, r *model.Repo) (*model
|
||||||
}
|
}
|
||||||
|
|
||||||
// File fetches the file from the Bitbucket repository and returns its contents.
|
// File fetches the file from the Bitbucket repository and returns its contents.
|
||||||
func (c *config) File(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, f string) ([]byte, error) {
|
func (c *config) File(ctx context.Context, u *model.User, r *model.Repo, p *model.Pipeline, f string) ([]byte, error) {
|
||||||
config, err := c.newClient(ctx, u).FindSource(r.Owner, r.Name, b.Commit, f)
|
config, err := c.newClient(ctx, u).FindSource(r.Owner, r.Name, p.Commit, f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return []byte(*config), err
|
return []byte(*config), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *config) Dir(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, f string) ([]*remote.FileMeta, error) {
|
func (c *config) Dir(ctx context.Context, u *model.User, r *model.Repo, p *model.Pipeline, f string) ([]*remote.FileMeta, error) {
|
||||||
return nil, fmt.Errorf("Not implemented")
|
return nil, fmt.Errorf("Not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Status creates a build status for the Bitbucket commit.
|
// Status creates a pipeline status for the Bitbucket commit.
|
||||||
func (c *config) Status(ctx context.Context, user *model.User, repo *model.Repo, build *model.Build, proc *model.Proc) error {
|
func (c *config) Status(ctx context.Context, user *model.User, repo *model.Repo, pipeline *model.Pipeline, proc *model.Proc) error {
|
||||||
status := internal.BuildStatus{
|
status := internal.PipelineStatus{
|
||||||
State: convertStatus(build.Status),
|
State: convertStatus(pipeline.Status),
|
||||||
Desc: common.GetBuildStatusDescription(build.Status),
|
Desc: common.GetPipelineStatusDescription(pipeline.Status),
|
||||||
Key: "Woodpecker",
|
Key: "Woodpecker",
|
||||||
URL: common.GetBuildStatusLink(repo, build, nil),
|
URL: common.GetPipelineStatusLink(repo, pipeline, nil),
|
||||||
}
|
}
|
||||||
return c.newClient(ctx, user).CreateStatus(repo.Owner, repo.Name, build.Commit, &status)
|
return c.newClient(ctx, user).CreateStatus(repo.Owner, repo.Name, pipeline.Commit, &status)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Activate activates the repository by registering repository push hooks with
|
// Activate activates the repository by registering repository push hooks with
|
||||||
|
@ -301,8 +302,8 @@ func (c *config) BranchHead(ctx context.Context, u *model.User, r *model.Repo, b
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hook parses the incoming Bitbucket hook and returns the Repository and
|
// Hook parses the incoming Bitbucket hook and returns the Repository and
|
||||||
// Build details. If the hook is unsupported nil values are returned.
|
// Pipeline details. If the hook is unsupported nil values are returned.
|
||||||
func (c *config) Hook(ctx context.Context, req *http.Request) (*model.Repo, *model.Build, error) {
|
func (c *config) Hook(ctx context.Context, req *http.Request) (*model.Repo, *model.Pipeline, error) {
|
||||||
return parseHook(req)
|
return parseHook(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// Copyright 2022 Woodpecker Authors
|
||||||
// Copyright 2018 Drone.IO Inc.
|
// Copyright 2018 Drone.IO Inc.
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@ -195,12 +196,12 @@ func Test_bitbucket(t *testing.T) {
|
||||||
|
|
||||||
g.Describe("When downloading a file", func() {
|
g.Describe("When downloading a file", func() {
|
||||||
g.It("Should return the bytes", func() {
|
g.It("Should return the bytes", func() {
|
||||||
raw, err := c.File(ctx, fakeUser, fakeRepo, fakeBuild, "file")
|
raw, err := c.File(ctx, fakeUser, fakeRepo, fakePipeline, "file")
|
||||||
g.Assert(err).IsNil()
|
g.Assert(err).IsNil()
|
||||||
g.Assert(len(raw) != 0).IsTrue()
|
g.Assert(len(raw) != 0).IsTrue()
|
||||||
})
|
})
|
||||||
g.It("Should handle not found error", func() {
|
g.It("Should handle not found error", func() {
|
||||||
_, err := c.File(ctx, fakeUser, fakeRepo, fakeBuild, "file_not_found")
|
_, err := c.File(ctx, fakeUser, fakeRepo, fakePipeline, "file_not_found")
|
||||||
g.Assert(err).IsNotNil()
|
g.Assert(err).IsNotNil()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -254,7 +255,7 @@ func Test_bitbucket(t *testing.T) {
|
||||||
})
|
})
|
||||||
|
|
||||||
g.It("Should update the status", func() {
|
g.It("Should update the status", func() {
|
||||||
err := c.Status(ctx, fakeUser, fakeRepo, fakeBuild, fakeProc)
|
err := c.Status(ctx, fakeUser, fakeRepo, fakePipeline, fakeProc)
|
||||||
g.Assert(err).IsNil()
|
g.Assert(err).IsNil()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -350,7 +351,7 @@ var (
|
||||||
FullName: "test_name/permission_admin",
|
FullName: "test_name/permission_admin",
|
||||||
}
|
}
|
||||||
|
|
||||||
fakeBuild = &model.Build{
|
fakePipeline = &model.Pipeline{
|
||||||
Commit: "9ecad50",
|
Commit: "9ecad50",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// Copyright 2022 Woodpecker Authors
|
||||||
// Copyright 2018 Drone.IO Inc.
|
// Copyright 2018 Drone.IO Inc.
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@ -129,9 +130,9 @@ func convertWorkspace(from *internal.Workspace) *model.Team {
|
||||||
}
|
}
|
||||||
|
|
||||||
// convertPullHook is a helper function used to convert a Bitbucket pull request
|
// convertPullHook is a helper function used to convert a Bitbucket pull request
|
||||||
// hook to the Woodpecker build struct holding commit information.
|
// hook to the Woodpecker pipeline struct holding commit information.
|
||||||
func convertPullHook(from *internal.PullRequestHook) *model.Build {
|
func convertPullHook(from *internal.PullRequestHook) *model.Pipeline {
|
||||||
return &model.Build{
|
return &model.Pipeline{
|
||||||
Event: model.EventPull,
|
Event: model.EventPull,
|
||||||
Commit: from.PullRequest.Dest.Commit.Hash,
|
Commit: from.PullRequest.Dest.Commit.Hash,
|
||||||
Ref: fmt.Sprintf("refs/heads/%s", from.PullRequest.Dest.Branch.Name),
|
Ref: fmt.Sprintf("refs/heads/%s", from.PullRequest.Dest.Branch.Name),
|
||||||
|
@ -151,9 +152,9 @@ func convertPullHook(from *internal.PullRequestHook) *model.Build {
|
||||||
}
|
}
|
||||||
|
|
||||||
// convertPushHook is a helper function used to convert a Bitbucket push
|
// convertPushHook is a helper function used to convert a Bitbucket push
|
||||||
// hook to the Woodpecker build struct holding commit information.
|
// hook to the Woodpecker pipeline struct holding commit information.
|
||||||
func convertPushHook(hook *internal.PushHook, change *internal.Change) *model.Build {
|
func convertPushHook(hook *internal.PushHook, change *internal.Change) *model.Pipeline {
|
||||||
build := &model.Build{
|
pipeline := &model.Pipeline{
|
||||||
Commit: change.New.Target.Hash,
|
Commit: change.New.Target.Hash,
|
||||||
Link: change.New.Target.Links.HTML.Href,
|
Link: change.New.Target.Links.HTML.Href,
|
||||||
Branch: change.New.Name,
|
Branch: change.New.Name,
|
||||||
|
@ -165,16 +166,16 @@ func convertPushHook(hook *internal.PushHook, change *internal.Change) *model.Bu
|
||||||
}
|
}
|
||||||
switch change.New.Type {
|
switch change.New.Type {
|
||||||
case "tag", "annotated_tag", "bookmark":
|
case "tag", "annotated_tag", "bookmark":
|
||||||
build.Event = model.EventTag
|
pipeline.Event = model.EventTag
|
||||||
build.Ref = fmt.Sprintf("refs/tags/%s", change.New.Name)
|
pipeline.Ref = fmt.Sprintf("refs/tags/%s", change.New.Name)
|
||||||
default:
|
default:
|
||||||
build.Event = model.EventPush
|
pipeline.Event = model.EventPush
|
||||||
build.Ref = fmt.Sprintf("refs/heads/%s", change.New.Name)
|
pipeline.Ref = fmt.Sprintf("refs/heads/%s", change.New.Name)
|
||||||
}
|
}
|
||||||
if len(change.New.Target.Author.Raw) != 0 {
|
if len(change.New.Target.Author.Raw) != 0 {
|
||||||
build.Email = extractEmail(change.New.Target.Author.Raw)
|
pipeline.Email = extractEmail(change.New.Target.Author.Raw)
|
||||||
}
|
}
|
||||||
return build
|
return pipeline
|
||||||
}
|
}
|
||||||
|
|
||||||
// regex for git author fields ("name <name@mail.tld>")
|
// regex for git author fields ("name <name@mail.tld>")
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// Copyright 2022 Woodpecker Authors
|
||||||
// Copyright 2018 Drone.IO Inc.
|
// Copyright 2018 Drone.IO Inc.
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@ -114,7 +115,7 @@ func Test_helper(t *testing.T) {
|
||||||
g.Assert(link).Equal("https://bitbucket.org/foo/bar.git")
|
g.Assert(link).Equal("https://bitbucket.org/foo/bar.git")
|
||||||
})
|
})
|
||||||
|
|
||||||
g.It("should convert pull hook to build", func() {
|
g.It("should convert pull hook to pipeline", func() {
|
||||||
hook := &internal.PullRequestHook{}
|
hook := &internal.PullRequestHook{}
|
||||||
hook.Actor.Login = "octocat"
|
hook.Actor.Login = "octocat"
|
||||||
hook.Actor.Links.Avatar.Href = "https://..."
|
hook.Actor.Links.Avatar.Href = "https://..."
|
||||||
|
@ -127,21 +128,21 @@ func Test_helper(t *testing.T) {
|
||||||
hook.PullRequest.Desc = "updated README"
|
hook.PullRequest.Desc = "updated README"
|
||||||
hook.PullRequest.Updated = time.Now()
|
hook.PullRequest.Updated = time.Now()
|
||||||
|
|
||||||
build := convertPullHook(hook)
|
pipeline := convertPullHook(hook)
|
||||||
g.Assert(build.Event).Equal(model.EventPull)
|
g.Assert(pipeline.Event).Equal(model.EventPull)
|
||||||
g.Assert(build.Author).Equal(hook.Actor.Login)
|
g.Assert(pipeline.Author).Equal(hook.Actor.Login)
|
||||||
g.Assert(build.Avatar).Equal(hook.Actor.Links.Avatar.Href)
|
g.Assert(pipeline.Avatar).Equal(hook.Actor.Links.Avatar.Href)
|
||||||
g.Assert(build.Commit).Equal(hook.PullRequest.Dest.Commit.Hash)
|
g.Assert(pipeline.Commit).Equal(hook.PullRequest.Dest.Commit.Hash)
|
||||||
g.Assert(build.Branch).Equal(hook.PullRequest.Dest.Branch.Name)
|
g.Assert(pipeline.Branch).Equal(hook.PullRequest.Dest.Branch.Name)
|
||||||
g.Assert(build.Link).Equal(hook.PullRequest.Links.HTML.Href)
|
g.Assert(pipeline.Link).Equal(hook.PullRequest.Links.HTML.Href)
|
||||||
g.Assert(build.Ref).Equal("refs/heads/master")
|
g.Assert(pipeline.Ref).Equal("refs/heads/master")
|
||||||
g.Assert(build.Refspec).Equal("change:master")
|
g.Assert(pipeline.Refspec).Equal("change:master")
|
||||||
g.Assert(build.Remote).Equal("https://bitbucket.org/baz/bar")
|
g.Assert(pipeline.Remote).Equal("https://bitbucket.org/baz/bar")
|
||||||
g.Assert(build.Message).Equal(hook.PullRequest.Desc)
|
g.Assert(pipeline.Message).Equal(hook.PullRequest.Desc)
|
||||||
g.Assert(build.Timestamp).Equal(hook.PullRequest.Updated.Unix())
|
g.Assert(pipeline.Timestamp).Equal(hook.PullRequest.Updated.Unix())
|
||||||
})
|
})
|
||||||
|
|
||||||
g.It("should convert push hook to build", func() {
|
g.It("should convert push hook to pipeline", func() {
|
||||||
change := internal.Change{}
|
change := internal.Change{}
|
||||||
change.New.Target.Hash = "73f9c44d"
|
change.New.Target.Hash = "73f9c44d"
|
||||||
change.New.Name = "master"
|
change.New.Name = "master"
|
||||||
|
@ -154,29 +155,29 @@ func Test_helper(t *testing.T) {
|
||||||
hook.Actor.Login = "octocat"
|
hook.Actor.Login = "octocat"
|
||||||
hook.Actor.Links.Avatar.Href = "https://..."
|
hook.Actor.Links.Avatar.Href = "https://..."
|
||||||
|
|
||||||
build := convertPushHook(&hook, &change)
|
pipeline := convertPushHook(&hook, &change)
|
||||||
g.Assert(build.Event).Equal(model.EventPush)
|
g.Assert(pipeline.Event).Equal(model.EventPush)
|
||||||
g.Assert(build.Email).Equal("test@domain.tld")
|
g.Assert(pipeline.Email).Equal("test@domain.tld")
|
||||||
g.Assert(build.Author).Equal(hook.Actor.Login)
|
g.Assert(pipeline.Author).Equal(hook.Actor.Login)
|
||||||
g.Assert(build.Avatar).Equal(hook.Actor.Links.Avatar.Href)
|
g.Assert(pipeline.Avatar).Equal(hook.Actor.Links.Avatar.Href)
|
||||||
g.Assert(build.Commit).Equal(change.New.Target.Hash)
|
g.Assert(pipeline.Commit).Equal(change.New.Target.Hash)
|
||||||
g.Assert(build.Branch).Equal(change.New.Name)
|
g.Assert(pipeline.Branch).Equal(change.New.Name)
|
||||||
g.Assert(build.Link).Equal(change.New.Target.Links.HTML.Href)
|
g.Assert(pipeline.Link).Equal(change.New.Target.Links.HTML.Href)
|
||||||
g.Assert(build.Ref).Equal("refs/heads/master")
|
g.Assert(pipeline.Ref).Equal("refs/heads/master")
|
||||||
g.Assert(build.Message).Equal(change.New.Target.Message)
|
g.Assert(pipeline.Message).Equal(change.New.Target.Message)
|
||||||
g.Assert(build.Timestamp).Equal(change.New.Target.Date.Unix())
|
g.Assert(pipeline.Timestamp).Equal(change.New.Target.Date.Unix())
|
||||||
})
|
})
|
||||||
|
|
||||||
g.It("should convert tag hook to build", func() {
|
g.It("should convert tag hook to pipeline", func() {
|
||||||
change := internal.Change{}
|
change := internal.Change{}
|
||||||
change.New.Name = "v1.0.0"
|
change.New.Name = "v1.0.0"
|
||||||
change.New.Type = "tag"
|
change.New.Type = "tag"
|
||||||
|
|
||||||
hook := internal.PushHook{}
|
hook := internal.PushHook{}
|
||||||
|
|
||||||
build := convertPushHook(&hook, &change)
|
pipeline := convertPushHook(&hook, &change)
|
||||||
g.Assert(build.Event).Equal(model.EventTag)
|
g.Assert(pipeline.Event).Equal(model.EventTag)
|
||||||
g.Assert(build.Ref).Equal("refs/tags/v1.0.0")
|
g.Assert(pipeline.Ref).Equal("refs/tags/v1.0.0")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -155,7 +155,7 @@ func (c *Client) FindSource(owner, name, revision, path string) (*string, error)
|
||||||
return c.do(uri, get, nil, nil)
|
return c.do(uri, get, nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) CreateStatus(owner, name, revision string, status *BuildStatus) error {
|
func (c *Client) CreateStatus(owner, name, revision string, status *PipelineStatus) error {
|
||||||
uri := fmt.Sprintf(pathStatus, c.base, owner, name, revision)
|
uri := fmt.Sprintf(pathStatus, c.base, owner, name, revision)
|
||||||
_, err := c.do(uri, post, status, nil)
|
_, err := c.do(uri, post, status, nil)
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -43,7 +43,7 @@ type WorkspacesResp struct {
|
||||||
Values []*Workspace `json:"values"`
|
Values []*Workspace `json:"values"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type BuildStatus struct {
|
type PipelineStatus struct {
|
||||||
State string `json:"state"`
|
State string `json:"state"`
|
||||||
Key string `json:"key"`
|
Key string `json:"key"`
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
|
|
|
@ -32,8 +32,8 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
// parseHook parses a Bitbucket hook from an http.Request request and returns
|
// parseHook parses a Bitbucket hook from an http.Request request and returns
|
||||||
// Repo and Build detail. If a hook type is unsupported nil values are returned.
|
// Repo and Pipeline detail. If a hook type is unsupported nil values are returned.
|
||||||
func parseHook(r *http.Request) (*model.Repo, *model.Build, error) {
|
func parseHook(r *http.Request) (*model.Repo, *model.Pipeline, error) {
|
||||||
payload, _ := io.ReadAll(r.Body)
|
payload, _ := io.ReadAll(r.Body)
|
||||||
|
|
||||||
switch r.Header.Get(hookEvent) {
|
switch r.Header.Get(hookEvent) {
|
||||||
|
@ -45,9 +45,9 @@ func parseHook(r *http.Request) (*model.Repo, *model.Build, error) {
|
||||||
return nil, nil, nil
|
return nil, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// parsePushHook parses a push hook and returns the Repo and Build details.
|
// parsePushHook parses a push hook and returns the Repo and Pipeline details.
|
||||||
// If the commit type is unsupported nil values are returned.
|
// If the commit type is unsupported nil values are returned.
|
||||||
func parsePushHook(payload []byte) (*model.Repo, *model.Build, error) {
|
func parsePushHook(payload []byte) (*model.Repo, *model.Pipeline, error) {
|
||||||
hook := internal.PushHook{}
|
hook := internal.PushHook{}
|
||||||
|
|
||||||
err := json.Unmarshal(payload, &hook)
|
err := json.Unmarshal(payload, &hook)
|
||||||
|
@ -64,9 +64,9 @@ func parsePushHook(payload []byte) (*model.Repo, *model.Build, error) {
|
||||||
return nil, nil, nil
|
return nil, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// parsePullHook parses a pull request hook and returns the Repo and Build
|
// parsePullHook parses a pull request hook and returns the Repo and Pipeline
|
||||||
// details. If the pull request is closed nil values are returned.
|
// details. If the pull request is closed nil values are returned.
|
||||||
func parsePullHook(payload []byte) (*model.Repo, *model.Build, error) {
|
func parsePullHook(payload []byte) (*model.Repo, *model.Pipeline, error) {
|
||||||
hook := internal.PullRequestHook{}
|
hook := internal.PullRequestHook{}
|
||||||
|
|
||||||
if err := json.Unmarshal(payload, &hook); err != nil {
|
if err := json.Unmarshal(payload, &hook); err != nil {
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// Copyright 2022 Woodpecker Authors
|
||||||
// Copyright 2018 Drone.IO Inc.
|
// Copyright 2018 Drone.IO Inc.
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@ -178,29 +179,29 @@ func (c *Config) Perm(ctx context.Context, u *model.User, repo *model.Repo) (*mo
|
||||||
return client.FindRepoPerms(repo.Owner, repo.Name)
|
return client.FindRepoPerms(repo.Owner, repo.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) File(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, f string) ([]byte, error) {
|
func (c *Config) File(ctx context.Context, u *model.User, r *model.Repo, p *model.Pipeline, f string) ([]byte, error) {
|
||||||
client := internal.NewClientWithToken(ctx, c.URL, c.Consumer, u.Token)
|
client := internal.NewClientWithToken(ctx, c.URL, c.Consumer, u.Token)
|
||||||
|
|
||||||
return client.FindFileForRepo(r.Owner, r.Name, f, b.Ref)
|
return client.FindFileForRepo(r.Owner, r.Name, f, p.Ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) Dir(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, f string) ([]*remote.FileMeta, error) {
|
func (c *Config) Dir(ctx context.Context, u *model.User, r *model.Repo, p *model.Pipeline, f string) ([]*remote.FileMeta, error) {
|
||||||
return nil, fmt.Errorf("Not implemented")
|
return nil, fmt.Errorf("Not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Status is not supported by the bitbucketserver driver.
|
// Status is not supported by the bitbucketserver driver.
|
||||||
func (c *Config) Status(ctx context.Context, user *model.User, repo *model.Repo, build *model.Build, proc *model.Proc) error {
|
func (c *Config) Status(ctx context.Context, user *model.User, repo *model.Repo, pipeline *model.Pipeline, proc *model.Proc) error {
|
||||||
status := internal.BuildStatus{
|
status := internal.PipelineStatus{
|
||||||
State: convertStatus(build.Status),
|
State: convertStatus(pipeline.Status),
|
||||||
Desc: common.GetBuildStatusDescription(build.Status),
|
Desc: common.GetPipelineStatusDescription(pipeline.Status),
|
||||||
Name: fmt.Sprintf("Woodpecker #%d - %s", build.Number, build.Branch),
|
Name: fmt.Sprintf("Woodpecker #%d - %s", pipeline.Number, pipeline.Branch),
|
||||||
Key: "Woodpecker",
|
Key: "Woodpecker",
|
||||||
URL: common.GetBuildStatusLink(repo, build, nil),
|
URL: common.GetPipelineStatusLink(repo, pipeline, nil),
|
||||||
}
|
}
|
||||||
|
|
||||||
client := internal.NewClientWithToken(ctx, c.URL, c.Consumer, user.Token)
|
client := internal.NewClientWithToken(ctx, c.URL, c.Consumer, user.Token)
|
||||||
|
|
||||||
return client.CreateStatus(build.Commit, &status)
|
return client.CreateStatus(pipeline.Commit, &status)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) Netrc(user *model.User, r *model.Repo) (*model.Netrc, error) {
|
func (c *Config) Netrc(user *model.User, r *model.Repo) (*model.Netrc, error) {
|
||||||
|
@ -247,7 +248,7 @@ func (c *Config) Deactivate(ctx context.Context, u *model.User, r *model.Repo, l
|
||||||
return client.DeleteHook(r.Owner, r.Name, link)
|
return client.DeleteHook(r.Owner, r.Name, link)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) Hook(ctx context.Context, r *http.Request) (*model.Repo, *model.Build, error) {
|
func (c *Config) Hook(ctx context.Context, r *http.Request) (*model.Repo, *model.Pipeline, error) {
|
||||||
return parseHook(r, c.URL)
|
return parseHook(r, c.URL)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// Copyright 2022 Woodpecker Authors
|
||||||
// Copyright 2018 Drone.IO Inc.
|
// Copyright 2018 Drone.IO Inc.
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@ -79,8 +80,8 @@ func convertRepo(from *internal.Repo) *model.Repo {
|
||||||
}
|
}
|
||||||
|
|
||||||
// convertPushHook is a helper function used to convert a Bitbucket push
|
// convertPushHook is a helper function used to convert a Bitbucket push
|
||||||
// hook to the Woodpecker build struct holding commit information.
|
// hook to the Woodpecker pipeline struct holding commit information.
|
||||||
func convertPushHook(hook *internal.PostHook, baseURL string) *model.Build {
|
func convertPushHook(hook *internal.PostHook, baseURL string) *model.Pipeline {
|
||||||
branch := strings.TrimPrefix(
|
branch := strings.TrimPrefix(
|
||||||
strings.TrimPrefix(
|
strings.TrimPrefix(
|
||||||
hook.RefChanges[0].RefID,
|
hook.RefChanges[0].RefID,
|
||||||
|
@ -95,7 +96,7 @@ func convertPushHook(hook *internal.PostHook, baseURL string) *model.Build {
|
||||||
authorLabel = authorLabel[0:37] + "..."
|
authorLabel = authorLabel[0:37] + "..."
|
||||||
}
|
}
|
||||||
|
|
||||||
build := &model.Build{
|
pipeline := &model.Pipeline{
|
||||||
Commit: hook.RefChanges[0].ToHash, // TODO check for index value
|
Commit: hook.RefChanges[0].ToHash, // TODO check for index value
|
||||||
Branch: branch,
|
Branch: branch,
|
||||||
Message: hook.Changesets.Values[0].ToCommit.Message, // TODO check for index Values
|
Message: hook.Changesets.Values[0].ToCommit.Message, // TODO check for index Values
|
||||||
|
@ -107,12 +108,12 @@ func convertPushHook(hook *internal.PostHook, baseURL string) *model.Build {
|
||||||
Link: fmt.Sprintf("%s/projects/%s/repos/%s/commits/%s", baseURL, hook.Repository.Project.Key, hook.Repository.Slug, hook.RefChanges[0].ToHash),
|
Link: fmt.Sprintf("%s/projects/%s/repos/%s/commits/%s", baseURL, hook.Repository.Project.Key, hook.Repository.Slug, hook.RefChanges[0].ToHash),
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(hook.RefChanges[0].RefID, "refs/tags/") {
|
if strings.HasPrefix(hook.RefChanges[0].RefID, "refs/tags/") {
|
||||||
build.Event = model.EventTag
|
pipeline.Event = model.EventTag
|
||||||
} else {
|
} else {
|
||||||
build.Event = model.EventPush
|
pipeline.Event = model.EventPush
|
||||||
}
|
}
|
||||||
|
|
||||||
return build
|
return pipeline
|
||||||
}
|
}
|
||||||
|
|
||||||
// convertUser is a helper function used to convert a Bitbucket user account
|
// convertUser is a helper function used to convert a Bitbucket user account
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue