diff --git a/agent/runner.go b/agent/runner.go index 6ed5283b7..ee096e139 100644 --- a/agent/runner.go +++ b/agent/runner.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -80,20 +81,20 @@ func (r *Runner) Run(ctx context.Context) error { timeout = time.Duration(minutes) * time.Minute } - repoName := extractRepositoryName(work.Config) // hack - buildNumber := extractBuildNumber(work.Config) // hack + repoName := extractRepositoryName(work.Config) // hack + pipelineNumber := extractPipelineNumber(work.Config) // hack r.counter.Add( work.ID, timeout, repoName, - buildNumber, + pipelineNumber, ) defer r.counter.Done(work.ID) logger := log.With(). Str("repo", repoName). - Str("build", buildNumber). + Str("pipeline", pipelineNumber). Str("id", work.ID). Logger() @@ -288,6 +289,10 @@ func (r *Runner) Run(ctx context.Context) error { // TODO: find better way to update this state and move it to pipeline to have the same env in cli-exec state.Pipeline.Step.Environment["CI_MACHINE"] = r.hostname + state.Pipeline.Step.Environment["CI_PIPELINE_STATUS"] = "success" + state.Pipeline.Step.Environment["CI_PIPELINE_STARTED"] = strconv.FormatInt(state.Pipeline.Time, 10) + state.Pipeline.Step.Environment["CI_PIPELINE_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10) + // DEPRECATED state.Pipeline.Step.Environment["CI_BUILD_STATUS"] = "success" state.Pipeline.Step.Environment["CI_BUILD_STARTED"] = strconv.FormatInt(state.Pipeline.Time, 10) state.Pipeline.Step.Environment["CI_BUILD_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10) @@ -299,6 +304,8 @@ func (r *Runner) Run(ctx context.Context) error { state.Pipeline.Step.Environment["CI_SYSTEM_ARCH"] = runtime.GOOS + "/" + runtime.GOARCH if state.Pipeline.Error != nil { + state.Pipeline.Step.Environment["CI_PIPELINE_STATUS"] = "failure" + // DEPRECATED state.Pipeline.Step.Environment["CI_BUILD_STATUS"] = "failure" state.Pipeline.Step.Environment["CI_JOB_STATUS"] = "failure" } @@ -311,9 +318,9 @@ func (r *Runner) Run(ctx context.Context) error { pipeline.WithTracer(defaultTracer), pipeline.WithEngine(*r.engine), pipeline.WithDescription(map[string]string{ - "ID": work.ID, - "Repo": repoName, - "Build": buildNumber, + "ID": work.ID, + "Repo": repoName, + "Pipeline": pipelineNumber, }), ).Run() @@ -363,7 +370,7 @@ func extractRepositoryName(config *backend.Config) string { return config.Stages[0].Steps[0].Environment["CI_REPO"] } -// extract build number from the configuration -func extractBuildNumber(config *backend.Config) string { - return config.Stages[0].Steps[0].Environment["CI_BUILD_NUMBER"] +// extract pipeline number from the configuration +func extractPipelineNumber(config *backend.Config) string { + return config.Stages[0].Steps[0].Environment["CI_PIPELINE_NUMBER"] } diff --git a/agent/state.go b/agent/state.go index 3690e954c..e5cb058af 100644 --- a/agent/state.go +++ b/agent/state.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -29,23 +30,23 @@ type State struct { } type Info struct { - ID string `json:"id"` - Repo string `json:"repository"` - Build string `json:"build_number"` - Started time.Time `json:"build_started"` - Timeout time.Duration `json:"build_timeout"` + ID string `json:"id"` + Repo string `json:"repository"` + Pipeline string `json:"build_number"` + Started time.Time `json:"build_started"` + Timeout time.Duration `json:"build_timeout"` } -func (s *State) Add(id string, timeout time.Duration, repo, build string) { +func (s *State) Add(id string, timeout time.Duration, repo, pipeline string) { s.Lock() s.Polling-- s.Running++ s.Metadata[id] = Info{ - ID: id, - Repo: repo, - Build: build, - Timeout: timeout, - Started: time.Now().UTC(), + ID: id, + Repo: repo, + Pipeline: pipeline, + Timeout: timeout, + Started: time.Now().UTC(), } s.Unlock() } diff --git a/cli/build/build.go b/cli/build/build.go deleted file mode 100644 index 8ef0d0df5..000000000 --- a/cli/build/build.go +++ /dev/null @@ -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, - }, -} diff --git a/cli/build/build_approve.go b/cli/build/build_approve.go deleted file mode 100644 index 5f5b7da24..000000000 --- a/cli/build/build_approve.go +++ /dev/null @@ -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: " ", - 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 -} diff --git a/cli/build/build_decline.go b/cli/build/build_decline.go deleted file mode 100644 index ea8a3df13..000000000 --- a/cli/build/build_decline.go +++ /dev/null @@ -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: " ", - 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 -} diff --git a/cli/build/build_info.go b/cli/build/build_info.go deleted file mode 100644 index a5e8e3a39..000000000 --- a/cli/build/build_info.go +++ /dev/null @@ -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: " [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 }} -` diff --git a/cli/build/build_kill.go b/cli/build/build_kill.go deleted file mode 100644 index 742061896..000000000 --- a/cli/build/build_kill.go +++ /dev/null @@ -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: " ", - 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 -} diff --git a/cli/build/build_last.go b/cli/build/build_last.go deleted file mode 100644 index 3638e15ec..000000000 --- a/cli/build/build_last.go +++ /dev/null @@ -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: "", - 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) -} diff --git a/cli/build/build_logs.go b/cli/build/build_logs.go deleted file mode 100644 index 5b709a4ab..000000000 --- a/cli/build/build_logs.go +++ /dev/null @@ -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: " [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 -} diff --git a/cli/build/build_ps.go b/cli/build/build_ps.go deleted file mode 100644 index 5c9b9aecd..000000000 --- a/cli/build/build_ps.go +++ /dev/null @@ -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: " [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 }} -` diff --git a/cli/build/build_queue.go b/cli/build/build_queue.go deleted file mode 100644 index cb8ad7d47..000000000 --- a/cli/build/build_queue.go +++ /dev/null @@ -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 }} -` diff --git a/cli/build/build_start.go b/cli/build/build_start.go deleted file mode 100644 index 1cc3578aa..000000000 --- a/cli/build/build_start.go +++ /dev/null @@ -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: " [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 -} diff --git a/cli/build/build_stop.go b/cli/build/build_stop.go deleted file mode 100644 index e2134875b..000000000 --- a/cli/build/build_stop.go +++ /dev/null @@ -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: " [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 -} diff --git a/cli/cron/cron_list.go b/cli/cron/cron_list.go index d7e2b8880..e8a8363bd 100644 --- a/cli/cron/cron_list.go +++ b/cli/cron/cron_list.go @@ -1,3 +1,17 @@ +// Copyright 2022 Woodpecker Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package cron import ( @@ -53,7 +67,7 @@ func cronList(c *cli.Context) error { return nil } -// template for build list information +// template for pipeline list information var tmplCronList = "\x1b[33m{{ .Name }} \x1b[0m" + ` ID: {{ .ID }} Branch: {{ .Branch }} diff --git a/cli/deploy/deploy.go b/cli/deploy/deploy.go index b48c156a2..9d9db3cd6 100644 --- a/cli/deploy/deploy.go +++ b/cli/deploy/deploy.go @@ -1,3 +1,17 @@ +// Copyright 2022 Woodpecker Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package deploy import ( @@ -17,7 +31,7 @@ import ( var Command = &cli.Command{ Name: "deploy", Usage: "deploy code", - ArgsUsage: " ", + ArgsUsage: " ", Action: deploy, Flags: append(common.GlobalFlags, common.FormatFlag(tmplDeployInfo), @@ -60,33 +74,33 @@ func deploy(c *cli.Context) error { event := c.String("event") status := c.String("status") - buildArg := c.Args().Get(1) + pipelineArg := c.Args().Get(1) var number int - if buildArg == "last" { - // Fetch the build number from the last build - builds, berr := client.BuildList(owner, name) + if pipelineArg == "last" { + // Fetch the pipeline number from the last pipeline + pipelines, berr := client.PipelineList(owner, name) if berr != nil { return berr } - for _, build := range builds { - if branch != "" && build.Branch != branch { + for _, pipeline := range pipelines { + if branch != "" && pipeline.Branch != branch { continue } - if event != "" && build.Event != event { + if event != "" && pipeline.Event != event { continue } - if status != "" && build.Status != status { + if status != "" && pipeline.Status != status { continue } - if build.Number > number { - number = build.Number + if pipeline.Number > number { + number = pipeline.Number } } if number == 0 { - return fmt.Errorf("Cannot deploy failure build") + return fmt.Errorf("Cannot deploy failure pipeline") } } else { - number, err = strconv.Atoi(buildArg) + number, err = strconv.Atoi(pipelineArg) if err != nil { return err } diff --git a/cli/exec/exec.go b/cli/exec/exec.go index 587a25cf4..631ede3b9 100644 --- a/cli/exec/exec.go +++ b/cli/exec/exec.go @@ -1,3 +1,17 @@ +// Copyright 2022 Woodpecker Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package exec import ( @@ -30,7 +44,7 @@ import ( // Command exports the exec command. var Command = &cli.Command{ Name: "exec", - Usage: "execute a local build", + Usage: "execute a local pipeline", ArgsUsage: "[path/to/.woodpecker.yml]", Action: run, Flags: append(common.GlobalFlags, flags...), @@ -231,16 +245,16 @@ func metadataFromContext(c *cli.Context, axis matrix.Axis) frontend.Metadata { Remote: c.String("repo-remote-url"), Private: c.Bool("repo-private"), }, - Curr: frontend.Build{ - Number: c.Int64("build-number"), - Parent: c.Int64("parent-build-number"), - Created: c.Int64("build-created"), - Started: c.Int64("build-started"), - Finished: c.Int64("build-finished"), - Status: c.String("build-status"), - Event: c.String("build-event"), - Link: c.String("build-link"), - Target: c.String("build-target"), + Curr: frontend.Pipeline{ + Number: c.Int64("pipeline-number"), + Parent: c.Int64("pipeline-parent"), + Created: c.Int64("pipeline-created"), + Started: c.Int64("pipeline-started"), + Finished: c.Int64("pipeline-finished"), + Status: c.String("pipeline-status"), + Event: c.String("pipeline-event"), + Link: c.String("pipeline-link"), + Target: c.String("pipeline-target"), Commit: frontend.Commit{ Sha: c.String("commit-sha"), Ref: c.String("commit-ref"), @@ -254,14 +268,14 @@ func metadataFromContext(c *cli.Context, axis matrix.Axis) frontend.Metadata { }, }, }, - Prev: frontend.Build{ - Number: c.Int64("prev-build-number"), - Created: c.Int64("prev-build-created"), - Started: c.Int64("prev-build-started"), - Finished: c.Int64("prev-build-finished"), - Status: c.String("prev-build-status"), - Event: c.String("prev-build-event"), - Link: c.String("prev-build-link"), + Prev: frontend.Pipeline{ + Number: c.Int64("prev-pipeline-number"), + Created: c.Int64("prev-pipeline-created"), + Started: c.Int64("prev-pipeline-started"), + Finished: c.Int64("prev-pipeline-finished"), + Status: c.String("prev-pipeline-status"), + Event: c.String("prev-pipeline-event"), + Link: c.String("prev-pipeline-link"), Commit: frontend.Commit{ Sha: c.String("prev-commit-sha"), Ref: c.String("prev-commit-ref"), diff --git a/cli/exec/flags.go b/cli/exec/flags.go index 144546c38..abfcc95e3 100644 --- a/cli/exec/flags.go +++ b/cli/exec/flags.go @@ -26,19 +26,19 @@ var flags = []cli.Flag{ &cli.BoolFlag{ EnvVars: []string{"WOODPECKER_LOCAL"}, Name: "local", - Usage: "build from local directory", + Usage: "run from local directory", Value: true, }, &cli.DurationFlag{ EnvVars: []string{"WOODPECKER_TIMEOUT"}, Name: "timeout", - Usage: "build timeout", + Usage: "pipeline timeout", Value: time.Hour, }, &cli.StringSliceFlag{ EnvVars: []string{"WOODPECKER_VOLUMES"}, Name: "volumes", - Usage: "build volumes", + Usage: "pipeline volumes", }, &cli.StringSliceFlag{ EnvVars: []string{"WOODPECKER_NETWORKS"}, @@ -131,41 +131,41 @@ var flags = []cli.Flag{ Name: "repo-private", }, &cli.IntFlag{ - EnvVars: []string{"CI_BUILD_NUMBER"}, - Name: "build-number", + EnvVars: []string{"CI_PIPELINE_NUMBER"}, + Name: "pipeline-number", }, &cli.IntFlag{ - EnvVars: []string{"CI_PARENT_BUILD_NUMBER"}, - Name: "parent-build-number", + EnvVars: []string{"CI_PIPELINE_PARENT"}, + Name: "pipeline-parent", }, &cli.Int64Flag{ - EnvVars: []string{"CI_BUILD_CREATED"}, - Name: "build-created", + EnvVars: []string{"CI_PIPELINE_CREATED"}, + Name: "pipeline-created", }, &cli.Int64Flag{ - EnvVars: []string{"CI_BUILD_STARTED"}, - Name: "build-started", + EnvVars: []string{"CI_PIPELINE_STARTED"}, + Name: "pipeline-started", }, &cli.Int64Flag{ - EnvVars: []string{"CI_BUILD_FINISHED"}, - Name: "build-finished", + EnvVars: []string{"CI_PIPELINE_FINISHED"}, + Name: "pipeline-finished", }, &cli.StringFlag{ - EnvVars: []string{"CI_BUILD_STATUS"}, - Name: "build-status", + EnvVars: []string{"CI_PIPELINE_STATUS"}, + Name: "pipeline-status", }, &cli.StringFlag{ - EnvVars: []string{"CI_BUILD_EVENT"}, - Name: "build-event", + EnvVars: []string{"CI_PIPELINE_EVENT"}, + Name: "pipeline-event", Value: "manual", }, &cli.StringFlag{ - EnvVars: []string{"CI_BUILD_LINK"}, - Name: "build-link", + EnvVars: []string{"CI_PIPELINE_LINK"}, + Name: "pipeline-link", }, &cli.StringFlag{ - EnvVars: []string{"CI_BUILD_TARGET"}, - Name: "build-target", + EnvVars: []string{"CI_PIPELINE_TARGET"}, + Name: "pipeline-target", }, &cli.StringFlag{ EnvVars: []string{"CI_COMMIT_SHA"}, @@ -200,32 +200,32 @@ var flags = []cli.Flag{ Name: "commit-author-email", }, &cli.IntFlag{ - EnvVars: []string{"CI_PREV_BUILD_NUMBER"}, - Name: "prev-build-number", + EnvVars: []string{"CI_PREV_PIPELINE_NUMBER"}, + Name: "prev-pipeline-number", }, &cli.Int64Flag{ - EnvVars: []string{"CI_PREV_BUILD_CREATED"}, - Name: "prev-build-created", + EnvVars: []string{"CI_PREV_PIPELINE_CREATED"}, + Name: "prev-pipeline-created", }, &cli.Int64Flag{ - EnvVars: []string{"CI_PREV_BUILD_STARTED"}, - Name: "prev-build-started", + EnvVars: []string{"CI_PREV_PIPELINE_STARTED"}, + Name: "prev-pipeline-started", }, &cli.Int64Flag{ - EnvVars: []string{"CI_PREV_BUILD_FINISHED"}, - Name: "prev-build-finished", + EnvVars: []string{"CI_PREV_PIPELINE_FINISHED"}, + Name: "prev-pipeline-finished", }, &cli.StringFlag{ - EnvVars: []string{"CI_PREV_BUILD_STATUS"}, - Name: "prev-build-status", + EnvVars: []string{"CI_PREV_PIPELINE_STATUS"}, + Name: "prev-pipeline-status", }, &cli.StringFlag{ - EnvVars: []string{"CI_PREV_BUILD_EVENT"}, - Name: "prev-build-event", + EnvVars: []string{"CI_PREV_PIPELINE_EVENT"}, + Name: "prev-pipeline-event", }, &cli.StringFlag{ - EnvVars: []string{"CI_PREV_BUILD_LINK"}, - Name: "prev-build-link", + EnvVars: []string{"CI_PREV_PIPELINE_LINK"}, + Name: "prev-pipeline-link", }, &cli.StringFlag{ EnvVars: []string{"CI_PREV_COMMIT_SHA"}, diff --git a/cli/exec/line.go b/cli/exec/line.go index 865d6fc33..07b96e28a 100644 --- a/cli/exec/line.go +++ b/cli/exec/line.go @@ -1,3 +1,17 @@ +// Copyright 2022 Woodpecker Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package exec import ( diff --git a/cli/log/log.go b/cli/log/log.go index 5e9e58164..255b8286c 100644 --- a/cli/log/log.go +++ b/cli/log/log.go @@ -1,3 +1,17 @@ +// Copyright 2022 Woodpecker Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package log import ( @@ -6,7 +20,7 @@ import ( "github.com/woodpecker-ci/woodpecker/cli/common" ) -// Command exports the build command set. +// Command exports the log command set. var Command = &cli.Command{ Name: "log", Usage: "manage logs", diff --git a/cli/log/log_purge.go b/cli/log/log_purge.go index 655ab44bf..e86d335d5 100644 --- a/cli/log/log_purge.go +++ b/cli/log/log_purge.go @@ -1,3 +1,17 @@ +// Copyright 2022 Woodpecker Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package log import ( @@ -13,7 +27,7 @@ import ( var logPurgeCmd = &cli.Command{ Name: "purge", Usage: "purge a log", - ArgsUsage: " ", + ArgsUsage: " ", Action: logPurge, Flags: common.GlobalFlags, } @@ -39,6 +53,6 @@ func logPurge(c *cli.Context) (err error) { return err } - fmt.Printf("Purging logs for build %s/%s#%d\n", owner, name, number) + fmt.Printf("Purging logs for pipeline %s/%s#%d\n", owner, name, number) return nil } diff --git a/cli/pipeline/approve.go b/cli/pipeline/approve.go new file mode 100644 index 000000000..d2dbcd092 --- /dev/null +++ b/cli/pipeline/approve.go @@ -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: " ", + 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 +} diff --git a/cli/build/build_create.go b/cli/pipeline/create.go similarity index 51% rename from cli/build/build_create.go rename to cli/pipeline/create.go index 5e77305fe..da327d040 100644 --- a/cli/build/build_create.go +++ b/cli/pipeline/create.go @@ -1,4 +1,18 @@ -package build +// Copyright 2022 Woodpecker Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package pipeline import ( "os" @@ -13,16 +27,16 @@ import ( "github.com/woodpecker-ci/woodpecker/cli/internal" ) -var buildCreateCmd = &cli.Command{ +var pipelineCreateCmd = &cli.Command{ Name: "create", - Usage: "create new build", + Usage: "create new pipeline", ArgsUsage: "", - Action: buildCreate, + Action: pipelineCreate, Flags: append(common.GlobalFlags, - common.FormatFlag(tmplBuildList), + common.FormatFlag(tmplPipelineList), &cli.StringFlag{ Name: "branch", - Usage: "branch to create build from", + Usage: "branch to create pipeline from", Required: true, }, &cli.StringSliceFlag{ @@ -32,7 +46,7 @@ var buildCreateCmd = &cli.Command{ ), } -func buildCreate(c *cli.Context) error { +func pipelineCreate(c *cli.Context) error { repo := c.Args().First() owner, name, err := internal.ParseRepo(repo) @@ -55,12 +69,12 @@ func buildCreate(c *cli.Context) error { } } - options := &woodpecker.BuildOptions{ + options := &woodpecker.PipelineOptions{ Branch: branch, Variables: variables, } - build, err := client.BuildCreate(owner, name, options) + pipeline, err := client.PipelineCreate(owner, name, options) if err != nil { return err } @@ -70,7 +84,7 @@ func buildCreate(c *cli.Context) error { return err } - if err := tmpl.Execute(os.Stdout, build); err != nil { + if err := tmpl.Execute(os.Stdout, pipeline); err != nil { return err } diff --git a/cli/pipeline/decline.go b/cli/pipeline/decline.go new file mode 100644 index 000000000..2335d4925 --- /dev/null +++ b/cli/pipeline/decline.go @@ -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: " ", + 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 +} diff --git a/cli/pipeline/info.go b/cli/pipeline/info.go new file mode 100644 index 000000000..9c6aaea90 --- /dev/null +++ b/cli/pipeline/info.go @@ -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: " [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 }} +` diff --git a/cli/pipeline/kill.go b/cli/pipeline/kill.go new file mode 100644 index 000000000..a9ddf97b3 --- /dev/null +++ b/cli/pipeline/kill.go @@ -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: " ", + 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 +} diff --git a/cli/pipeline/last.go b/cli/pipeline/last.go new file mode 100644 index 000000000..52625719f --- /dev/null +++ b/cli/pipeline/last.go @@ -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: "", + 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) +} diff --git a/cli/build/build_list.go b/cli/pipeline/list.go similarity index 52% rename from cli/build/build_list.go rename to cli/pipeline/list.go index 4c3f1acc9..0650b4152 100644 --- a/cli/build/build_list.go +++ b/cli/pipeline/list.go @@ -1,4 +1,18 @@ -package build +// Copyright 2022 Woodpecker Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package pipeline import ( "os" @@ -10,13 +24,13 @@ import ( "github.com/woodpecker-ci/woodpecker/cli/internal" ) -var buildListCmd = &cli.Command{ +var pipelineListCmd = &cli.Command{ Name: "ls", - Usage: "show build history", + Usage: "show pipeline history", ArgsUsage: "", - Action: buildList, + Action: pipelineList, Flags: append(common.GlobalFlags, - common.FormatFlag(tmplBuildList), + common.FormatFlag(tmplPipelineList), &cli.StringFlag{ Name: "branch", Usage: "branch filter", @@ -37,7 +51,7 @@ var buildListCmd = &cli.Command{ ), } -func buildList(c *cli.Context) error { +func pipelineList(c *cli.Context) error { repo := c.Args().First() owner, name, err := internal.ParseRepo(repo) if err != nil { @@ -49,7 +63,7 @@ func buildList(c *cli.Context) error { return err } - builds, err := client.BuildList(owner, name) + pipelines, err := client.PipelineList(owner, name) if err != nil { return err } @@ -65,20 +79,20 @@ func buildList(c *cli.Context) error { limit := c.Int("limit") var count int - for _, build := range builds { + for _, pipeline := range pipelines { if count >= limit { break } - if branch != "" && build.Branch != branch { + if branch != "" && pipeline.Branch != branch { continue } - if event != "" && build.Event != event { + if event != "" && pipeline.Event != event { continue } - if status != "" && build.Status != status { + if status != "" && pipeline.Status != status { continue } - if err := tmpl.Execute(os.Stdout, build); err != nil { + if err := tmpl.Execute(os.Stdout, pipeline); err != nil { return err } count++ @@ -86,8 +100,8 @@ func buildList(c *cli.Context) error { return nil } -// template for build list information -var tmplBuildList = "\x1b[33mBuild #{{ .Number }} \x1b[0m" + ` +// template for pipeline list information +var tmplPipelineList = "\x1b[33mBuild #{{ .Number }} \x1b[0m" + ` Status: {{ .Status }} Event: {{ .Event }} Commit: {{ .Commit }} diff --git a/cli/pipeline/logs.go b/cli/pipeline/logs.go new file mode 100644 index 000000000..f42f4950f --- /dev/null +++ b/cli/pipeline/logs.go @@ -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: " [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 +} diff --git a/cli/pipeline/pipeline.go b/cli/pipeline/pipeline.go new file mode 100644 index 000000000..358fdf1ee --- /dev/null +++ b/cli/pipeline/pipeline.go @@ -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, + }, +} diff --git a/cli/pipeline/ps.go b/cli/pipeline/ps.go new file mode 100644 index 000000000..5b57e7e7f --- /dev/null +++ b/cli/pipeline/ps.go @@ -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: " [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 }} +` diff --git a/cli/pipeline/queue.go b/cli/pipeline/queue.go new file mode 100644 index 000000000..b8ef02700 --- /dev/null +++ b/cli/pipeline/queue.go @@ -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 }} +` diff --git a/cli/pipeline/start.go b/cli/pipeline/start.go new file mode 100644 index 000000000..30a341238 --- /dev/null +++ b/cli/pipeline/start.go @@ -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: " [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 +} diff --git a/cli/pipeline/stop.go b/cli/pipeline/stop.go new file mode 100644 index 000000000..1e333cbd5 --- /dev/null +++ b/cli/pipeline/stop.go @@ -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: " [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 +} diff --git a/cli/registry/registry_list.go b/cli/registry/registry_list.go index b5e4cae6c..f8077b87e 100644 --- a/cli/registry/registry_list.go +++ b/cli/registry/registry_list.go @@ -1,3 +1,17 @@ +// Copyright 2022 Woodpecker Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package registry import ( @@ -53,7 +67,7 @@ func registryList(c *cli.Context) error { return nil } -// template for build list information +// template for registry list information var tmplRegistryList = "\x1b[33m{{ .Address }} \x1b[0m" + ` Username: {{ .Username }} Email: {{ .Email }} diff --git a/cli/repo/repo_update.go b/cli/repo/repo_update.go index d771826d7..420a8fe4d 100644 --- a/cli/repo/repo_update.go +++ b/cli/repo/repo_update.go @@ -1,3 +1,17 @@ +// Copyright 2022 Woodpecker Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package repo import ( @@ -38,12 +52,12 @@ var repoUpdateCmd = &cli.Command{ Usage: "repository configuration path (e.g. .woodpecker.yml)", }, &cli.IntFlag{ - Name: "build-counter", - Usage: "repository starting build number", + Name: "pipeline-counter", + Usage: "repository starting pipeline number", }, &cli.BoolFlag{ Name: "unsafe", - Usage: "validate updating the build-counter is unsafe", + Usage: "validate updating the pipeline-counter is unsafe", }, ), } @@ -61,13 +75,13 @@ func repoUpdate(c *cli.Context) error { } var ( - visibility = c.String("visibility") - config = c.String("config") - timeout = c.Duration("timeout") - trusted = c.Bool("trusted") - gated = c.Bool("gated") - buildCounter = c.Int("build-counter") - unsafe = c.Bool("unsafe") + visibility = c.String("visibility") + config = c.String("config") + timeout = c.Duration("timeout") + trusted = c.Bool("trusted") + gated = c.Bool("gated") + pipelineCounter = c.Int("pipeline-counter") + unsafe = c.Bool("unsafe") ) patch := new(woodpecker.RepoPatch) @@ -90,11 +104,11 @@ func repoUpdate(c *cli.Context) error { patch.Visibility = &visibility } } - if c.IsSet("build-counter") && !unsafe { - fmt.Printf("Setting the build counter is an unsafe operation that could put your repository in an inconsistent state. Please use --unsafe to proceed") + if c.IsSet("pipeline-counter") && !unsafe { + fmt.Printf("Setting the pipeline counter is an unsafe operation that could put your repository in an inconsistent state. Please use --unsafe to proceed") } - if c.IsSet("build-counter") && unsafe { - patch.BuildCounter = &buildCounter + if c.IsSet("pipeline-counter") && unsafe { + patch.PipelineCounter = &pipelineCounter } if _, err := client.RepoPatch(owner, name, patch); err != nil { diff --git a/cmd/agent/flags.go b/cmd/agent/flags.go index a613f8194..a70f0fdf0 100644 --- a/cmd/agent/flags.go +++ b/cmd/agent/flags.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2019 Laszlo Fogas // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -80,7 +81,7 @@ var flags = []cli.Flag{ &cli.IntFlag{ EnvVars: []string{"WOODPECKER_MAX_PROCS"}, Name: "max-procs", - Usage: "agent parallel builds", + Usage: "agent parallel workflows", Value: 1, }, &cli.BoolFlag{ diff --git a/cmd/cli/app.go b/cmd/cli/app.go index fa80efb1a..330588292 100644 --- a/cmd/cli/app.go +++ b/cmd/cli/app.go @@ -21,7 +21,6 @@ import ( zlog "github.com/rs/zerolog/log" "github.com/urfave/cli/v2" - "github.com/woodpecker-ci/woodpecker/cli/build" "github.com/woodpecker-ci/woodpecker/cli/common" "github.com/woodpecker-ci/woodpecker/cli/cron" "github.com/woodpecker-ci/woodpecker/cli/deploy" @@ -30,6 +29,7 @@ import ( "github.com/woodpecker-ci/woodpecker/cli/lint" "github.com/woodpecker-ci/woodpecker/cli/log" "github.com/woodpecker-ci/woodpecker/cli/loglevel" + "github.com/woodpecker-ci/woodpecker/cli/pipeline" "github.com/woodpecker-ci/woodpecker/cli/registry" "github.com/woodpecker-ci/woodpecker/cli/repo" "github.com/woodpecker-ci/woodpecker/cli/secret" @@ -46,7 +46,7 @@ func newApp() *cli.App { app.EnableBashCompletion = true app.Flags = common.GlobalFlags app.Commands = []*cli.Command{ - build.Command, + pipeline.Command, log.Command, deploy.Command, exec.Command, diff --git a/cmd/server/setup.go b/cmd/server/setup.go index 097a3a170..58fb6fb38 100644 --- a/cmd/server/setup.go +++ b/cmd/server/setup.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -61,7 +62,7 @@ func setupStore(c *cli.Context) (store.Store, error) { if datastore.SupportedDriver("sqlite3") { log.Debug().Msgf("server has sqlite3 support") } else { - log.Debug().Msgf("server was build with no sqlite3 support!") + log.Debug().Msgf("server was built without sqlite3 support!") } } @@ -306,27 +307,27 @@ func setupMetrics(g *errgroup.Group, _store store.Store) { pendingJobs := promauto.NewGauge(prometheus.GaugeOpts{ Namespace: "woodpecker", Name: "pending_jobs", - Help: "Total number of pending build processes.", + Help: "Total number of pending pipeline processes.", }) waitingJobs := promauto.NewGauge(prometheus.GaugeOpts{ Namespace: "woodpecker", Name: "waiting_jobs", - Help: "Total number of builds waiting on deps.", + Help: "Total number of pipeline waiting on deps.", }) runningJobs := promauto.NewGauge(prometheus.GaugeOpts{ Namespace: "woodpecker", Name: "running_jobs", - Help: "Total number of running build processes.", + Help: "Total number of running pipeline processes.", }) workers := promauto.NewGauge(prometheus.GaugeOpts{ Namespace: "woodpecker", Name: "worker_count", Help: "Total number of workers.", }) - builds := promauto.NewGauge(prometheus.GaugeOpts{ + pipelines := promauto.NewGauge(prometheus.GaugeOpts{ Namespace: "woodpecker", - Name: "build_total_count", - Help: "Total number of builds.", + Name: "pipeline_total_count", + Help: "Total number of pipelines.", }) users := promauto.NewGauge(prometheus.GaugeOpts{ Namespace: "woodpecker", @@ -353,8 +354,8 @@ func setupMetrics(g *errgroup.Group, _store store.Store) { for { repoCount, _ := _store.GetRepoCount() userCount, _ := _store.GetUserCount() - buildCount, _ := _store.GetBuildCount() - builds.Set(float64(buildCount)) + pipelineCount, _ := _store.GetPipelineCount() + pipelines.Set(float64(pipelineCount)) users.Set(float64(userCount)) repos.Set(float64(repoCount)) time.Sleep(10 * time.Second) diff --git a/docs/docs/10-intro.md b/docs/docs/10-intro.md index a75c12f5d..571a91100 100644 --- a/docs/docs/10-intro.md +++ b/docs/docs/10-intro.md @@ -23,7 +23,7 @@ pipeline: - echo "Testing.." ``` -### Build steps are containers +### Pipeline steps are containers - Define any container image as context - either use your own and install the needed tools in custom image or diff --git a/docs/docs/20-usage/50-environment.md b/docs/docs/20-usage/50-environment.md index 02ea741ce..121f7fef3 100644 --- a/docs/docs/20-usage/50-environment.md +++ b/docs/docs/20-usage/50-environment.md @@ -46,86 +46,86 @@ pipeline: This is the reference list of all environment variables available to your pipeline containers. These are injected into your pipeline step and plugins containers, at runtime. -| NAME | Description | -|--------------------------------|----------------------------------------------------------------------------------------------| -| `CI=woodpecker` | environment is woodpecker | -| | **Repository** | -| `CI_REPO` | repository full name `/` | -| `CI_REPO_OWNER` | repository owner | -| `CI_REPO_NAME` | repository name | -| `CI_REPO_SCM` | repository SCM (git) | -| `CI_REPO_LINK` | repository link | -| `CI_REPO_REMOTE` | repository clone URL | -| `CI_REPO_DEFAULT_BRANCH` | repository default branch (master) | -| `CI_REPO_PRIVATE` | repository is private | -| `CI_REPO_TRUSTED` | repository is trusted | -| | **Current Commit** | -| `CI_COMMIT_SHA` | commit SHA | -| `CI_COMMIT_REF` | commit ref | -| `CI_COMMIT_REFSPEC` | commit ref spec | -| `CI_COMMIT_BRANCH` | commit branch (equals target branch for pull requests) | -| `CI_COMMIT_SOURCE_BRANCH` | commit source branch | -| `CI_COMMIT_TARGET_BRANCH` | commit target branch | -| `CI_COMMIT_TAG` | commit tag name (empty if event is not `tag`) | -| `CI_COMMIT_PULL_REQUEST` | commit pull request number (empty if event is not `pull_request`) | -| `CI_COMMIT_LINK` | commit link in remote | -| `CI_COMMIT_MESSAGE` | commit message | -| `CI_COMMIT_AUTHOR` | commit author username | -| `CI_COMMIT_AUTHOR_EMAIL` | commit author email address | -| `CI_COMMIT_AUTHOR_AVATAR` | commit author avatar | -| | **Current build** | -| `CI_BUILD_NUMBER` | build number | -| `CI_BUILD_PARENT` | build number of parent build | -| `CI_BUILD_EVENT` | build event (push, pull_request, tag, deployment) | -| `CI_BUILD_LINK` | build link in CI | -| `CI_BUILD_DEPLOY_TARGET` | build deploy target for `deployment` events (i.e. production) | -| `CI_BUILD_STATUS` | build status (success, failure) | -| `CI_BUILD_CREATED` | build created UNIX timestamp | -| `CI_BUILD_STARTED` | build started UNIX timestamp | -| `CI_BUILD_FINISHED` | build finished UNIX timestamp | -| | **Current job** | -| `CI_JOB_NUMBER` | job number | -| `CI_JOB_STATUS` | job status (success, failure) | -| `CI_JOB_STARTED` | job started UNIX timestamp | -| `CI_JOB_FINISHED` | job finished UNIX timestamp | -| | **Previous commit** | -| `CI_PREV_COMMIT_SHA` | previous commit SHA | -| `CI_PREV_COMMIT_REF` | previous commit ref | -| `CI_PREV_COMMIT_REFSPEC` | previous commit ref spec | -| `CI_PREV_COMMIT_BRANCH` | previous commit branch | -| `CI_PREV_COMMIT_SOURCE_BRANCH` | previous commit source branch | -| `CI_PREV_COMMIT_TARGET_BRANCH` | previous commit target branch | -| `CI_PREV_COMMIT_LINK` | previous commit link in remote | -| `CI_PREV_COMMIT_MESSAGE` | previous commit message | -| `CI_PREV_COMMIT_AUTHOR` | previous commit author username | -| `CI_PREV_COMMIT_AUTHOR_EMAIL` | previous commit author email address | -| `CI_PREV_COMMIT_AUTHOR_AVATAR` | previous commit author avatar | -| | **Previous build** | -| `CI_PREV_BUILD_NUMBER` | previous build number | -| `CI_PREV_BUILD_PARENT` | previous build number of parent build | -| `CI_PREV_BUILD_EVENT` | previous build event (push, pull_request, tag, deployment) | -| `CI_PREV_BUILD_LINK` | previous build link in CI | -| `CI_PREV_BUILD_DEPLOY_TARGET` | previous build deploy target for `deployment` events (i.e. production) | -| `CI_PREV_BUILD_STATUS` | previous build status (success, failure) | -| `CI_PREV_BUILD_CREATED` | previous build created UNIX timestamp | -| `CI_PREV_BUILD_STARTED` | previous build started UNIX timestamp | -| `CI_PREV_BUILD_FINISHED` | previous build finished UNIX timestamp | -| |   | -| `CI_WORKSPACE` | Path of the workspace where source code gets cloned to | -| | **System** | -| `CI_SYSTEM_NAME` | name of the CI system: `woodpecker` | -| `CI_SYSTEM_LINK` | link to CI system | -| `CI_SYSTEM_HOST` | hostname of CI server | -| `CI_SYSTEM_VERSION` | version of the server | -| | **Internal** - Please don't use! | -| `CI_SCRIPT` | Internal script path. Used to call pipeline step commands. | -| `CI_NETRC_USERNAME` | Credentials for private repos to be able to clone data. (Only available for specific images) | -| `CI_NETRC_PASSWORD` | Credentials for private repos to be able to clone data. (Only available for specific images) | -| `CI_NETRC_MACHINE` | Credentials for private repos to be able to clone data. (Only available for specific images) | +| NAME | Description | +|----------------------------------|----------------------------------------------------------------------------------------------| +| `CI=woodpecker` | environment is woodpecker | +| | **Repository** | +| `CI_REPO` | repository full name `/` | +| `CI_REPO_OWNER` | repository owner | +| `CI_REPO_NAME` | repository name | +| `CI_REPO_SCM` | repository SCM (git) | +| `CI_REPO_LINK` | repository link | +| `CI_REPO_REMOTE` | repository clone URL | +| `CI_REPO_DEFAULT_BRANCH` | repository default branch (master) | +| `CI_REPO_PRIVATE` | repository is private | +| `CI_REPO_TRUSTED` | repository is trusted | +| | **Current Commit** | +| `CI_COMMIT_SHA` | commit SHA | +| `CI_COMMIT_REF` | commit ref | +| `CI_COMMIT_REFSPEC` | commit ref spec | +| `CI_COMMIT_BRANCH` | commit branch (equals target branch for pull requests) | +| `CI_COMMIT_SOURCE_BRANCH` | commit source branch | +| `CI_COMMIT_TARGET_BRANCH` | commit target branch | +| `CI_COMMIT_TAG` | commit tag name (empty if event is not `tag`) | +| `CI_COMMIT_PULL_REQUEST` | commit pull request number (empty if event is not `pull_request`) | +| `CI_COMMIT_LINK` | commit link in remote | +| `CI_COMMIT_MESSAGE` | commit message | +| `CI_COMMIT_AUTHOR` | commit author username | +| `CI_COMMIT_AUTHOR_EMAIL` | commit author email address | +| `CI_COMMIT_AUTHOR_AVATAR` | commit author avatar | +| | **Current pipeline** | +| `CI_PIPELINE_NUMBER` | pipeline number | +| `CI_PIPELINE_PARENT` | number of parent pipeline | +| `CI_PIPELINE_EVENT` | pipeline event (push, pull_request, tag, deployment) | +| `CI_PIPELINE_LINK` | pipeline link in CI | +| `CI_PIPELINE_DEPLOY_TARGET` | pipeline deploy target for `deployment` events (ie production) | +| `CI_PIPELINE_STATUS` | pipeline status (success, failure) | +| `CI_PIPELINE_CREATED` | pipeline created UNIX timestamp | +| `CI_PIPELINE_STARTED` | pipeline started UNIX timestamp | +| `CI_PIPELINE_FINISHED` | pipeline finished UNIX timestamp | +| | **Current job** | +| `CI_JOB_NUMBER` | job number | +| `CI_JOB_STATUS` | job status (success, failure) | +| `CI_JOB_STARTED` | job started UNIX timestamp | +| `CI_JOB_FINISHED` | job finished UNIX timestamp | +| | **Previous commit** | +| `CI_PREV_COMMIT_SHA` | previous commit SHA | +| `CI_PREV_COMMIT_REF` | previous commit ref | +| `CI_PREV_COMMIT_REFSPEC` | previous commit ref spec | +| `CI_PREV_COMMIT_BRANCH` | previous commit branch | +| `CI_PREV_COMMIT_SOURCE_BRANCH` | previous commit source branch | +| `CI_PREV_COMMIT_TARGET_BRANCH` | previous commit target branch | +| `CI_PREV_COMMIT_LINK` | previous commit link in remote | +| `CI_PREV_COMMIT_MESSAGE` | previous commit message | +| `CI_PREV_COMMIT_AUTHOR` | previous commit author username | +| `CI_PREV_COMMIT_AUTHOR_EMAIL` | previous commit author email address | +| `CI_PREV_COMMIT_AUTHOR_AVATAR` | previous commit author avatar | +| | **Previous pipeline** | +| `CI_PREV_PIPELINE_NUMBER` | previous pipeline number | +| `CI_PREV_PIPELINE_PARENT` | previous pipeline number of parent pipeline | +| `CI_PREV_PIPELINE_EVENT` | previous pipeline event (push, pull_request, tag, deployment) | +| `CI_PREV_PIPELINE_LINK` | previous pipeline link in CI | +| `CI_PREV_PIPELINE_DEPLOY_TARGET` | previous pipeline deploy target for `deployment` events (ie production) | +| `CI_PREV_PIPELINE_STATUS` | previous pipeline status (success, failure) | +| `CI_PREV_PIPELINE_CREATED` | previous pipeline created UNIX timestamp | +| `CI_PREV_PIPELINE_STARTED` | previous pipeline started UNIX timestamp | +| `CI_PREV_PIPELINE_FINISHED` | previous pipeline finished UNIX timestamp | +| |   | +| `CI_WORKSPACE` | Path of the workspace where source code gets cloned to | +| | **System** | +| `CI_SYSTEM_NAME` | name of the CI system: `woodpecker` | +| `CI_SYSTEM_LINK` | link to CI system | +| `CI_SYSTEM_HOST` | hostname of CI server | +| `CI_SYSTEM_VERSION` | version of the server | +| | **Internal** - Please don't use! | +| `CI_SCRIPT` | Internal script path. Used to call pipeline step commands. | +| `CI_NETRC_USERNAME` | Credentials for private repos to be able to clone data. (Only available for specific images) | +| `CI_NETRC_PASSWORD` | Credentials for private repos to be able to clone data. (Only available for specific images) | +| `CI_NETRC_MACHINE` | Credentials for private repos to be able to clone data. (Only available for specific images) | ## Global environment variables -If you want specific environment variables to be available in all of your builds use the `WOODPECKER_ENVIRONMENT` setting on the Woodpecker server. Note that these can't overwrite any existing, built-in variables. +If you want specific environment variables to be available in all of your pipelines use the `WOODPECKER_ENVIRONMENT` setting on the Woodpecker server. Note that these can't overwrite any existing, built-in variables. ```diff services: @@ -152,7 +152,7 @@ pipeline: ## String Substitution -Woodpecker provides the ability to substitute environment variables at runtime. This gives us the ability to use dynamic build or commit details in our pipeline configuration. +Woodpecker provides the ability to substitute environment variables at runtime. This gives us the ability to use dynamic settings, commands and filters in our pipeline configuration. Example commit substitution: diff --git a/docs/docs/30-administration/90-prometheus.md b/docs/docs/30-administration/90-prometheus.md index 3cd28640d..d7e6ddee8 100644 --- a/docs/docs/30-administration/90-prometheus.md +++ b/docs/docs/30-administration/90-prometheus.md @@ -35,16 +35,16 @@ scrape_configs: List of Prometheus metrics specific to Woodpecker: ``` -# HELP woodpecker_build_count Build count. -# TYPE woodpecker_build_count counter +# HELP woodpecker_pipeline_count Build count. +# TYPE woodpecker_pipeline_count counter woodpecker_build_count{branch="master",pipeline="total",repo="woodpecker-ci/woodpecker",status="success"} 3 woodpecker_build_count{branch="mkdocs",pipeline="total",repo="woodpecker-ci/woodpecker",status="success"} 3 -# HELP woodpecker_build_time Build time. -# TYPE woodpecker_build_time gauge +# HELP woodpecker_pipeline_time Build time. +# TYPE woodpecker_pipeline_time gauge woodpecker_build_time{branch="master",pipeline="total",repo="woodpecker-ci/woodpecker",status="success"} 116 woodpecker_build_time{branch="mkdocs",pipeline="total",repo="woodpecker-ci/woodpecker",status="success"} 155 -# HELP woodpecker_build_total_count Total number of builds. -# TYPE woodpecker_build_total_count gauge +# HELP woodpecker_pipeline_total_count Total number of builds. +# TYPE woodpecker_pipeline_total_count gauge woodpecker_build_total_count 1025 # HELP woodpecker_pending_jobs Total number of pending build processes. # TYPE woodpecker_pending_jobs gauge diff --git a/docs/docs/91-migrations.md b/docs/docs/91-migrations.md index a450da22b..1808aa63b 100644 --- a/docs/docs/91-migrations.md +++ b/docs/docs/91-migrations.md @@ -7,6 +7,9 @@ Some versions need some changes to the server configuration or the pipeline conf - The signature used to verify extensions calls (like those used for the [config-extension](./30-administration/100-external-configuration-api.md)) done by the Woodpecker server switched from using a shared-secret HMac to an ed25519 key-pair. Read more about it at the [config-extensions](./30-administration/100-external-configuration-api.md) documentation. - Refactored support of old agent filter labels and expression. Learn how to use the new [filter](./20-usage/20-pipeline-syntax.md#labels) - Renamed step environment variable `CI_SYSTEM_ARCH` to `CI_SYSTEM_PLATFORM`. Same applies for the cli exec variable. +- Renamed environment variables `CI_BUILD_*` and `CI_PREV_BUILD_*` to `CI_PIPELINE_*` and `CI_PREV_PIPELINE_*`, old ones are still available but deprecated +- Renamed API endpoints for pipelines (`//builds/` -> `//pipelines/`), old ones are still available but deprecated +- Updated Prometheus gauge `build_*` to `pipeline_*` ## 0.15.0 diff --git a/pipeline/backend/local/local.go b/pipeline/backend/local/local.go index cc636fb99..dd84b75fa 100644 --- a/pipeline/backend/local/local.go +++ b/pipeline/backend/local/local.go @@ -1,3 +1,17 @@ +// Copyright 2022 Woodpecker Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package local import ( @@ -99,7 +113,7 @@ func (e *local) Wait(context.Context, *types.Step) (*types.State, error) { ExitCode := 0 if eerr, ok := err.(*exec.ExitError); ok { ExitCode = eerr.ExitCode() - // Non-zero exit code is a build failure, but not an agent error. + // Non-zero exit code is a pipeline failure, but not an agent error. err = nil } return &types.State{ diff --git a/pipeline/frontend/drone_compatibility.go b/pipeline/frontend/drone_compatibility.go index 8e6d6d2c4..1a9520bae 100644 --- a/pipeline/frontend/drone_compatibility.go +++ b/pipeline/frontend/drone_compatibility.go @@ -22,15 +22,15 @@ func (m *Metadata) setDroneEnviron(env map[string]string) { env["DRONE_TAG"] = env["CI_COMMIT_TAG"] env["DRONE_SOURCE_BRANCH"] = env["CI_COMMIT_SOURCE_BRANCH"] env["DRONE_TARGET_BRANCH"] = env["CI_COMMIT_TARGET_BRANCH"] - // build - env["DRONE_BUILD_NUMBER"] = env["CI_BUILD_NUMBER"] - env["DRONE_BUILD_PARENT"] = env["CI_BUILD_PARENT"] - env["DRONE_BUILD_EVENT"] = env["CI_BUILD_EVENT"] - env["DRONE_BUILD_STATUS"] = env["CI_BUILD_STATUS"] - env["DRONE_BUILD_LINK"] = env["CI_BUILD_LINK"] - env["DRONE_BUILD_CREATED"] = env["CI_BUILD_CREATED"] - env["DRONE_BUILD_STARTED"] = env["CI_BUILD_STARTED"] - env["DRONE_BUILD_FINISHED"] = env["CI_BUILD_FINISHED"] + // pipeline + env["DRONE_BUILD_NUMBER"] = env["CI_PIPELINE_NUMBER"] + env["DRONE_BUILD_PARENT"] = env["CI_PIPELINE_PARENT"] + env["DRONE_BUILD_EVENT"] = env["CI_PIPELINE_EVENT"] + env["DRONE_BUILD_STATUS"] = env["CI_PIPELINE_STATUS"] + env["DRONE_BUILD_LINK"] = env["CI_PIPELINE_LINK"] + env["DRONE_BUILD_CREATED"] = env["CI_PIPELINE_CREATED"] + env["DRONE_BUILD_STARTED"] = env["CI_PIPELINE_STARTED"] + env["DRONE_BUILD_FINISHED"] = env["CI_PIPELINE_FINISHED"] // commit env["DRONE_COMMIT"] = env["CI_COMMIT_SHA"] env["DRONE_COMMIT_BEFORE"] = env["CI_PREV_COMMIT_SHA"] diff --git a/pipeline/frontend/metadata.go b/pipeline/frontend/metadata.go index 06474e200..82c403e34 100644 --- a/pipeline/frontend/metadata.go +++ b/pipeline/frontend/metadata.go @@ -35,12 +35,12 @@ const ( type ( // Metadata defines runtime m. Metadata struct { - ID string `json:"id,omitempty"` - Repo Repo `json:"repo,omitempty"` - Curr Build `json:"curr,omitempty"` - Prev Build `json:"prev,omitempty"` - Job Job `json:"job,omitempty"` - Sys System `json:"sys,omitempty"` + ID string `json:"id,omitempty"` + Repo Repo `json:"repo,omitempty"` + Curr Pipeline `json:"curr,omitempty"` + Prev Pipeline `json:"prev,omitempty"` + Job Job `json:"job,omitempty"` + Sys System `json:"sys,omitempty"` } // Repo defines runtime metadata for a repository. @@ -53,8 +53,8 @@ type ( Branch string `json:"default_branch,omitempty"` } - // Build defines runtime metadata for a build. - Build struct { + // Pipeline defines runtime metadata for a pipeline. + Pipeline struct { Number int64 `json:"number,omitempty"` Created int64 `json:"created,omitempty"` Started int64 `json:"started,omitempty"` @@ -161,15 +161,15 @@ func (m *Metadata) Environ() map[string]string { "CI_COMMIT_TAG": "", // will be set if event is tag "CI_COMMIT_PULL_REQUEST": "", // will be set if event is pr - "CI_BUILD_NUMBER": strconv.FormatInt(m.Curr.Number, 10), - "CI_BUILD_PARENT": strconv.FormatInt(m.Curr.Parent, 10), - "CI_BUILD_EVENT": m.Curr.Event, - "CI_BUILD_LINK": m.Curr.Link, - "CI_BUILD_DEPLOY_TARGET": m.Curr.Target, - "CI_BUILD_STATUS": m.Curr.Status, - "CI_BUILD_CREATED": strconv.FormatInt(m.Curr.Created, 10), - "CI_BUILD_STARTED": strconv.FormatInt(m.Curr.Started, 10), - "CI_BUILD_FINISHED": strconv.FormatInt(m.Curr.Finished, 10), + "CI_PIPELINE_NUMBER": strconv.FormatInt(m.Curr.Number, 10), + "CI_PIPELINE_PARENT": strconv.FormatInt(m.Curr.Parent, 10), + "CI_PIPELINE_EVENT": m.Curr.Event, + "CI_PIPELINE_LINK": m.Curr.Link, + "CI_PIPELINE_DEPLOY_TARGET": m.Curr.Target, + "CI_PIPELINE_STATUS": m.Curr.Status, + "CI_PIPELINE_CREATED": strconv.FormatInt(m.Curr.Created, 10), + "CI_PIPELINE_STARTED": strconv.FormatInt(m.Curr.Started, 10), + "CI_PIPELINE_FINISHED": strconv.FormatInt(m.Curr.Finished, 10), "CI_JOB_NUMBER": strconv.Itoa(m.Job.Number), "CI_JOB_STATUS": "", // will be set by agent @@ -186,15 +186,15 @@ func (m *Metadata) Environ() map[string]string { "CI_PREV_COMMIT_AUTHOR_EMAIL": m.Prev.Commit.Author.Email, "CI_PREV_COMMIT_AUTHOR_AVATAR": m.Prev.Commit.Author.Avatar, - "CI_PREV_BUILD_NUMBER": strconv.FormatInt(m.Prev.Number, 10), - "CI_PREV_BUILD_PARENT": strconv.FormatInt(m.Prev.Parent, 10), - "CI_PREV_BUILD_EVENT": m.Prev.Event, - "CI_PREV_BUILD_LINK": m.Prev.Link, - "CI_PREV_BUILD_DEPLOY_TARGET": m.Prev.Target, - "CI_PREV_BUILD_STATUS": m.Prev.Status, - "CI_PREV_BUILD_CREATED": strconv.FormatInt(m.Prev.Created, 10), - "CI_PREV_BUILD_STARTED": strconv.FormatInt(m.Prev.Started, 10), - "CI_PREV_BUILD_FINISHED": strconv.FormatInt(m.Prev.Finished, 10), + "CI_PREV_PIPELINE_NUMBER": strconv.FormatInt(m.Prev.Number, 10), + "CI_PREV_PIPELINE_PARENT": strconv.FormatInt(m.Prev.Parent, 10), + "CI_PREV_PIPELINE_EVENT": m.Prev.Event, + "CI_PREV_PIPELINE_LINK": m.Prev.Link, + "CI_PREV_PIPELINE_DEPLOY_TARGET": m.Prev.Target, + "CI_PREV_PIPELINE_STATUS": m.Prev.Status, + "CI_PREV_PIPELINE_CREATED": strconv.FormatInt(m.Prev.Created, 10), + "CI_PREV_PIPELINE_STARTED": strconv.FormatInt(m.Prev.Started, 10), + "CI_PREV_PIPELINE_FINISHED": strconv.FormatInt(m.Prev.Finished, 10), "CI_SYSTEM_NAME": m.Sys.Name, "CI_SYSTEM_LINK": m.Sys.Link, @@ -204,6 +204,26 @@ func (m *Metadata) Environ() map[string]string { // DEPRECATED "CI_SYSTEM_ARCH": m.Sys.Platform, // TODO: remove after v1.0.x version + // use CI_PIPELINE_* + "CI_BUILD_NUMBER": strconv.FormatInt(m.Curr.Number, 10), + "CI_BUILD_PARENT": strconv.FormatInt(m.Curr.Parent, 10), + "CI_BUILD_EVENT": m.Curr.Event, + "CI_BUILD_LINK": m.Curr.Link, + "CI_BUILD_DEPLOY_TARGET": m.Curr.Target, + "CI_BUILD_STATUS": m.Curr.Status, + "CI_BUILD_CREATED": strconv.FormatInt(m.Curr.Created, 10), + "CI_BUILD_STARTED": strconv.FormatInt(m.Curr.Started, 10), + "CI_BUILD_FINISHED": strconv.FormatInt(m.Curr.Finished, 10), + // use CI_PREV_PIPELINE_* + "CI_PREV_BUILD_NUMBER": strconv.FormatInt(m.Prev.Number, 10), + "CI_PREV_BUILD_PARENT": strconv.FormatInt(m.Prev.Parent, 10), + "CI_PREV_BUILD_EVENT": m.Prev.Event, + "CI_PREV_BUILD_LINK": m.Prev.Link, + "CI_PREV_BUILD_DEPLOY_TARGET": m.Prev.Target, + "CI_PREV_BUILD_STATUS": m.Prev.Status, + "CI_PREV_BUILD_CREATED": strconv.FormatInt(m.Prev.Created, 10), + "CI_PREV_BUILD_STARTED": strconv.FormatInt(m.Prev.Started, 10), + "CI_PREV_BUILD_FINISHED": strconv.FormatInt(m.Prev.Finished, 10), } if m.Curr.Event == EventTag { params["CI_COMMIT_TAG"] = strings.TrimPrefix(m.Curr.Commit.Ref, "refs/tags/") diff --git a/pipeline/frontend/yaml/compiler/option.go b/pipeline/frontend/yaml/compiler/option.go index 4ec98e302..2ca1c797e 100644 --- a/pipeline/frontend/yaml/compiler/option.go +++ b/pipeline/frontend/yaml/compiler/option.go @@ -1,3 +1,17 @@ +// Copyright 2022 Woodpecker Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package compiler import ( @@ -49,7 +63,7 @@ func WithSecret(secrets ...Secret) Option { } } -// WithMetadata configures the compiler with the repository, build +// WithMetadata configures the compiler with the repository, pipeline // and system metadata. The metadata is used to remove steps from // the compiled pipeline configuration that should be skipped. The // metadata is also added to each container as environment variables. @@ -76,7 +90,7 @@ func WithNetrc(username, password, machine string) Option { // WithWorkspace configures the compiler with the workspace base // and path. The workspace base is a volume created at runtime and // mounted into all containers in the pipeline. The base and path -// are joined to provide the working directory for all build and +// are joined to provide the working directory for all pipeline and // plugin steps in the pipeline. func WithWorkspace(base, path string) Option { return func(compiler *Compiler) { @@ -177,7 +191,7 @@ func WithProxy() Option { } // WithNetworks configures the compiler with additional networks -// to be connected to build containers +// to be connected to pipeline containers func WithNetworks(networks ...string) Option { return func(compiler *Compiler) { compiler.networks = networks diff --git a/pipeline/frontend/yaml/compiler/script_posix.go b/pipeline/frontend/yaml/compiler/script_posix.go index a4c6574a1..7f7bc85a6 100644 --- a/pipeline/frontend/yaml/compiler/script_posix.go +++ b/pipeline/frontend/yaml/compiler/script_posix.go @@ -1,3 +1,17 @@ +// Copyright 2022 Woodpecker Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package compiler import ( @@ -7,7 +21,7 @@ import ( "strings" ) -// generateScriptPosix is a helper function that generates a build script +// generateScriptPosix is a helper function that generates a step script // for a linux container using the given func generateScriptPosix(commands []string) string { var buf bytes.Buffer @@ -27,7 +41,7 @@ func generateScriptPosix(commands []string) string { return base64.StdEncoding.EncodeToString([]byte(script)) } -// setupScript is a helper script this is added to the build to ensure +// setupScript is a helper script this is added to the step script to ensure // a minimum set of environment variables are set correctly. const setupScript = ` if [ -n "$CI_NETRC_MACHINE" ]; then @@ -44,7 +58,7 @@ unset CI_SCRIPT %s ` -// traceScript is a helper script that is added to the build script +// traceScript is a helper script that is added to the step script // to trace a command. const traceScript = ` echo + %s diff --git a/pipeline/frontend/yaml/compiler/script_win.go b/pipeline/frontend/yaml/compiler/script_win.go index b9e021a24..800a04a96 100644 --- a/pipeline/frontend/yaml/compiler/script_win.go +++ b/pipeline/frontend/yaml/compiler/script_win.go @@ -1,3 +1,17 @@ +// Copyright 2022 Woodpecker Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package compiler import ( @@ -39,7 +53,7 @@ $netrc=[string]::Format("{0}\_netrc",$Env:HOME); %s ` -// traceScript is a helper script that is added to the build script +// traceScript is a helper script that is added to the step script // to trace a command. const traceScriptWin = ` Write-Output ('+ %s'); diff --git a/pipeline/frontend/yaml/config_test.go b/pipeline/frontend/yaml/config_test.go index cb69c8865..97d54af8b 100644 --- a/pipeline/frontend/yaml/config_test.go +++ b/pipeline/frontend/yaml/config_test.go @@ -80,7 +80,7 @@ func TestParse(t *testing.T) { g.It("Should match event tester", func() { match, err := matchConfig.When.Match(frontend.Metadata{ - Curr: frontend.Build{ + Curr: frontend.Pipeline{ Event: "tester", }, }, false) @@ -90,7 +90,7 @@ func TestParse(t *testing.T) { g.It("Should match event tester2", func() { match, err := matchConfig.When.Match(frontend.Metadata{ - Curr: frontend.Build{ + Curr: frontend.Pipeline{ Event: "tester2", }, }, false) @@ -100,7 +100,7 @@ func TestParse(t *testing.T) { g.It("Should match branch tester", func() { match, err := matchConfig.When.Match(frontend.Metadata{ - Curr: frontend.Build{ + Curr: frontend.Pipeline{ Commit: frontend.Commit{ Branch: "tester", }, @@ -112,7 +112,7 @@ func TestParse(t *testing.T) { g.It("Should not match event push", func() { match, err := matchConfig.When.Match(frontend.Metadata{ - Curr: frontend.Build{ + Curr: frontend.Pipeline{ Event: "push", }, }, false) diff --git a/pipeline/frontend/yaml/constraint/constraint_test.go b/pipeline/frontend/yaml/constraint/constraint_test.go index 416fb1912..f5fec49be 100644 --- a/pipeline/frontend/yaml/constraint/constraint_test.go +++ b/pipeline/frontend/yaml/constraint/constraint_test.go @@ -392,7 +392,7 @@ func TestConstraints(t *testing.T) { desc: "no constraints, must match on default events", conf: "", with: frontend.Metadata{ - Curr: frontend.Build{ + Curr: frontend.Pipeline{ Event: frontend.EventPush, }, }, @@ -401,99 +401,99 @@ func TestConstraints(t *testing.T) { { desc: "global branch filter", conf: "{ branch: develop }", - with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventPush, Commit: frontend.Commit{Branch: "master"}}}, + with: frontend.Metadata{Curr: frontend.Pipeline{Event: frontend.EventPush, Commit: frontend.Commit{Branch: "master"}}}, want: false, }, { desc: "global branch filter", conf: "{ branch: master }", - with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventPush, Commit: frontend.Commit{Branch: "master"}}}, + with: frontend.Metadata{Curr: frontend.Pipeline{Event: frontend.EventPush, Commit: frontend.Commit{Branch: "master"}}}, want: true, }, { desc: "repo constraint", conf: "{ repo: owner/* }", - with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventPush}, Repo: frontend.Repo{Name: "owner/repo"}}, + with: frontend.Metadata{Curr: frontend.Pipeline{Event: frontend.EventPush}, Repo: frontend.Repo{Name: "owner/repo"}}, want: true, }, { desc: "repo constraint", conf: "{ repo: octocat/* }", - with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventPush}, Repo: frontend.Repo{Name: "owner/repo"}}, + with: frontend.Metadata{Curr: frontend.Pipeline{Event: frontend.EventPush}, Repo: frontend.Repo{Name: "owner/repo"}}, want: false, }, { desc: "ref constraint", conf: "{ ref: refs/tags/* }", - with: frontend.Metadata{Curr: frontend.Build{Commit: frontend.Commit{Ref: "refs/tags/v1.0.0"}, Event: frontend.EventPush}}, + with: frontend.Metadata{Curr: frontend.Pipeline{Commit: frontend.Commit{Ref: "refs/tags/v1.0.0"}, Event: frontend.EventPush}}, want: true, }, { desc: "ref constraint", conf: "{ ref: refs/tags/* }", - with: frontend.Metadata{Curr: frontend.Build{Commit: frontend.Commit{Ref: "refs/heads/master"}, Event: frontend.EventPush}}, + with: frontend.Metadata{Curr: frontend.Pipeline{Commit: frontend.Commit{Ref: "refs/heads/master"}, Event: frontend.EventPush}}, want: false, }, { desc: "platform constraint", conf: "{ platform: linux/amd64 }", - with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventPush}, Sys: frontend.System{Platform: "linux/amd64"}}, + with: frontend.Metadata{Curr: frontend.Pipeline{Event: frontend.EventPush}, Sys: frontend.System{Platform: "linux/amd64"}}, want: true, }, { desc: "platform constraint", conf: "{ repo: linux/amd64 }", - with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventPush}, Sys: frontend.System{Platform: "windows/amd64"}}, + with: frontend.Metadata{Curr: frontend.Pipeline{Event: frontend.EventPush}, Sys: frontend.System{Platform: "windows/amd64"}}, want: false, }, { desc: "instance constraint", conf: "{ instance: agent.tld }", - with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventPush}, Sys: frontend.System{Host: "agent.tld"}}, + with: frontend.Metadata{Curr: frontend.Pipeline{Event: frontend.EventPush}, Sys: frontend.System{Host: "agent.tld"}}, want: true, }, { desc: "instance constraint", conf: "{ instance: agent.tld }", - with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventPush}, Sys: frontend.System{Host: "beta.agent.tld"}}, + with: frontend.Metadata{Curr: frontend.Pipeline{Event: frontend.EventPush}, Sys: frontend.System{Host: "beta.agent.tld"}}, want: false, }, { desc: "filter cron by default constraint", conf: "{}", - with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventCron}}, + with: frontend.Metadata{Curr: frontend.Pipeline{Event: frontend.EventCron}}, want: false, }, { desc: "filter cron by matching name", conf: "{ event: cron, cron: job1 }", - with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventCron, Cron: "job1"}}, + with: frontend.Metadata{Curr: frontend.Pipeline{Event: frontend.EventCron, Cron: "job1"}}, want: true, }, { desc: "filter cron by name", conf: "{ event: cron, cron: job2 }", - with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventCron, Cron: "job1"}}, + with: frontend.Metadata{Curr: frontend.Pipeline{Event: frontend.EventCron, Cron: "job1"}}, want: false, }, { desc: "no constraints, event gets filtered by default event filter", conf: "", with: frontend.Metadata{ - Curr: frontend.Build{Event: "non-default"}, + Curr: frontend.Pipeline{Event: "non-default"}, }, want: false, }, { desc: "filter by eval based on event", - conf: `{ evaluate: 'CI_BUILD_EVENT == "push"' }`, - with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventPush}}, + conf: `{ evaluate: 'CI_PIPELINE_EVENT == "push"' }`, + with: frontend.Metadata{Curr: frontend.Pipeline{Event: frontend.EventPush}}, want: true, }, { desc: "filter by eval based on event and repo", - conf: `{ evaluate: 'CI_BUILD_EVENT == "push" && CI_REPO == "owner/repo"' }`, - with: frontend.Metadata{Curr: frontend.Build{Event: frontend.EventPush}, Repo: frontend.Repo{Name: "owner/repo"}}, + conf: `{ evaluate: 'CI_PIPELINE_EVENT == "push" && CI_REPO == "owner/repo"' }`, + with: frontend.Metadata{Curr: frontend.Pipeline{Event: frontend.EventPush}, Repo: frontend.Repo{Name: "owner/repo"}}, want: true, }, } diff --git a/pipeline/frontend/yaml/matrix/matrix.go b/pipeline/frontend/yaml/matrix/matrix.go index a8a9402c6..da5e9f247 100644 --- a/pipeline/frontend/yaml/matrix/matrix.go +++ b/pipeline/frontend/yaml/matrix/matrix.go @@ -1,3 +1,17 @@ +// Copyright 2022 Woodpecker Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package matrix import ( @@ -13,10 +27,10 @@ const ( limitAxis = 25 ) -// Matrix represents the build matrix. +// Matrix represents the pipeline matrix. type Matrix map[string][]string -// Axis represents a single permutation of entries from the build matrix. +// Axis represents a single permutation of entries from the pipeline matrix. type Axis map[string]string // String returns a string representation of an Axis as a comma-separated list @@ -79,7 +93,7 @@ func calc(matrix Matrix) []Axis { elem := p / decr % len(elems) axis[tag] = elems[elem] - // enforce a maximum number of tags in the build matrix. + // enforce a maximum number of tags in the pipeline matrix. if i > limitTags { break } diff --git a/pipeline/rpc/proto/woodpecker.pb.go b/pipeline/rpc/proto/woodpecker.pb.go index 19feb9960..177b8615d 100644 --- a/pipeline/rpc/proto/woodpecker.pb.go +++ b/pipeline/rpc/proto/woodpecker.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.28.0 +// protoc-gen-go v1.28.1 // protoc v3.12.4 // source: woodpecker.proto diff --git a/pipeline/tracer.go b/pipeline/tracer.go index 75c1b0800..570b5864c 100644 --- a/pipeline/tracer.go +++ b/pipeline/tracer.go @@ -29,6 +29,10 @@ var DefaultTracer = TraceFunc(func(state *State) error { if state.Pipeline.Step.Environment == nil { return nil } + state.Pipeline.Step.Environment["CI_PIPELINE_STATUS"] = "success" + state.Pipeline.Step.Environment["CI_PIPELINE_STARTED"] = strconv.FormatInt(state.Pipeline.Time, 10) + state.Pipeline.Step.Environment["CI_PIPELINE_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10) + // DEPRECATED state.Pipeline.Step.Environment["CI_BUILD_STATUS"] = "success" state.Pipeline.Step.Environment["CI_BUILD_STARTED"] = strconv.FormatInt(state.Pipeline.Time, 10) state.Pipeline.Step.Environment["CI_BUILD_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10) @@ -38,7 +42,10 @@ var DefaultTracer = TraceFunc(func(state *State) error { state.Pipeline.Step.Environment["CI_JOB_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10) if state.Pipeline.Error != nil { + state.Pipeline.Step.Environment["CI_PIPELINE_STATUS"] = "failure" + // DEPRECATED state.Pipeline.Step.Environment["CI_BUILD_STATUS"] = "failure" + state.Pipeline.Step.Environment["CI_JOB_STATUS"] = "failure" } return nil diff --git a/server/api/badge.go b/server/api/badge.go index 7aeaaa731..b8b6f1c69 100644 --- a/server/api/badge.go +++ b/server/api/badge.go @@ -1,5 +1,6 @@ -// Copyright 2018 Drone.IO Inc. +// Copyright 2022 Woodpecker Authors // Copyright 2021 Informatyka Boguslawski sp. z o.o. sp.k., http://www.ib.pl/ +// Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -47,15 +48,15 @@ func GetBadge(c *gin.Context) { branch = repo.Branch } - build, err := _store.GetBuildLast(repo, branch) + pipeline, err := _store.GetPipelineLast(repo, branch) if err != nil { log.Warn().Err(err).Msg("") - build = nil + pipeline = nil } // we serve an SVG, so set content type appropriately. c.Writer.Header().Set("Content-Type", "image/svg+xml") - c.String(http.StatusOK, badges.Generate(build)) + c.String(http.StatusOK, badges.Generate(pipeline)) } func GetCC(c *gin.Context) { @@ -66,13 +67,13 @@ func GetCC(c *gin.Context) { return } - builds, err := _store.GetBuildList(repo, 1) - if err != nil || len(builds) == 0 { + pipelines, err := _store.GetPipelineList(repo, 1) + if err != nil || len(pipelines) == 0 { c.AbortWithStatus(404) return } - url := fmt.Sprintf("%s/%s/%d", server.Config.Server.Host, repo.FullName, builds[0].Number) - cc := ccmenu.New(repo, builds[0], url) + url := fmt.Sprintf("%s/%s/%d", server.Config.Server.Host, repo.FullName, pipelines[0].Number) + cc := ccmenu.New(repo, pipelines[0], url) c.XML(200, cc) } diff --git a/server/api/file.go b/server/api/file.go index e1880d81b..4b8893ba3 100644 --- a/server/api/file.go +++ b/server/api/file.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -27,7 +28,7 @@ import ( "github.com/woodpecker-ci/woodpecker/server/store" ) -// FileList gets a list file by build. +// FileList gets a list file by pipeline. func FileList(c *gin.Context) { _store := store.FromContext(c) num, err := strconv.ParseInt(c.Param("number"), 10, 64) @@ -37,13 +38,13 @@ func FileList(c *gin.Context) { } repo := session.Repo(c) - build, err := _store.GetBuildNumber(repo, num) + pipeline, err := _store.GetPipelineNumber(repo, num) if err != nil { _ = c.AbortWithError(http.StatusInternalServerError, err) return } - files, err := _store.FileList(build) + files, err := _store.FileList(pipeline) if err != nil { _ = c.AbortWithError(http.StatusInternalServerError, err) return @@ -76,13 +77,13 @@ func FileGet(c *gin.Context) { return } - build, err := _store.GetBuildNumber(repo, num) + pipeline, err := _store.GetPipelineNumber(repo, num) if err != nil { _ = c.AbortWithError(http.StatusInternalServerError, err) return } - proc, err := _store.ProcFind(build, pid) + proc, err := _store.ProcFind(pipeline, pid) if err != nil { _ = c.AbortWithError(http.StatusInternalServerError, err) return diff --git a/server/api/hook.go b/server/api/hook.go index 92f7e1c79..967cc193e 100644 --- a/server/api/hook.go +++ b/server/api/hook.go @@ -1,5 +1,6 @@ -// Copyright 2018 Drone.IO Inc. +// Copyright 2022 Woodpecker Authors // Copyright 2021 Informatyka Boguslawski sp. z o.o. sp.k., http://www.ib.pl/ +// Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -79,7 +80,7 @@ func PostHook(c *gin.Context) { return } if tmpBuild == nil { - msg := "ignoring hook: hook parsing resulted in empty build" + msg := "ignoring hook: hook parsing resulted in empty pipeline" log.Debug().Msg(msg) c.String(http.StatusOK, msg) return @@ -174,10 +175,10 @@ func PostHook(c *gin.Context) { return } - build, err := pipeline.Create(c, _store, repo, tmpBuild) + pl, err := pipeline.Create(c, _store, repo, tmpBuild) if err != nil { handlePipelineErr(c, err) } else { - c.JSON(200, build) + c.JSON(200, pl) } } diff --git a/server/api/build.go b/server/api/pipeline.go similarity index 71% rename from server/api/build.go rename to server/api/pipeline.go index 9b691333d..db5259f80 100644 --- a/server/api/build.go +++ b/server/api/pipeline.go @@ -1,5 +1,6 @@ -// Copyright 2018 Drone.IO Inc. +// Copyright 2022 Woodpecker Authors // Copyright 2021 Informatyka Boguslawski sp. z o.o. sp.k., http://www.ib.pl/ +// Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -37,11 +38,11 @@ import ( "github.com/woodpecker-ci/woodpecker/server/store" ) -func CreateBuild(c *gin.Context) { +func CreatePipeline(c *gin.Context) { _store := store.FromContext(c) repo := session.Repo(c) - var p model.BuildOptions + var p model.PipelineOptions err := json.NewDecoder(c.Request.Body).Decode(&p) if err != nil { @@ -53,25 +54,25 @@ func CreateBuild(c *gin.Context) { lastCommit, _ := server.Config.Services.Remote.BranchHead(c, user, repo, p.Branch) - tmpBuild := createTmpBuild(model.EventManual, lastCommit, repo, user, &p) + tmpBuild := createTmpPipeline(model.EventManual, lastCommit, repo, user, &p) - build, err := pipeline.Create(c, _store, repo, tmpBuild) + pl, err := pipeline.Create(c, _store, repo, tmpBuild) if err != nil { handlePipelineErr(c, err) } else { - c.JSON(http.StatusOK, build) + c.JSON(http.StatusOK, pl) } } -func createTmpBuild(event model.WebhookEvent, commitSHA string, repo *model.Repo, user *model.User, opts *model.BuildOptions) *model.Build { - return &model.Build{ +func createTmpPipeline(event model.WebhookEvent, commitSHA string, repo *model.Repo, user *model.User, opts *model.PipelineOptions) *model.Pipeline { + return &model.Pipeline{ Event: event, Commit: commitSHA, Branch: opts.Branch, Timestamp: time.Now().UTC().Unix(), Avatar: user.Avatar, - Message: "MANUAL BUILD @ " + opts.Branch, + Message: "MANUAL PIPELINE @ " + opts.Branch, Ref: opts.Branch, AdditionalVariables: opts.Variables, @@ -84,7 +85,7 @@ func createTmpBuild(event model.WebhookEvent, commitSHA string, repo *model.Repo } } -func GetBuilds(c *gin.Context) { +func GetPipelines(c *gin.Context) { repo := session.Repo(c) page, err := strconv.Atoi(c.DefaultQuery("page", "1")) if err != nil { @@ -92,18 +93,18 @@ func GetBuilds(c *gin.Context) { return } - builds, err := store.FromContext(c).GetBuildList(repo, page) + pipelines, err := store.FromContext(c).GetPipelineList(repo, page) if err != nil { c.AbortWithStatus(http.StatusInternalServerError) return } - c.JSON(http.StatusOK, builds) + c.JSON(http.StatusOK, pipelines) } -func GetBuild(c *gin.Context) { +func GetPipeline(c *gin.Context) { _store := store.FromContext(c) if c.Param("number") == "latest" { - GetBuildLast(c) + GetPipelineLast(c) return } @@ -114,62 +115,62 @@ func GetBuild(c *gin.Context) { return } - build, err := _store.GetBuildNumber(repo, num) + pl, err := _store.GetPipelineNumber(repo, num) if err != nil { _ = c.AbortWithError(http.StatusInternalServerError, err) return } - files, _ := _store.FileList(build) - procs, _ := _store.ProcList(build) - if build.Procs, err = model.Tree(procs); err != nil { + files, _ := _store.FileList(pl) + procs, _ := _store.ProcList(pl) + if pl.Procs, err = model.Tree(procs); err != nil { _ = c.AbortWithError(http.StatusInternalServerError, err) return } - build.Files = files + pl.Files = files - c.JSON(http.StatusOK, build) + c.JSON(http.StatusOK, pl) } -func GetBuildLast(c *gin.Context) { +func GetPipelineLast(c *gin.Context) { _store := store.FromContext(c) repo := session.Repo(c) branch := c.DefaultQuery("branch", repo.Branch) - build, err := _store.GetBuildLast(repo, branch) + pl, err := _store.GetPipelineLast(repo, branch) if err != nil { c.String(http.StatusInternalServerError, err.Error()) return } - procs, err := _store.ProcList(build) + procs, err := _store.ProcList(pl) if err != nil { _ = c.AbortWithError(http.StatusInternalServerError, err) return } - if build.Procs, err = model.Tree(procs); err != nil { + if pl.Procs, err = model.Tree(procs); err != nil { _ = c.AbortWithError(http.StatusInternalServerError, err) return } - c.JSON(http.StatusOK, build) + c.JSON(http.StatusOK, pl) } -func GetBuildLogs(c *gin.Context) { +func GetPipelineLogs(c *gin.Context) { _store := store.FromContext(c) repo := session.Repo(c) - // parse the build number and job sequence number from + // parse the pipeline number and job sequence number from // the request parameter. num, _ := strconv.ParseInt(c.Params.ByName("number"), 10, 64) ppid, _ := strconv.Atoi(c.Params.ByName("pid")) name := c.Params.ByName("proc") - build, err := _store.GetBuildNumber(repo, num) + pl, err := _store.GetPipelineNumber(repo, num) if err != nil { _ = c.AbortWithError(404, err) return } - proc, err := _store.ProcChild(build, ppid, name) + proc, err := _store.ProcChild(pl, ppid, name) if err != nil { _ = c.AbortWithError(404, err) return @@ -193,18 +194,18 @@ func GetProcLogs(c *gin.Context) { _store := store.FromContext(c) repo := session.Repo(c) - // parse the build number and job sequence number from + // parse the pipeline number and job sequence number from // the request parameter. num, _ := strconv.ParseInt(c.Params.ByName("number"), 10, 64) pid, _ := strconv.Atoi(c.Params.ByName("pid")) - build, err := _store.GetBuildNumber(repo, num) + pl, err := _store.GetPipelineNumber(repo, num) if err != nil { _ = c.AbortWithError(http.StatusNotFound, err) return } - proc, err := _store.ProcFind(build, pid) + proc, err := _store.ProcFind(pl, pid) if err != nil { _ = c.AbortWithError(http.StatusNotFound, err) return @@ -224,7 +225,7 @@ func GetProcLogs(c *gin.Context) { } } -func GetBuildConfig(c *gin.Context) { +func GetPipelineConfig(c *gin.Context) { _store := store.FromContext(c) repo := session.Repo(c) num, err := strconv.ParseInt(c.Param("number"), 10, 64) @@ -233,13 +234,13 @@ func GetBuildConfig(c *gin.Context) { return } - build, err := _store.GetBuildNumber(repo, num) + pl, err := _store.GetPipelineNumber(repo, num) if err != nil { _ = c.AbortWithError(http.StatusInternalServerError, err) return } - configs, err := _store.ConfigsForBuild(build.ID) + configs, err := _store.ConfigsForPipeline(pl.ID) if err != nil { c.String(http.StatusInternalServerError, err.Error()) return @@ -248,19 +249,19 @@ func GetBuildConfig(c *gin.Context) { c.JSON(http.StatusOK, configs) } -// DeleteBuild cancels a build -func DeleteBuild(c *gin.Context) { +// DeletePipeline cancels a pipeline +func DeletePipeline(c *gin.Context) { _store := store.FromContext(c) repo := session.Repo(c) num, _ := strconv.ParseInt(c.Params.ByName("number"), 10, 64) - build, err := _store.GetBuildNumber(repo, num) + pl, err := _store.GetPipelineNumber(repo, num) if err != nil { _ = c.AbortWithError(http.StatusNotFound, err) return } - if err := pipeline.Cancel(c, _store, repo, build); err != nil { + if err := pipeline.Cancel(c, _store, repo, pl); err != nil { handlePipelineErr(c, err) } else { c.Status(http.StatusNoContent) @@ -276,17 +277,17 @@ func PostApproval(c *gin.Context) { num, _ = strconv.ParseInt(c.Params.ByName("number"), 10, 64) ) - build, err := _store.GetBuildNumber(repo, num) + pl, err := _store.GetPipelineNumber(repo, num) if err != nil { _ = c.AbortWithError(404, err) return } - newBuild, err := pipeline.Approve(c, _store, build, user, repo) + newpipeline, err := pipeline.Approve(c, _store, pl, user, repo) if err != nil { handlePipelineErr(c, err) } else { - c.JSON(200, newBuild) + c.JSON(200, newpipeline) } } @@ -299,31 +300,31 @@ func PostDecline(c *gin.Context) { num, _ = strconv.ParseInt(c.Params.ByName("number"), 10, 64) ) - build, err := _store.GetBuildNumber(repo, num) + pl, err := _store.GetPipelineNumber(repo, num) if err != nil { c.String(http.StatusNotFound, "%v", err) return } - build, err = pipeline.Decline(c, _store, build, user, repo) + pl, err = pipeline.Decline(c, _store, pl, user, repo) if err != nil { handlePipelineErr(c, err) } else { - c.JSON(200, build) + c.JSON(200, pl) } } -func GetBuildQueue(c *gin.Context) { - out, err := store.FromContext(c).GetBuildQueue() +func GetPipelineQueue(c *gin.Context) { + out, err := store.FromContext(c).GetPipelineQueue() if err != nil { - c.String(500, "Error getting build queue. %s", err) + c.String(500, "Error getting pipeline queue. %s", err) return } c.JSON(200, out) } -// PostBuild restarts a build optional with altered event, deploy or environment -func PostBuild(c *gin.Context) { +// PostPipeline restarts a pipeline optional with altered event, deploy or environment +func PostPipeline(c *gin.Context) { _store := store.FromContext(c) repo := session.Repo(c) @@ -340,9 +341,9 @@ func PostBuild(c *gin.Context) { return } - build, err := _store.GetBuildNumber(repo, num) + pl, err := _store.GetPipelineNumber(repo, num) if err != nil { - log.Error().Msgf("failure to get build %d. %s", num, err) + log.Error().Msgf("failure to get pipeline %d. %s", num, err) _ = c.AbortWithError(404, err) return } @@ -351,20 +352,20 @@ func PostBuild(c *gin.Context) { refreshUserToken(c, user) // make Deploy overridable - build.Deploy = c.DefaultQuery("deploy_to", build.Deploy) + pl.Deploy = c.DefaultQuery("deploy_to", pl.Deploy) // make Event overridable if event, ok := c.GetQuery("event"); ok { - build.Event = model.WebhookEvent(event) + pl.Event = model.WebhookEvent(event) - if !model.ValidateWebhookEvent(build.Event) { - msg := fmt.Sprintf("build event '%s' is invalid", event) + if !model.ValidateWebhookEvent(pl.Event) { + msg := fmt.Sprintf("pipeline event '%s' is invalid", event) c.String(http.StatusBadRequest, msg) return } } - // Read query string parameters into buildParams, exclude reserved params + // Read query string parameters into pipelineParams, exclude reserved params envs := map[string]string{} for key, val := range c.Request.URL.Query() { switch key { @@ -372,43 +373,43 @@ func PostBuild(c *gin.Context) { case "fork", "event", "deploy_to": continue default: - // We only accept string literals, because build parameters will be + // We only accept string literals, because pipeline parameters will be // injected as environment variables // TODO: sanitize the value envs[key] = val[0] } } - newBuild, err := pipeline.Restart(c, _store, build, user, repo, envs) + newpipeline, err := pipeline.Restart(c, _store, pl, user, repo, envs) if err != nil { handlePipelineErr(c, err) } else { - c.JSON(200, newBuild) + c.JSON(200, newpipeline) } } -func DeleteBuildLogs(c *gin.Context) { +func DeletePipelineLogs(c *gin.Context) { _store := store.FromContext(c) repo := session.Repo(c) user := session.User(c) num, _ := strconv.ParseInt(c.Params.ByName("number"), 10, 64) - build, err := _store.GetBuildNumber(repo, num) + pl, err := _store.GetPipelineNumber(repo, num) if err != nil { _ = c.AbortWithError(404, err) return } - procs, err := _store.ProcList(build) + procs, err := _store.ProcList(pl) if err != nil { _ = c.AbortWithError(404, err) return } - switch build.Status { + switch pl.Status { case model.StatusRunning, model.StatusPending: - c.String(400, "Cannot delete logs for a pending or running build") + c.String(400, "Cannot delete logs for a pending or running pipeline") return } diff --git a/server/api/repo.go b/server/api/repo.go index 10d09e539..1103b0c07 100644 --- a/server/api/repo.go +++ b/server/api/repo.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -33,7 +34,7 @@ import ( // TODO: make it set system wide via environment variables const ( - defaultTimeout int64 = 60 // 1 hour default build time + defaultTimeout int64 = 60 // 1 hour default pipeline time maxTimeout int64 = defaultTimeout * 2 ) diff --git a/server/api/stream.go b/server/api/stream.go index 7359d8220..ed148aa4b 100644 --- a/server/api/stream.go +++ b/server/api/stream.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -140,18 +141,18 @@ func LogStreamSSE(c *gin.Context) { repo := session.Repo(c) _store := store.FromContext(c) - // // parse the build number and job sequence number from + // // parse the pipeline number and job sequence number from // // the repquest parameter. - buildn, _ := strconv.ParseInt(c.Param("build"), 10, 64) + pipelinen, _ := strconv.ParseInt(c.Param("pipeline"), 10, 64) jobn, _ := strconv.Atoi(c.Param("number")) - build, err := _store.GetBuildNumber(repo, buildn) + pipeline, err := _store.GetPipelineNumber(repo, pipelinen) if err != nil { - log.Debug().Msgf("stream cannot get build number: %v", err) - logWriteStringErr(io.WriteString(rw, "event: error\ndata: build not found\n\n")) + log.Debug().Msgf("stream cannot get pipeline number: %v", err) + logWriteStringErr(io.WriteString(rw, "event: error\ndata: pipeline not found\n\n")) return } - proc, err := _store.ProcFind(build, jobn) + proc, err := _store.ProcFind(pipeline, jobn) if err != nil { log.Debug().Msgf("stream cannot get proc number: %v", err) logWriteStringErr(io.WriteString(rw, "event: error\ndata: process not found\n\n")) diff --git a/server/badges/badges.go b/server/badges/badges.go index cc2fadb2a..bef782639 100644 --- a/server/badges/badges.go +++ b/server/badges/badges.go @@ -25,7 +25,7 @@ var ( ) // Generate an SVG badge based on a pipeline -func Generate(pipeline *model.Build) string { +func Generate(pipeline *model.Pipeline) string { if pipeline == nil { return badgeNone } diff --git a/server/ccmenu/cc.go b/server/ccmenu/cc.go index 8525740e6..47c4b932a 100644 --- a/server/ccmenu/cc.go +++ b/server/ccmenu/cc.go @@ -23,7 +23,7 @@ import ( "github.com/woodpecker-ci/woodpecker/server/model" ) -// CCMenu displays the build status of projects on a ci server as an item in the Mac's menu bar. +// CCMenu displays the pipeline status of projects on a ci server as an item in the Mac's menu bar. // It started as part of the CruiseControl project that built the first continuous integration server. // // http://ccmenu.org/ @@ -43,7 +43,7 @@ type CCProject struct { WebURL string `xml:"webUrl,attr"` } -func New(r *model.Repo, b *model.Build, link string) *CCProjects { +func New(r *model.Repo, b *model.Pipeline, link string) *CCProjects { proj := &CCProject{ Name: r.FullName, WebURL: link, @@ -52,8 +52,8 @@ func New(r *model.Repo, b *model.Build, link string) *CCProjects { LastBuildLabel: "Unknown", } - // if the build is not currently running then - // we can return the latest build status. + // if the pipeline is not currently running then + // we can return the latest pipeline status. if b.Status != model.StatusPending && b.Status != model.StatusRunning { proj.Activity = "Sleeping" @@ -61,7 +61,7 @@ func New(r *model.Repo, b *model.Build, link string) *CCProjects { proj.LastBuildLabel = strconv.FormatInt(b.Number, 10) } - // ensure the last build Status accepts a valid + // ensure the last pipeline status accepts a valid // ccmenu enumeration switch b.Status { case model.StatusError, model.StatusKilled: diff --git a/server/ccmenu/cc_test.go b/server/ccmenu/cc_test.go index c1f6be23c..d91c9cb1c 100644 --- a/server/ccmenu/cc_test.go +++ b/server/ccmenu/cc_test.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -32,7 +33,7 @@ func TestCC(t *testing.T) { r := &model.Repo{ FullName: "foo/bar", } - b := &model.Build{ + b := &model.Pipeline{ Status: model.StatusSuccess, Number: 1, Started: now, @@ -49,7 +50,7 @@ func TestCC(t *testing.T) { g.It("Should properly label exceptions", func() { r := &model.Repo{FullName: "foo/bar"} - b := &model.Build{ + b := &model.Pipeline{ Status: model.StatusError, Number: 1, Started: 1257894000, @@ -61,7 +62,7 @@ func TestCC(t *testing.T) { g.It("Should properly label success", func() { r := &model.Repo{FullName: "foo/bar"} - b := &model.Build{ + b := &model.Pipeline{ Status: model.StatusSuccess, Number: 1, Started: 1257894000, @@ -73,7 +74,7 @@ func TestCC(t *testing.T) { g.It("Should properly label failure", func() { r := &model.Repo{FullName: "foo/bar"} - b := &model.Build{ + b := &model.Pipeline{ Status: model.StatusFailure, Number: 1, Started: 1257894000, @@ -85,7 +86,7 @@ func TestCC(t *testing.T) { g.It("Should properly label running", func() { r := &model.Repo{FullName: "foo/bar"} - b := &model.Build{ + b := &model.Pipeline{ Status: model.StatusRunning, Number: 1, Started: 1257894000, diff --git a/server/cron/cron.go b/server/cron/cron.go index 4e3679fb5..c9f5dc253 100644 --- a/server/cron/cron.go +++ b/server/cron/cron.go @@ -105,7 +105,7 @@ func runCron(store store.Store, remote remote.Remote, cron *model.Cron, now time return err } -func createBuild(ctx context.Context, store store.Store, remote remote.Remote, cron *model.Cron) (*model.Repo, *model.Build, error) { +func createBuild(ctx context.Context, store store.Store, remote remote.Remote, cron *model.Cron) (*model.Repo, *model.Pipeline, error) { repo, err := store.GetRepo(cron.RepoID) if err != nil { return nil, nil, err @@ -126,7 +126,7 @@ func createBuild(ctx context.Context, store store.Store, remote remote.Remote, c return nil, nil, err } - return repo, &model.Build{ + return repo, &model.Pipeline{ Event: model.EventCron, Commit: commit, Ref: "refs/heads/" + cron.Branch, diff --git a/server/cron/cron_test.go b/server/cron/cron_test.go index a441cd0b3..831c156ca 100644 --- a/server/cron/cron_test.go +++ b/server/cron/cron_test.go @@ -49,18 +49,18 @@ func TestCreateBuild(t *testing.T) { store.On("GetUser", mock.Anything).Return(creator, nil) remote.On("BranchHead", mock.Anything, creator, repo1, "default").Return("sha1", nil) - _, build, err := createBuild(ctx, store, remote, &model.Cron{ + _, pipeline, err := createBuild(ctx, store, remote, &model.Cron{ Name: "test", }) assert.NoError(t, err) - assert.EqualValues(t, &model.Build{ + assert.EqualValues(t, &model.Pipeline{ Event: "cron", Commit: "sha1", Branch: "default", Ref: "refs/heads/default", Message: "test", Sender: "test", - }, build) + }, pipeline) } func TestCalcNewNext(t *testing.T) { diff --git a/server/grpc/rpc.go b/server/grpc/rpc.go index 97c6d39a3..12b43ffd5 100644 --- a/server/grpc/rpc.go +++ b/server/grpc/rpc.go @@ -1,5 +1,6 @@ -// Copyright 2018 Drone.IO Inc. +// Copyright 2022 Woodpecker Authors // Copyright 2021 Informatyka Boguslawski sp. z o.o. sp.k., http://www.ib.pl/ +// Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -41,14 +42,14 @@ import ( ) type RPC struct { - remote remote.Remote - queue queue.Queue - pubsub pubsub.Publisher - logger logging.Log - store store.Store - host string - buildTime *prometheus.GaugeVec - buildCount *prometheus.CounterVec + remote remote.Remote + queue queue.Queue + pubsub pubsub.Publisher + logger logging.Log + store store.Store + host string + pipelineTime *prometheus.GaugeVec + pipelineCount *prometheus.CounterVec } // Next implements the rpc.Next function @@ -107,13 +108,13 @@ func (s *RPC) Update(c context.Context, id string, state rpc.State) error { return err } - build, err := s.store.GetBuild(pproc.BuildID) + pipeline, err := s.store.GetPipeline(pproc.PipelineID) if err != nil { - log.Error().Msgf("error: cannot find build with id %d: %s", pproc.BuildID, err) + log.Error().Msgf("error: cannot find pipeline with id %d: %s", pproc.PipelineID, err) return err } - proc, err := s.store.ProcChild(build, pproc.PID, state.Proc) + proc, err := s.store.ProcChild(pipeline, pproc.PID, state.Proc) if err != nil { log.Error().Msgf("error: cannot find proc with name %s: %s", state.Proc, err) return err @@ -127,20 +128,20 @@ func (s *RPC) Update(c context.Context, id string, state rpc.State) error { } } - repo, err := s.store.GetRepo(build.RepoID) + repo, err := s.store.GetRepo(pipeline.RepoID) if err != nil { - log.Error().Msgf("error: cannot find repo with id %d: %s", build.RepoID, err) + log.Error().Msgf("error: cannot find repo with id %d: %s", pipeline.RepoID, err) return err } - if _, err = shared.UpdateProcStatus(s.store, *proc, state, build.Started); err != nil { + if _, err = shared.UpdateProcStatus(s.store, *proc, state, pipeline.Started); err != nil { log.Error().Err(err).Msg("rpc.update: cannot update proc") } - if build.Procs, err = s.store.ProcList(build); err != nil { + if pipeline.Procs, err = s.store.ProcList(pipeline); err != nil { log.Error().Err(err).Msg("can not get proc list from store") } - if build.Procs, err = model.Tree(build.Procs); err != nil { + if pipeline.Procs, err = model.Tree(pipeline.Procs); err != nil { log.Error().Err(err).Msg("can not build tree from proc list") return err } @@ -151,8 +152,8 @@ func (s *RPC) Update(c context.Context, id string, state rpc.State) error { }, } message.Data, _ = json.Marshal(model.Event{ - Repo: *repo, - Build: *build, + Repo: *repo, + Pipeline: *pipeline, }) if err := s.pubsub.Publish(c, "topic/events", message); err != nil { log.Error().Err(err).Msg("can not publish proc list to") @@ -174,13 +175,13 @@ func (s *RPC) Upload(c context.Context, id string, file *rpc.File) error { return err } - build, err := s.store.GetBuild(pproc.BuildID) + pipeline, err := s.store.GetPipeline(pproc.PipelineID) if err != nil { - log.Error().Msgf("error: cannot find build with id %d: %s", pproc.BuildID, err) + log.Error().Msgf("error: cannot find pipeline with id %d: %s", pproc.PipelineID, err) return err } - proc, err := s.store.ProcChild(build, pproc.PID, file.Proc) + proc, err := s.store.ProcChild(pipeline, pproc.PID, file.Proc) if err != nil { log.Error().Msgf("error: cannot find child proc with name %s: %s", file.Proc, err) return err @@ -194,13 +195,13 @@ func (s *RPC) Upload(c context.Context, id string, file *rpc.File) error { } report := &model.File{ - BuildID: proc.BuildID, - ProcID: proc.ID, - PID: proc.PID, - Mime: file.Mime, - Name: file.Name, - Size: file.Size, - Time: file.Time, + PipelineID: proc.PipelineID, + ProcID: proc.ID, + PID: proc.PID, + Mime: file.Mime, + Name: file.Name, + Size: file.Size, + Time: file.Time, } if d, ok := file.Meta["X-Tests-Passed"]; ok { report.Passed, _ = strconv.Atoi(d) @@ -254,26 +255,26 @@ func (s *RPC) Init(c context.Context, id string, state rpc.State) error { } } - build, err := s.store.GetBuild(proc.BuildID) + pipeline, err := s.store.GetPipeline(proc.PipelineID) if err != nil { - log.Error().Msgf("error: cannot find build with id %d: %s", proc.BuildID, err) + log.Error().Msgf("error: cannot find pipeline with id %d: %s", proc.PipelineID, err) return err } - repo, err := s.store.GetRepo(build.RepoID) + repo, err := s.store.GetRepo(pipeline.RepoID) if err != nil { - log.Error().Msgf("error: cannot find repo with id %d: %s", build.RepoID, err) + log.Error().Msgf("error: cannot find repo with id %d: %s", pipeline.RepoID, err) return err } - if build.Status == model.StatusPending { - if build, err = shared.UpdateToStatusRunning(s.store, *build, state.Started); err != nil { - log.Error().Msgf("error: init: cannot update build_id %d state: %s", build.ID, err) + if pipeline.Status == model.StatusPending { + if pipeline, err = shared.UpdateToStatusRunning(s.store, *pipeline, state.Started); err != nil { + log.Error().Msgf("error: init: cannot update build_id %d state: %s", pipeline.ID, err) } } defer func() { - build.Procs, _ = s.store.ProcList(build) + pipeline.Procs, _ = s.store.ProcList(pipeline) message := pubsub.Message{ Labels: map[string]string{ "repo": repo.FullName, @@ -281,8 +282,8 @@ func (s *RPC) Init(c context.Context, id string, state rpc.State) error { }, } message.Data, _ = json.Marshal(model.Event{ - Repo: *repo, - Build: *build, + Repo: *repo, + Pipeline: *pipeline, }) if err := s.pubsub.Publish(c, "topic/events", message); err != nil { log.Error().Err(err).Msg("can not publish proc list to") @@ -306,21 +307,21 @@ func (s *RPC) Done(c context.Context, id string, state rpc.State) error { return err } - build, err := s.store.GetBuild(proc.BuildID) + pipeline, err := s.store.GetPipeline(proc.PipelineID) if err != nil { - log.Error().Msgf("error: cannot find build with id %d: %s", proc.BuildID, err) + log.Error().Msgf("error: cannot find pipeline with id %d: %s", proc.PipelineID, err) return err } - repo, err := s.store.GetRepo(build.RepoID) + repo, err := s.store.GetRepo(pipeline.RepoID) if err != nil { - log.Error().Msgf("error: cannot find repo with id %d: %s", build.RepoID, err) + log.Error().Msgf("error: cannot find repo with id %d: %s", pipeline.RepoID, err) return err } log.Trace(). Str("repo_id", fmt.Sprint(repo.ID)). - Str("build_id", fmt.Sprint(build.ID)). + Str("build_id", fmt.Sprint(pipeline.ID)). Str("proc_id", id). Msgf("gRPC Done with state: %#v", state) @@ -338,34 +339,34 @@ func (s *RPC) Done(c context.Context, id string, state rpc.State) error { log.Error().Msgf("error: done: cannot ack proc_id %d: %s", procID, err) } - procs, err := s.store.ProcList(build) + procs, err := s.store.ProcList(pipeline) if err != nil { return err } s.completeChildrenIfParentCompleted(procs, proc) if !model.IsThereRunningStage(procs) { - if build, err = shared.UpdateStatusToDone(s.store, *build, model.BuildStatus(procs), proc.Stopped); err != nil { - log.Error().Err(err).Msgf("error: done: cannot update build_id %d final state", build.ID) + if pipeline, err = shared.UpdateStatusToDone(s.store, *pipeline, model.PipelineStatus(procs), proc.Stopped); err != nil { + log.Error().Err(err).Msgf("error: done: cannot update build_id %d final state", pipeline.ID) } } - s.updateRemoteStatus(c, repo, build, proc) + s.updateRemoteStatus(c, repo, pipeline, proc) if err := s.logger.Close(c, id); err != nil { log.Error().Err(err).Msgf("done: cannot close build_id %d logger", proc.ID) } - if err := s.notify(c, repo, build, procs); err != nil { + if err := s.notify(c, repo, pipeline, procs); err != nil { return err } - if build.Status == model.StatusSuccess || build.Status == model.StatusFailure { - s.buildCount.WithLabelValues(repo.FullName, build.Branch, string(build.Status), "total").Inc() - s.buildTime.WithLabelValues(repo.FullName, build.Branch, string(build.Status), "total").Set(float64(build.Finished - build.Started)) + if pipeline.Status == model.StatusSuccess || pipeline.Status == model.StatusFailure { + s.pipelineCount.WithLabelValues(repo.FullName, pipeline.Branch, string(pipeline.Status), "total").Inc() + s.pipelineTime.WithLabelValues(repo.FullName, pipeline.Branch, string(pipeline.Status), "total").Set(float64(pipeline.Finished - pipeline.Started)) } if model.IsMultiPipeline(procs) { - s.buildTime.WithLabelValues(repo.FullName, build.Branch, string(proc.State), proc.Name).Set(float64(proc.Stopped - proc.Started)) + s.pipelineTime.WithLabelValues(repo.FullName, pipeline.Branch, string(proc.State), proc.Name).Set(float64(proc.Stopped - proc.Started)) } return nil @@ -391,7 +392,7 @@ func (s *RPC) completeChildrenIfParentCompleted(procs []*model.Proc, completedPr } } -func (s *RPC) updateRemoteStatus(ctx context.Context, repo *model.Repo, build *model.Build, proc *model.Proc) { +func (s *RPC) updateRemoteStatus(ctx context.Context, repo *model.Repo, pipeline *model.Pipeline, proc *model.Proc) { user, err := s.store.GetUser(repo.UserID) if err != nil { log.Error().Err(err).Msgf("can not get user with id '%d'", repo.UserID) @@ -411,15 +412,15 @@ func (s *RPC) updateRemoteStatus(ctx context.Context, repo *model.Repo, build *m // only do status updates for parent procs if proc != nil && proc.IsParent() { - err = s.remote.Status(ctx, user, repo, build, proc) + err = s.remote.Status(ctx, user, repo, pipeline, proc) if err != nil { - log.Error().Err(err).Msgf("error setting commit status for %s/%d", repo.FullName, build.Number) + log.Error().Err(err).Msgf("error setting commit status for %s/%d", repo.FullName, pipeline.Number) } } } -func (s *RPC) notify(c context.Context, repo *model.Repo, build *model.Build, procs []*model.Proc) (err error) { - if build.Procs, err = model.Tree(procs); err != nil { +func (s *RPC) notify(c context.Context, repo *model.Repo, pipeline *model.Pipeline, procs []*model.Proc) (err error) { + if pipeline.Procs, err = model.Tree(procs); err != nil { return err } message := pubsub.Message{ @@ -429,8 +430,8 @@ func (s *RPC) notify(c context.Context, repo *model.Repo, build *model.Build, pr }, } message.Data, _ = json.Marshal(model.Event{ - Repo: *repo, - Build: *build, + Repo: *repo, + Pipeline: *pipeline, }) if err := s.pubsub.Publish(c, "topic/events", message); err != nil { log.Error().Err(err).Msgf("grpc could not notify event: '%v'", message) diff --git a/server/grpc/server.go b/server/grpc/server.go index 43e1f1d4b..38e4a96c4 100644 --- a/server/grpc/server.go +++ b/server/grpc/server.go @@ -37,25 +37,25 @@ type WoodpeckerServer struct { } func NewWoodpeckerServer(remote remote.Remote, queue queue.Queue, logger logging.Log, pubsub pubsub.Publisher, store store.Store, host string) *WoodpeckerServer { - buildTime := promauto.NewGaugeVec(prometheus.GaugeOpts{ + pipelineTime := promauto.NewGaugeVec(prometheus.GaugeOpts{ Namespace: "woodpecker", - Name: "build_time", - Help: "Build time.", + Name: "pipeline_time", + Help: "Pipeline time.", }, []string{"repo", "branch", "status", "pipeline"}) - buildCount := promauto.NewCounterVec(prometheus.CounterOpts{ + pipelineCount := promauto.NewCounterVec(prometheus.CounterOpts{ Namespace: "woodpecker", - Name: "build_count", - Help: "Build count.", + Name: "pipeline_count", + Help: "Pipeline count.", }, []string{"repo", "branch", "status", "pipeline"}) peer := RPC{ - remote: remote, - store: store, - queue: queue, - pubsub: pubsub, - logger: logger, - host: host, - buildTime: buildTime, - buildCount: buildCount, + remote: remote, + store: store, + queue: queue, + pubsub: pubsub, + logger: logger, + host: host, + pipelineTime: pipelineTime, + pipelineCount: pipelineCount, } return &WoodpeckerServer{peer: peer} } diff --git a/server/model/config.go b/server/model/config.go index 7649ff7c3..be6d1622c 100644 --- a/server/model/config.go +++ b/server/model/config.go @@ -17,11 +17,11 @@ package model // ConfigStore persists pipeline configuration to storage. type ConfigStore interface { - ConfigsForBuild(buildID int64) ([]*Config, error) + ConfigsForPipeline(pipelineID int64) ([]*Config, error) ConfigFindIdentical(repoID int64, hash string) (*Config, error) ConfigFindApproved(*Config) (bool, error) ConfigCreate(*Config) error - BuildConfigCreate(*BuildConfig) error + PipelineConfigCreate(*PipelineConfig) error } // Config represents a pipeline configuration. @@ -33,8 +33,8 @@ type Config struct { Data []byte `json:"data" xorm:"config_data"` } -// BuildConfig is the n:n relation between Build and Config -type BuildConfig struct { - ConfigID int64 `json:"-" xorm:"UNIQUE(s) NOT NULL 'config_id'"` - BuildID int64 `json:"-" xorm:"UNIQUE(s) NOT NULL 'build_id'"` +// PipelineConfig is the n:n relation between Pipeline and Config +type PipelineConfig struct { + ConfigID int64 `json:"-" xorm:"UNIQUE(s) NOT NULL 'config_id'"` + PipelineID int64 `json:"-" xorm:"UNIQUE(s) NOT NULL 'build_id'"` } diff --git a/server/model/const.go b/server/model/const.go index 7538e6e7b..ebfa6fb9d 100644 --- a/server/model/const.go +++ b/server/model/const.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/server/model/event.go b/server/model/event.go index 49ae8d390..b7078dafc 100644 --- a/server/model/event.go +++ b/server/model/event.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,11 +15,11 @@ package model -// EventType defines the possible types of build events. +// EventType defines the possible types of pipeline events. type EventType string -// Event represents a build event. +// Event represents a pipeline event. type Event struct { - Repo Repo `json:"repo"` - Build Build `json:"build"` + Repo Repo `json:"repo"` + Pipeline Pipeline `json:"build"` } diff --git a/server/model/file.go b/server/model/file.go index a74e34aaf..915fd0dea 100644 --- a/server/model/file.go +++ b/server/model/file.go @@ -19,7 +19,7 @@ import "io" // FileStore persists pipeline artifacts to storage. type FileStore interface { - FileList(*Build) ([]*File, error) + FileList(*Pipeline) ([]*File, error) FileFind(*Proc, string) (*File, error) FileRead(*Proc, string) (io.ReadCloser, error) FileCreate(*File, io.Reader) error @@ -27,18 +27,18 @@ type FileStore interface { // File represents a pipeline artifact. type File struct { - ID int64 `json:"id" xorm:"pk autoincr 'file_id'"` - BuildID int64 `json:"-" xorm:"INDEX 'file_build_id'"` - ProcID int64 `json:"proc_id" xorm:"UNIQUE(s) INDEX 'file_proc_id'"` - PID int `json:"pid" xorm:"file_pid"` - Name string `json:"name" xorm:"UNIQUE(s) file_name"` - Size int `json:"size" xorm:"file_size"` - Mime string `json:"mime" xorm:"file_mime"` - Time int64 `json:"time" xorm:"file_time"` - Passed int `json:"passed" xorm:"file_meta_passed"` - Failed int `json:"failed" xorm:"file_meta_failed"` - Skipped int `json:"skipped" xorm:"file_meta_skipped"` - Data []byte `json:"-" xorm:"file_data"` // TODO: dont store in db but object storage? + ID int64 `json:"id" xorm:"pk autoincr 'file_id'"` + PipelineID int64 `json:"-" xorm:"INDEX 'file_build_id'"` + ProcID int64 `json:"proc_id" xorm:"UNIQUE(s) INDEX 'file_proc_id'"` + PID int `json:"pid" xorm:"file_pid"` + Name string `json:"name" xorm:"UNIQUE(s) file_name"` + Size int `json:"size" xorm:"file_size"` + Mime string `json:"mime" xorm:"file_mime"` + Time int64 `json:"time" xorm:"file_time"` + Passed int `json:"passed" xorm:"file_meta_passed"` + Failed int `json:"failed" xorm:"file_meta_failed"` + Skipped int `json:"skipped" xorm:"file_meta_skipped"` + Data []byte `json:"-" xorm:"file_data"` // TODO: don't store in db but object storage? } // TableName return database table name for xorm diff --git a/server/model/build.go b/server/model/pipeline.go similarity index 95% rename from server/model/build.go rename to server/model/pipeline.go index e3ebae9e2..8161d2155 100644 --- a/server/model/build.go +++ b/server/model/pipeline.go @@ -15,8 +15,8 @@ package model -// swagger:model build -type Build struct { +// swagger:model pipeline +type Pipeline struct { ID int64 `json:"id" xorm:"pk autoincr 'build_id'"` RepoID int64 `json:"-" xorm:"UNIQUE(s) INDEX 'build_repo_id'"` Number int64 `json:"number" xorm:"UNIQUE(s) 'build_number'"` @@ -55,15 +55,15 @@ type Build struct { } // TableName return database table name for xorm -func (Build) TableName() string { - return "builds" +func (Pipeline) TableName() string { + return "pipelines" } -type UpdateBuildStore interface { - UpdateBuild(*Build) error +type UpdatePipelineStore interface { + UpdatePipeline(*Pipeline) error } -type BuildOptions struct { +type PipelineOptions struct { Branch string `json:"branch"` Variables map[string]string `json:"variables"` } diff --git a/server/model/proc.go b/server/model/proc.go index e3914931e..f7ded0010 100644 --- a/server/model/proc.go +++ b/server/model/proc.go @@ -20,32 +20,32 @@ import "fmt" // ProcStore persists process information to storage. type ProcStore interface { ProcLoad(int64) (*Proc, error) - ProcFind(*Build, int) (*Proc, error) - ProcChild(*Build, int, string) (*Proc, error) - ProcList(*Build) ([]*Proc, error) + ProcFind(*Pipeline, int) (*Proc, error) + ProcChild(*Pipeline, int, string) (*Proc, error) + ProcList(*Pipeline) ([]*Proc, error) ProcCreate([]*Proc) error ProcUpdate(*Proc) error - ProcClear(*Build) error + ProcClear(*Pipeline) error } -// Proc represents a process in the build pipeline. +// Proc represents a process in the pipeline. // swagger:model proc type Proc struct { - ID int64 `json:"id" xorm:"pk autoincr 'proc_id'"` - BuildID int64 `json:"build_id" xorm:"UNIQUE(s) INDEX 'proc_build_id'"` - PID int `json:"pid" xorm:"UNIQUE(s) 'proc_pid'"` - PPID int `json:"ppid" xorm:"proc_ppid"` - PGID int `json:"pgid" xorm:"proc_pgid"` - Name string `json:"name" xorm:"proc_name"` - State StatusValue `json:"state" xorm:"proc_state"` - Error string `json:"error,omitempty" xorm:"VARCHAR(500) proc_error"` - ExitCode int `json:"exit_code" xorm:"proc_exit_code"` - Started int64 `json:"start_time,omitempty" xorm:"proc_started"` - Stopped int64 `json:"end_time,omitempty" xorm:"proc_stopped"` - Machine string `json:"machine,omitempty" xorm:"proc_machine"` - Platform string `json:"platform,omitempty" xorm:"proc_platform"` - Environ map[string]string `json:"environ,omitempty" xorm:"json 'proc_environ'"` - Children []*Proc `json:"children,omitempty" xorm:"-"` + ID int64 `json:"id" xorm:"pk autoincr 'proc_id'"` + PipelineID int64 `json:"build_id" xorm:"UNIQUE(s) INDEX 'proc_build_id'"` + PID int `json:"pid" xorm:"UNIQUE(s) 'proc_pid'"` + PPID int `json:"ppid" xorm:"proc_ppid"` + PGID int `json:"pgid" xorm:"proc_pgid"` + Name string `json:"name" xorm:"proc_name"` + State StatusValue `json:"state" xorm:"proc_state"` + Error string `json:"error,omitempty" xorm:"VARCHAR(500) proc_error"` + ExitCode int `json:"exit_code" xorm:"proc_exit_code"` + Started int64 `json:"start_time,omitempty" xorm:"proc_started"` + Stopped int64 `json:"end_time,omitempty" xorm:"proc_stopped"` + Machine string `json:"machine,omitempty" xorm:"proc_machine"` + Platform string `json:"platform,omitempty" xorm:"proc_platform"` + Environ map[string]string `json:"environ,omitempty" xorm:"json 'proc_environ'"` + Children []*Proc `json:"children,omitempty" xorm:"-"` } type UpdateProcStore interface { @@ -111,8 +111,8 @@ func Tree(procs []*Proc) ([]*Proc, error) { return nodes, nil } -// BuildStatus determine build status based on corresponding proc list -func BuildStatus(procs []*Proc) StatusValue { +// PipelineStatus determine pipeline status based on corresponding proc list +func PipelineStatus(procs []*Proc) StatusValue { status := StatusSuccess for _, p := range procs { diff --git a/server/model/proc_test.go b/server/model/proc_test.go index 5c876e4fd..ace58889e 100644 --- a/server/model/proc_test.go +++ b/server/model/proc_test.go @@ -22,32 +22,32 @@ import ( func TestTree(t *testing.T) { procs := []*Proc{{ - ID: 25, - PID: 2, - BuildID: 6, - PPID: 1, - PGID: 2, - Name: "clone", - State: StatusSuccess, - Error: "0", + ID: 25, + PID: 2, + PipelineID: 6, + PPID: 1, + PGID: 2, + Name: "clone", + State: StatusSuccess, + Error: "0", }, { - ID: 24, - BuildID: 6, - PID: 1, - PPID: 0, - PGID: 1, - Name: "lint", - State: StatusFailure, - Error: "1", + ID: 24, + PipelineID: 6, + PID: 1, + PPID: 0, + PGID: 1, + Name: "lint", + State: StatusFailure, + Error: "1", }, { - ID: 26, - BuildID: 6, - PID: 3, - PPID: 1, - PGID: 3, - Name: "lint", - State: StatusFailure, - Error: "1", + ID: 26, + PipelineID: 6, + PID: 3, + PPID: 1, + PGID: 3, + Name: "lint", + State: StatusFailure, + Error: "1", }} procs, err := Tree(procs) assert.NoError(t, err) @@ -55,14 +55,14 @@ func TestTree(t *testing.T) { assert.Len(t, procs[0].Children, 2) procs = []*Proc{{ - ID: 25, - PID: 2, - BuildID: 6, - PPID: 1, - PGID: 2, - Name: "clone", - State: StatusSuccess, - Error: "0", + ID: 25, + PID: 2, + PipelineID: 6, + PPID: 1, + PGID: 2, + Name: "clone", + State: StatusSuccess, + Error: "0", }} _, err = Tree(procs) assert.Error(t, err) diff --git a/server/model/redirection.go b/server/model/redirection.go index 5481d590b..fa780fe17 100644 --- a/server/model/redirection.go +++ b/server/model/redirection.go @@ -1,3 +1,17 @@ +// Copyright 2022 Woodpecker Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package model type Redirection struct { diff --git a/server/model/secret.go b/server/model/secret.go index f2eacc5c3..9cfb861e3 100644 --- a/server/model/secret.go +++ b/server/model/secret.go @@ -31,7 +31,7 @@ var ( // SecretService defines a service for managing secrets. type SecretService interface { - SecretListBuild(*Repo, *Build) ([]*Secret, error) + SecretListPipeline(*Repo, *Pipeline) ([]*Secret, error) // Repository secrets SecretFind(*Repo, string) (*Secret, error) SecretList(*Repo) ([]*Secret, error) diff --git a/server/pipeline/approve.go b/server/pipeline/approve.go index c56c18c23..4a0b9fd1d 100644 --- a/server/pipeline/approve.go +++ b/server/pipeline/approve.go @@ -26,23 +26,23 @@ import ( "github.com/woodpecker-ci/woodpecker/server/store" ) -// Approve update the status to pending for blocked build because of a gated repo +// Approve update the status to pending for blocked pipeline because of a gated repo // and start them afterwards -func Approve(ctx context.Context, store store.Store, build *model.Build, user *model.User, repo *model.Repo) (*model.Build, error) { - if build.Status != model.StatusBlocked { - return nil, ErrBadRequest{Msg: fmt.Sprintf("cannot decline a build with status %s", build.Status)} +func Approve(ctx context.Context, store store.Store, pipeline *model.Pipeline, user *model.User, repo *model.Repo) (*model.Pipeline, error) { + if pipeline.Status != model.StatusBlocked { + return nil, ErrBadRequest{Msg: fmt.Sprintf("cannot decline a pipeline with status %s", pipeline.Status)} } - // fetch the build file from the database - configs, err := store.ConfigsForBuild(build.ID) + // fetch the pipeline file from the database + configs, err := store.ConfigsForPipeline(pipeline.ID) if err != nil { - msg := fmt.Sprintf("failure to get build config for %s. %s", repo.FullName, err) + msg := fmt.Sprintf("failure to get pipeline config for %s. %s", repo.FullName, err) log.Error().Msg(msg) return nil, ErrNotFound{Msg: msg} } - if build, err = shared.UpdateToStatusPending(store, *build, user.Login); err != nil { - return nil, fmt.Errorf("error updating build. %s", err) + if pipeline, err = shared.UpdateToStatusPending(store, *pipeline, user.Login); err != nil { + return nil, fmt.Errorf("error updating pipeline. %s", err) } var yamls []*remote.FileMeta @@ -50,19 +50,19 @@ func Approve(ctx context.Context, store store.Store, build *model.Build, user *m yamls = append(yamls, &remote.FileMeta{Data: y.Data, Name: y.Name}) } - build, buildItems, err := createBuildItems(ctx, store, build, user, repo, yamls, nil) + pipeline, pipelineItems, err := createPipelineItems(ctx, store, pipeline, user, repo, yamls, nil) if err != nil { msg := fmt.Sprintf("failure to createBuildItems for %s", repo.FullName) log.Error().Err(err).Msg(msg) return nil, err } - build, err = start(ctx, store, build, user, repo, buildItems) + pipeline, err = start(ctx, store, pipeline, user, repo, pipelineItems) if err != nil { - msg := fmt.Sprintf("failure to start build for %s: %v", repo.FullName, err) + msg := fmt.Sprintf("failure to start pipeline for %s: %v", repo.FullName, err) log.Error().Err(err).Msg(msg) return nil, fmt.Errorf(msg) } - return build, nil + return pipeline, nil } diff --git a/server/pipeline/cancel.go b/server/pipeline/cancel.go index 262bc59a7..f494f0772 100644 --- a/server/pipeline/cancel.go +++ b/server/pipeline/cancel.go @@ -27,13 +27,13 @@ import ( "github.com/woodpecker-ci/woodpecker/server/store" ) -// Cancel the build and returns the status. -func Cancel(ctx context.Context, store store.Store, repo *model.Repo, build *model.Build) error { - if build.Status != model.StatusRunning && build.Status != model.StatusPending && build.Status != model.StatusBlocked { - return ErrBadRequest{Msg: "Cannot cancel a non-running or non-pending or non-blocked build"} +// Cancel the pipeline and returns the status. +func Cancel(ctx context.Context, store store.Store, repo *model.Repo, pipeline *model.Pipeline) error { + if pipeline.Status != model.StatusRunning && pipeline.Status != model.StatusPending && pipeline.Status != model.StatusBlocked { + return ErrBadRequest{Msg: "Cannot cancel a non-running or non-pending or non-blocked pipeline"} } - procs, err := store.ProcList(build) + procs, err := store.ProcList(pipeline) if err != nil { return ErrNotFound{Msg: err.Error()} } @@ -69,7 +69,7 @@ func Cancel(ctx context.Context, store store.Store, repo *model.Repo, build *mod } } - // Then update the DB status for pending builds + // Then update the DB status for pending pipelines // Running ones will be set when the agents stop on the cancel signal for _, proc := range procs { if proc.State == model.StatusPending { @@ -85,9 +85,9 @@ func Cancel(ctx context.Context, store store.Store, repo *model.Repo, build *mod } } - killedBuild, err := shared.UpdateToStatusKilled(store, *build) + killedBuild, err := shared.UpdateToStatusKilled(store, *pipeline) if err != nil { - log.Error().Err(err).Msgf("UpdateToStatusKilled: %v", build) + log.Error().Err(err).Msgf("UpdateToStatusKilled: %v", pipeline) return err } @@ -108,13 +108,13 @@ func Cancel(ctx context.Context, store store.Store, repo *model.Repo, build *mod func cancelPreviousPipelines( ctx context.Context, _store store.Store, - build *model.Build, + pipeline *model.Pipeline, repo *model.Repo, ) error { // check this event should cancel previous pipelines eventIncluded := false for _, ev := range repo.CancelPreviousPipelineEvents { - if ev == build.Event { + if ev == pipeline.Event { eventIncluded = true break } @@ -124,38 +124,38 @@ func cancelPreviousPipelines( } // get all active activeBuilds - activeBuilds, err := _store.GetActiveBuildList(repo, -1) + activeBuilds, err := _store.GetActivePipelineList(repo, -1) if err != nil { return err } - buildNeedsCancel := func(active *model.Build) (bool, error) { + pipelineNeedsCancel := func(active *model.Pipeline) (bool, error) { // always filter on same event - if active.Event != build.Event { + if active.Event != pipeline.Event { return false, nil } // find events for the same context - switch build.Event { + switch pipeline.Event { case model.EventPush: - return build.Branch == active.Branch, nil + return pipeline.Branch == active.Branch, nil default: - return build.Refspec == active.Refspec, nil + return pipeline.Refspec == active.Refspec, nil } } for _, active := range activeBuilds { - if active.ID == build.ID { - // same build. e.g. self + if active.ID == pipeline.ID { + // same pipeline. e.g. self continue } - cancel, err := buildNeedsCancel(active) + cancel, err := pipelineNeedsCancel(active) if err != nil { log.Error(). Err(err). Str("Ref", active.Ref). - Msg("Error while trying to cancel build, skipping") + Msg("Error while trying to cancel pipeline, skipping") continue } @@ -168,7 +168,7 @@ func cancelPreviousPipelines( Err(err). Str("Ref", active.Ref). Int64("ID", active.ID). - Msg("Failed to cancel build") + Msg("Failed to cancel pipeline") } } diff --git a/server/pipeline/config.go b/server/pipeline/config.go index b2d0bfc70..d555c8de7 100644 --- a/server/pipeline/config.go +++ b/server/pipeline/config.go @@ -24,12 +24,12 @@ import ( "github.com/woodpecker-ci/woodpecker/server/store" ) -func findOrPersistPipelineConfig(store store.Store, build *model.Build, remoteYamlConfig *remote.FileMeta) (*model.Config, error) { +func findOrPersistPipelineConfig(store store.Store, pipeline *model.Pipeline, remoteYamlConfig *remote.FileMeta) (*model.Config, error) { sha := fmt.Sprintf("%x", sha256.Sum256(remoteYamlConfig.Data)) - conf, err := store.ConfigFindIdentical(build.RepoID, sha) + conf, err := store.ConfigFindIdentical(pipeline.RepoID, sha) if err != nil { conf = &model.Config{ - RepoID: build.RepoID, + RepoID: pipeline.RepoID, Data: remoteYamlConfig.Data, Hash: sha, Name: shared.SanitizePath(remoteYamlConfig.Name), @@ -37,18 +37,18 @@ func findOrPersistPipelineConfig(store store.Store, build *model.Build, remoteYa err = store.ConfigCreate(conf) if err != nil { // retry in case we receive two hooks at the same time - conf, err = store.ConfigFindIdentical(build.RepoID, sha) + conf, err = store.ConfigFindIdentical(pipeline.RepoID, sha) if err != nil { return nil, err } } } - buildConfig := &model.BuildConfig{ - ConfigID: conf.ID, - BuildID: build.ID, + pipelineConfig := &model.PipelineConfig{ + ConfigID: conf.ID, + PipelineID: pipeline.ID, } - if err := store.BuildConfigCreate(buildConfig); err != nil { + if err := store.PipelineConfigCreate(pipelineConfig); err != nil { return nil, err } diff --git a/server/pipeline/create.go b/server/pipeline/create.go index 8cfee0994..a3b759e87 100644 --- a/server/pipeline/create.go +++ b/server/pipeline/create.go @@ -28,8 +28,8 @@ import ( "github.com/woodpecker-ci/woodpecker/server/store" ) -// Create a new build and start it -func Create(ctx context.Context, _store store.Store, repo *model.Repo, build *model.Build) (*model.Build, error) { +// Create a new pipeline and start it +func Create(ctx context.Context, _store store.Store, repo *model.Repo, pipeline *model.Pipeline) (*model.Pipeline, error) { repoUser, err := _store.GetUser(repo.UserID) if err != nil { msg := fmt.Sprintf("failure to find repo owner via id '%d'", repo.UserID) @@ -39,7 +39,7 @@ func Create(ctx context.Context, _store store.Store, repo *model.Repo, build *mo // if the remote has a refresh token, the current access token // may be stale. Therefore, we should refresh prior to dispatching - // the build. + // the pipeline. if refresher, ok := server.Config.Services.Remote.(remote.Refresher); ok { refreshed, err := refresher.Refresh(ctx, repoUser) if err != nil { @@ -59,11 +59,11 @@ func Create(ctx context.Context, _store store.Store, repo *model.Repo, build *mo parseErr error ) - // fetch the build file from the remote - configFetcher := shared.NewConfigFetcher(server.Config.Services.Remote, server.Config.Services.ConfigService, repoUser, repo, build) + // fetch the pipeline file from the remote + configFetcher := shared.NewConfigFetcher(server.Config.Services.Remote, server.Config.Services.ConfigService, repoUser, repo, pipeline) remoteYamlConfigs, configFetchErr = configFetcher.Fetch(ctx) if configFetchErr == nil { - filtered, parseErr = checkIfFiltered(build, remoteYamlConfigs) + filtered, parseErr = checkIfFiltered(pipeline, remoteYamlConfigs) if parseErr == nil { if filtered { err := ErrFiltered{Msg: "branch does not match restrictions defined in yaml"} @@ -71,7 +71,7 @@ func Create(ctx context.Context, _store store.Store, repo *model.Repo, build *mo return nil, err } - if zeroSteps(build, remoteYamlConfigs) { + if zeroSteps(pipeline, remoteYamlConfigs) { err := ErrFiltered{Msg: "step conditions yield zero runnable steps"} log.Debug().Str("repo", repo.FullName).Msgf("%v", err) return nil, err @@ -79,38 +79,38 @@ func Create(ctx context.Context, _store store.Store, repo *model.Repo, build *mo } } - // update some build fields - build.RepoID = repo.ID - build.Verified = true - build.Status = model.StatusPending + // update some pipeline fields + pipeline.RepoID = repo.ID + pipeline.Verified = true + pipeline.Status = model.StatusPending if configFetchErr != nil { - log.Debug().Str("repo", repo.FullName).Err(configFetchErr).Msgf("cannot find config '%s' in '%s' with user: '%s'", repo.Config, build.Ref, repoUser.Login) - build.Started = time.Now().Unix() - build.Finished = build.Started - build.Status = model.StatusError - build.Error = fmt.Sprintf("pipeline definition not found in %s", repo.FullName) + log.Debug().Str("repo", repo.FullName).Err(configFetchErr).Msgf("cannot find config '%s' in '%s' with user: '%s'", repo.Config, pipeline.Ref, repoUser.Login) + pipeline.Started = time.Now().Unix() + pipeline.Finished = pipeline.Started + pipeline.Status = model.StatusError + pipeline.Error = fmt.Sprintf("pipeline definition not found in %s", repo.FullName) } else if parseErr != nil { log.Debug().Str("repo", repo.FullName).Err(parseErr).Msg("failed to parse yaml") - build.Started = time.Now().Unix() - build.Finished = build.Started - build.Status = model.StatusError - build.Error = fmt.Sprintf("failed to parse pipeline: %s", parseErr.Error()) + pipeline.Started = time.Now().Unix() + pipeline.Finished = pipeline.Started + pipeline.Status = model.StatusError + pipeline.Error = fmt.Sprintf("failed to parse pipeline: %s", parseErr.Error()) } else if repo.IsGated { // TODO(336) extend gated feature with an allow/block List - build.Status = model.StatusBlocked + pipeline.Status = model.StatusBlocked } - err = _store.CreateBuild(build, build.Procs...) + err = _store.CreatePipeline(pipeline, pipeline.Procs...) if err != nil { - msg := fmt.Sprintf("failure to save build for %s", repo.FullName) + msg := fmt.Sprintf("failure to save pipeline for %s", repo.FullName) log.Error().Err(err).Msg(msg) return nil, fmt.Errorf(msg) } - // persist the build config for historical correctness, restarts, etc + // persist the pipeline config for historical correctness, restarts, etc for _, remoteYamlConfig := range remoteYamlConfigs { - _, err := findOrPersistPipelineConfig(_store, build, remoteYamlConfig) + _, err := findOrPersistPipelineConfig(_store, pipeline, remoteYamlConfig) if err != nil { msg := fmt.Sprintf("failure to find or persist pipeline config for %s", repo.FullName) log.Error().Err(err).Msg(msg) @@ -118,43 +118,43 @@ func Create(ctx context.Context, _store store.Store, repo *model.Repo, build *mo } } - if build.Status == model.StatusError { - if err := publishToTopic(ctx, build, repo); err != nil { + if pipeline.Status == model.StatusError { + if err := publishToTopic(ctx, pipeline, repo); err != nil { log.Error().Err(err).Msg("publishToTopic") } - if err := updateBuildStatus(ctx, build, repo, repoUser); err != nil { - log.Error().Err(err).Msg("updateBuildStatus") + if err := updatePipelineStatus(ctx, pipeline, repo, repoUser); err != nil { + log.Error().Err(err).Msg("updatePipelineStatus") } - return build, nil + return pipeline, nil } - build, buildItems, err := createBuildItems(ctx, _store, build, repoUser, repo, remoteYamlConfigs, nil) + pipeline, pipelineItems, err := createPipelineItems(ctx, _store, pipeline, repoUser, repo, remoteYamlConfigs, nil) if err != nil { - msg := fmt.Sprintf("failure to createBuildItems for %s", repo.FullName) + msg := fmt.Sprintf("failure to createPipelineItems for %s", repo.FullName) log.Error().Err(err).Msg(msg) return nil, fmt.Errorf(msg) } - if build.Status == model.StatusBlocked { - if err := publishToTopic(ctx, build, repo); err != nil { + if pipeline.Status == model.StatusBlocked { + if err := publishToTopic(ctx, pipeline, repo); err != nil { log.Error().Err(err).Msg("publishToTopic") } - if err := updateBuildStatus(ctx, build, repo, repoUser); err != nil { - log.Error().Err(err).Msg("updateBuildStatus") + if err := updatePipelineStatus(ctx, pipeline, repo, repoUser); err != nil { + log.Error().Err(err).Msg("updatePipelineStatus") } - return build, nil + return pipeline, nil } - build, err = start(ctx, _store, build, repoUser, repo, buildItems) + pipeline, err = start(ctx, _store, pipeline, repoUser, repo, pipelineItems) if err != nil { - msg := fmt.Sprintf("failure to start build for %s", repo.FullName) + msg := fmt.Sprintf("failure to start pipeline for %s", repo.FullName) log.Error().Err(err).Msg(msg) return nil, fmt.Errorf(msg) } - return build, nil + return pipeline, nil } diff --git a/server/pipeline/decline.go b/server/pipeline/decline.go index 3744daa33..3d6965f01 100644 --- a/server/pipeline/decline.go +++ b/server/pipeline/decline.go @@ -24,31 +24,31 @@ import ( "github.com/woodpecker-ci/woodpecker/server/store" ) -// Decline update the status to declined for blocked build because of a gated repo -func Decline(ctx context.Context, store store.Store, build *model.Build, user *model.User, repo *model.Repo) (*model.Build, error) { - if build.Status != model.StatusBlocked { - return nil, fmt.Errorf("cannot decline a build with status %s", build.Status) +// Decline update the status to declined for blocked pipeline because of a gated repo +func Decline(ctx context.Context, store store.Store, pipeline *model.Pipeline, user *model.User, repo *model.Repo) (*model.Pipeline, error) { + if pipeline.Status != model.StatusBlocked { + return nil, fmt.Errorf("cannot decline a pipeline with status %s", pipeline.Status) } - _, err := shared.UpdateToStatusDeclined(store, *build, user.Login) + _, err := shared.UpdateToStatusDeclined(store, *pipeline, user.Login) if err != nil { - return nil, fmt.Errorf("error updating build. %s", err) + return nil, fmt.Errorf("error updating pipeline. %s", err) } - if build.Procs, err = store.ProcList(build); err != nil { + if pipeline.Procs, err = store.ProcList(pipeline); err != nil { log.Error().Err(err).Msg("can not get proc list from store") } - if build.Procs, err = model.Tree(build.Procs); err != nil { + if pipeline.Procs, err = model.Tree(pipeline.Procs); err != nil { log.Error().Err(err).Msg("can not build tree from proc list") } - if err := updateBuildStatus(ctx, build, repo, user); err != nil { + if err := updatePipelineStatus(ctx, pipeline, repo, user); err != nil { log.Error().Err(err).Msg("updateBuildStatus") } - if err := publishToTopic(ctx, build, repo); err != nil { + if err := publishToTopic(ctx, pipeline, repo); err != nil { log.Error().Err(err).Msg("publishToTopic") } - return build, nil + return pipeline, nil } diff --git a/server/pipeline/filter.go b/server/pipeline/filter.go index 83afd123d..15144036e 100644 --- a/server/pipeline/filter.go +++ b/server/pipeline/filter.go @@ -26,11 +26,11 @@ import ( "github.com/woodpecker-ci/woodpecker/server/shared" ) -func zeroSteps(build *model.Build, remoteYamlConfigs []*remote.FileMeta) bool { +func zeroSteps(pipeline *model.Pipeline, remoteYamlConfigs []*remote.FileMeta) bool { b := shared.ProcBuilder{ Repo: &model.Repo{}, - Curr: build, - Last: &model.Build{}, + Curr: pipeline, + Last: &model.Pipeline{}, Netrc: &model.Netrc{}, Secs: []*model.Secret{}, Regs: []*model.Registry{}, @@ -38,11 +38,11 @@ func zeroSteps(build *model.Build, remoteYamlConfigs []*remote.FileMeta) bool { Yamls: remoteYamlConfigs, } - buildItems, err := b.Build() + pipelineItems, err := b.Build() if err != nil { return false } - if len(buildItems) == 0 { + if len(pipelineItems) == 0 { return true } @@ -51,14 +51,14 @@ func zeroSteps(build *model.Build, remoteYamlConfigs []*remote.FileMeta) bool { // TODO: parse yaml once and not for each filter function // Check if at least one pipeline step will be execute otherwise we will just ignore this webhook -func checkIfFiltered(build *model.Build, remoteYamlConfigs []*remote.FileMeta) (bool, error) { - log.Trace().Msgf("hook.branchFiltered(): build branch: '%s' build event: '%s' config count: %d", build.Branch, build.Event, len(remoteYamlConfigs)) +func checkIfFiltered(pipeline *model.Pipeline, remoteYamlConfigs []*remote.FileMeta) (bool, error) { + log.Trace().Msgf("hook.branchFiltered(): pipeline branch: '%s' pipeline event: '%s' config count: %d", pipeline.Branch, pipeline.Event, len(remoteYamlConfigs)) matchMetadata := frontend.Metadata{ - Curr: frontend.Build{ - Event: string(build.Event), + Curr: frontend.Pipeline{ + Event: string(pipeline.Event), Commit: frontend.Commit{ - Branch: build.Branch, + Branch: pipeline.Branch, }, }, } @@ -79,7 +79,7 @@ func checkIfFiltered(build *model.Build, remoteYamlConfigs []*remote.FileMeta) ( } // ignore if the pipeline was filtered by the branch (legacy) - if !parsedPipelineConfig.Branches.Match(build.Branch) { + if !parsedPipelineConfig.Branches.Match(pipeline.Branch) { continue } diff --git a/server/pipeline/helper.go b/server/pipeline/helper.go index 0dcf41d4d..b6e0b3c44 100644 --- a/server/pipeline/helper.go +++ b/server/pipeline/helper.go @@ -23,16 +23,16 @@ import ( "github.com/woodpecker-ci/woodpecker/server/model" ) -func updateBuildStatus(ctx context.Context, build *model.Build, repo *model.Repo, user *model.User) error { - for _, proc := range build.Procs { +func updatePipelineStatus(ctx context.Context, pipeline *model.Pipeline, repo *model.Repo, user *model.User) error { + for _, proc := range pipeline.Procs { // skip child procs if !proc.IsParent() { continue } - err := server.Config.Services.Remote.Status(ctx, user, repo, build, proc) + err := server.Config.Services.Remote.Status(ctx, user, repo, pipeline, proc) if err != nil { - log.Error().Err(err).Msgf("error setting commit status for %s/%d", repo.FullName, build.Number) + log.Error().Err(err).Msgf("error setting commit status for %s/%d", repo.FullName, pipeline.Number) return err } } diff --git a/server/pipeline/items.go b/server/pipeline/items.go index 308474273..2f689e060 100644 --- a/server/pipeline/items.go +++ b/server/pipeline/items.go @@ -28,26 +28,26 @@ import ( "github.com/woodpecker-ci/woodpecker/server/store" ) -func createBuildItems(ctx context.Context, store store.Store, build *model.Build, user *model.User, repo *model.Repo, yamls []*remote.FileMeta, envs map[string]string) (*model.Build, []*shared.BuildItem, error) { +func createPipelineItems(ctx context.Context, store store.Store, pipeline *model.Pipeline, user *model.User, repo *model.Repo, yamls []*remote.FileMeta, envs map[string]string) (*model.Pipeline, []*shared.PipelineItem, error) { netrc, err := server.Config.Services.Remote.Netrc(user, repo) if err != nil { log.Error().Err(err).Msg("Failed to generate netrc file") } - // get the previous build so that we can send status change notifications - last, err := store.GetBuildLastBefore(repo, build.Branch, build.ID) + // get the previous pipeline so that we can send status change notifications + last, err := store.GetPipelineLastBefore(repo, pipeline.Branch, pipeline.ID) if err != nil && !errors.Is(err, sql.ErrNoRows) { - log.Error().Err(err).Str("repo", repo.FullName).Msgf("Error getting last build before build number '%d'", build.Number) + log.Error().Err(err).Str("repo", repo.FullName).Msgf("Error getting last pipeline before pipeline number '%d'", pipeline.Number) } - secs, err := server.Config.Services.Secrets.SecretListBuild(repo, build) + secs, err := server.Config.Services.Secrets.SecretListPipeline(repo, pipeline) if err != nil { - log.Error().Err(err).Msgf("Error getting secrets for %s#%d", repo.FullName, build.Number) + log.Error().Err(err).Msgf("Error getting secrets for %s#%d", repo.FullName, pipeline.Number) } regs, err := server.Config.Services.Registries.RegistryList(repo) if err != nil { - log.Error().Err(err).Msgf("Error getting registry credentials for %s#%d", repo.FullName, build.Number) + log.Error().Err(err).Msgf("Error getting registry credentials for %s#%d", repo.FullName, pipeline.Number) } if envs == nil { @@ -60,13 +60,13 @@ func createBuildItems(ctx context.Context, store store.Store, build *model.Build } } - for k, v := range build.AdditionalVariables { + for k, v := range pipeline.AdditionalVariables { envs[k] = v } b := shared.ProcBuilder{ Repo: repo, - Curr: build, + Curr: pipeline, Last: last, Netrc: netrc, Secs: secs, @@ -75,16 +75,16 @@ func createBuildItems(ctx context.Context, store store.Store, build *model.Build Link: server.Config.Server.Host, Yamls: yamls, } - buildItems, err := b.Build() + pipelineItems, err := b.Build() if err != nil { - build, uerr := shared.UpdateToStatusError(store, *build, err) + pipeline, uerr := shared.UpdateToStatusError(store, *pipeline, err) if uerr != nil { - log.Error().Err(err).Msgf("Error setting error status of build for %s#%d", repo.FullName, build.Number) + log.Error().Err(err).Msgf("Error setting error status of pipeline for %s#%d", repo.FullName, pipeline.Number) } - return build, nil, err + return pipeline, nil, err } - build = shared.SetBuildStepsOnBuild(b.Curr, buildItems) + pipeline = shared.SetPipelineStepsOnPipeline(b.Curr, pipelineItems) - return build, buildItems, nil + return pipeline, pipelineItems, nil } diff --git a/server/pipeline/queue.go b/server/pipeline/queue.go index d8c0cf855..546f9bc0f 100644 --- a/server/pipeline/queue.go +++ b/server/pipeline/queue.go @@ -26,9 +26,9 @@ import ( "github.com/woodpecker-ci/woodpecker/server/shared" ) -func queueBuild(build *model.Build, repo *model.Repo, buildItems []*shared.BuildItem) error { +func queueBuild(pipeline *model.Pipeline, repo *model.Repo, pipelineItems []*shared.PipelineItem) error { var tasks []*queue.Task - for _, item := range buildItems { + for _, item := range pipelineItems { if item.Proc.State == model.StatusSkipped { continue } @@ -40,7 +40,7 @@ func queueBuild(build *model.Build, repo *model.Repo, buildItems []*shared.Build } task.Labels["platform"] = item.Platform task.Labels["repo"] = repo.FullName - task.Dependencies = taskIds(item.DependsOn, buildItems) + task.Dependencies = taskIds(item.DependsOn, pipelineItems) task.RunOn = item.RunsOn task.DepStatus = make(map[string]string) @@ -58,11 +58,11 @@ func queueBuild(build *model.Build, repo *model.Repo, buildItems []*shared.Build return server.Config.Services.Queue.PushAtOnce(context.Background(), tasks) } -func taskIds(dependsOn []string, buildItems []*shared.BuildItem) (taskIds []string) { +func taskIds(dependsOn []string, pipelineItems []*shared.PipelineItem) (taskIds []string) { for _, dep := range dependsOn { - for _, buildItem := range buildItems { - if buildItem.Proc.Name == dep { - taskIds = append(taskIds, fmt.Sprint(buildItem.Proc.ID)) + for _, pipelineItem := range pipelineItems { + if pipelineItem.Proc.Name == dep { + taskIds = append(taskIds, fmt.Sprint(pipelineItem.Proc.ID)) } } } diff --git a/server/pipeline/restart.go b/server/pipeline/restart.go index 85cede592..aaeee8916 100644 --- a/server/pipeline/restart.go +++ b/server/pipeline/restart.go @@ -30,20 +30,20 @@ import ( "github.com/woodpecker-ci/woodpecker/server/store" ) -// Restart a build by creating a new one out of the old and start it -func Restart(ctx context.Context, store store.Store, lastBuild *model.Build, user *model.User, repo *model.Repo, envs map[string]string) (*model.Build, error) { +// Restart a pipeline by creating a new one out of the old and start it +func Restart(ctx context.Context, store store.Store, lastBuild *model.Pipeline, user *model.User, repo *model.Repo, envs map[string]string) (*model.Pipeline, error) { switch lastBuild.Status { case model.StatusDeclined, model.StatusBlocked: - return nil, ErrBadRequest{Msg: fmt.Sprintf("cannot restart a build with status %s", lastBuild.Status)} + return nil, ErrBadRequest{Msg: fmt.Sprintf("cannot restart a pipeline with status %s", lastBuild.Status)} } var pipelineFiles []*remote.FileMeta // fetch the old pipeline config from database - configs, err := store.ConfigsForBuild(lastBuild.ID) + configs, err := store.ConfigsForPipeline(lastBuild.ID) if err != nil { - msg := fmt.Sprintf("failure to get build config for %s. %s", repo.FullName, err) + msg := fmt.Sprintf("failure to get pipeline config for %s. %s", repo.FullName, err) log.Error().Msgf(msg) return nil, ErrNotFound{Msg: msg} } @@ -62,7 +62,7 @@ func Restart(ctx context.Context, store store.Store, lastBuild *model.Build, use newConfig, useOld, err := server.Config.Services.ConfigService.FetchConfig(ctx, repo, lastBuild, currentFileMeta) if err != nil { return nil, ErrBadRequest{ - Msg: fmt.Sprintf("On fetching external build config: %s", err), + Msg: fmt.Sprintf("On fetching external pipeline config: %s", err), } } if !useOld { @@ -70,12 +70,12 @@ func Restart(ctx context.Context, store store.Store, lastBuild *model.Build, use } } - newBuild := createNewBuildOutOfOld(lastBuild) + newBuild := createNewOutOfOld(lastBuild) newBuild.Parent = lastBuild.ID - err = store.CreateBuild(newBuild) + err = store.CreatePipeline(newBuild) if err != nil { - msg := fmt.Sprintf("failure to save build for %s", repo.FullName) + msg := fmt.Sprintf("failure to save pipeline for %s", repo.FullName) log.Error().Err(err).Msg(msg) return nil, fmt.Errorf(msg) } @@ -87,13 +87,13 @@ func Restart(ctx context.Context, store store.Store, lastBuild *model.Build, use } return newBuild, nil } - if err := persistBuildConfigs(store, configs, newBuild.ID); err != nil { - msg := fmt.Sprintf("failure to persist build config for %s.", repo.FullName) + if err := persistPipelineConfigs(store, configs, newBuild.ID); err != nil { + msg := fmt.Sprintf("failure to persist pipeline config for %s.", repo.FullName) log.Error().Err(err).Msg(msg) return nil, fmt.Errorf(msg) } - newBuild, buildItems, err := createBuildItems(ctx, store, newBuild, user, repo, pipelineFiles, envs) + newBuild, pipelineItems, err := createPipelineItems(ctx, store, newBuild, user, repo, pipelineFiles, envs) if err != nil { if errors.Is(err, &yaml.PipelineParseError{}) { return newBuild, nil @@ -103,9 +103,9 @@ func Restart(ctx context.Context, store store.Store, lastBuild *model.Build, use return nil, fmt.Errorf(msg) } - newBuild, err = start(ctx, store, newBuild, user, repo, buildItems) + newBuild, err = start(ctx, store, newBuild, user, repo, pipelineItems) if err != nil { - msg := fmt.Sprintf("failure to start build for %s", repo.FullName) + msg := fmt.Sprintf("failure to start pipeline for %s", repo.FullName) log.Error().Err(err).Msg(msg) return nil, fmt.Errorf(msg) } @@ -114,13 +114,13 @@ func Restart(ctx context.Context, store store.Store, lastBuild *model.Build, use } // TODO: reuse at create.go too -func persistBuildConfigs(store store.Store, configs []*model.Config, buildID int64) error { +func persistPipelineConfigs(store store.Store, configs []*model.Config, pipelineID int64) error { for _, conf := range configs { - buildConfig := &model.BuildConfig{ - ConfigID: conf.ID, - BuildID: buildID, + pipelineConfig := &model.PipelineConfig{ + ConfigID: conf.ID, + PipelineID: pipelineID, } - err := store.BuildConfigCreate(buildConfig) + err := store.PipelineConfigCreate(pipelineConfig) if err != nil { return err } @@ -128,7 +128,7 @@ func persistBuildConfigs(store store.Store, configs []*model.Config, buildID int return nil } -func createNewBuildOutOfOld(old *model.Build) *model.Build { +func createNewOutOfOld(old *model.Pipeline) *model.Pipeline { new := *old new.ID = 0 new.Number = 0 diff --git a/server/pipeline/start.go b/server/pipeline/start.go index 9af2011bd..4d20acd27 100644 --- a/server/pipeline/start.go +++ b/server/pipeline/start.go @@ -24,31 +24,31 @@ import ( "github.com/woodpecker-ci/woodpecker/server/store" ) -// start a build, make sure it was stored persistent in the store before -func start(ctx context.Context, store store.Store, activeBuild *model.Build, user *model.User, repo *model.Repo, buildItems []*shared.BuildItem) (*model.Build, error) { - // call to cancel previous builds if needed - if err := cancelPreviousPipelines(ctx, store, activeBuild, repo); err != nil { +// start a pipeline, make sure it was stored persistent in the store before +func start(ctx context.Context, store store.Store, activePipeline *model.Pipeline, user *model.User, repo *model.Repo, pipelineItems []*shared.PipelineItem) (*model.Pipeline, error) { + // call to cancel previous pipelines if needed + if err := cancelPreviousPipelines(ctx, store, activePipeline, repo); err != nil { // should be not breaking - log.Error().Err(err).Msg("Failed to cancel previous builds") + log.Error().Err(err).Msg("Failed to cancel previous pipelines") } - if err := store.ProcCreate(activeBuild.Procs); err != nil { - log.Error().Err(err).Str("repo", repo.FullName).Msgf("error persisting procs for %s#%d", repo.FullName, activeBuild.Number) + if err := store.ProcCreate(activePipeline.Procs); err != nil { + log.Error().Err(err).Str("repo", repo.FullName).Msgf("error persisting procs for %s#%d", repo.FullName, activePipeline.Number) return nil, err } - if err := publishToTopic(ctx, activeBuild, repo); err != nil { + if err := publishToTopic(ctx, activePipeline, repo); err != nil { log.Error().Err(err).Msg("publishToTopic") } - if err := queueBuild(activeBuild, repo, buildItems); err != nil { + if err := queueBuild(activePipeline, repo, pipelineItems); err != nil { log.Error().Err(err).Msg("queueBuild") return nil, err } - if err := updateBuildStatus(ctx, activeBuild, repo, user); err != nil { + if err := updatePipelineStatus(ctx, activePipeline, repo, user); err != nil { log.Error().Err(err).Msg("updateBuildStatus") } - return activeBuild, nil + return activePipeline, nil } diff --git a/server/pipeline/topic.go b/server/pipeline/topic.go index 006752609..7930bc715 100644 --- a/server/pipeline/topic.go +++ b/server/pipeline/topic.go @@ -25,21 +25,21 @@ import ( ) // publishToTopic publishes message to UI clients -func publishToTopic(c context.Context, build *model.Build, repo *model.Repo) (err error) { +func publishToTopic(c context.Context, pipeline *model.Pipeline, repo *model.Repo) (err error) { message := pubsub.Message{ Labels: map[string]string{ "repo": repo.FullName, "private": strconv.FormatBool(repo.IsSCMPrivate), }, } - buildCopy := *build - if buildCopy.Procs, err = model.Tree(buildCopy.Procs); err != nil { + pipelineCopy := *pipeline + if pipelineCopy.Procs, err = model.Tree(pipelineCopy.Procs); err != nil { return err } message.Data, _ = json.Marshal(model.Event{ - Repo: *repo, - Build: buildCopy, + Repo: *repo, + Pipeline: pipelineCopy, }) return server.Config.Services.Pubsub.Publish(c, "topic/events", message) } diff --git a/server/plugins/config/extension.go b/server/plugins/config/extension.go index c01322885..d63551254 100644 --- a/server/plugins/config/extension.go +++ b/server/plugins/config/extension.go @@ -1,3 +1,17 @@ +// Copyright 2022 Woodpecker Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package config import ( @@ -9,5 +23,5 @@ import ( type Extension interface { IsConfigured() bool - FetchConfig(ctx context.Context, repo *model.Repo, build *model.Build, currentFileMeta []*remote.FileMeta) (configData []*remote.FileMeta, useOld bool, err error) + FetchConfig(ctx context.Context, repo *model.Repo, pipeline *model.Pipeline, currentFileMeta []*remote.FileMeta) (configData []*remote.FileMeta, useOld bool, err error) } diff --git a/server/plugins/config/http.go b/server/plugins/config/http.go index d831e2ffc..535a11400 100644 --- a/server/plugins/config/http.go +++ b/server/plugins/config/http.go @@ -1,3 +1,17 @@ +// Copyright 2022 Woodpecker Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package config import ( @@ -22,9 +36,9 @@ type config struct { } type requestStructure struct { - Repo *model.Repo `json:"repo"` - Build *model.Build `json:"build"` - Configuration []*config `json:"configs"` + Repo *model.Repo `json:"repo"` + Pipeline *model.Pipeline `json:"build"` + Configuration []*config `json:"configs"` } type responseStructure struct { @@ -39,14 +53,14 @@ func (cp *http) IsConfigured() bool { return cp.endpoint != "" } -func (cp *http) FetchConfig(ctx context.Context, repo *model.Repo, build *model.Build, currentFileMeta []*remote.FileMeta) (configData []*remote.FileMeta, useOld bool, err error) { +func (cp *http) FetchConfig(ctx context.Context, repo *model.Repo, pipeline *model.Pipeline, currentFileMeta []*remote.FileMeta) (configData []*remote.FileMeta, useOld bool, err error) { currentConfigs := make([]*config, len(currentFileMeta)) for i, pipe := range currentFileMeta { currentConfigs[i] = &config{Name: pipe.Name, Data: string(pipe.Data)} } response := new(responseStructure) - body := requestStructure{Repo: repo, Build: build, Configuration: currentConfigs} + body := requestStructure{Repo: repo, Pipeline: pipeline, Configuration: currentConfigs} status, err := utils.Send(ctx, "POST", cp.endpoint, cp.privateKey, body, response) if err != nil && status != 204 { return nil, false, fmt.Errorf("Failed to fetch config via http (%d) %w", status, err) diff --git a/server/plugins/secrets/builtin.go b/server/plugins/secrets/builtin.go index 67ae8476e..19ec80d1a 100644 --- a/server/plugins/secrets/builtin.go +++ b/server/plugins/secrets/builtin.go @@ -1,3 +1,17 @@ +// Copyright 2022 Woodpecker Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package secrets import ( @@ -24,7 +38,7 @@ func (b *builtin) SecretList(repo *model.Repo) ([]*model.Secret, error) { return b.store.SecretList(repo, false) } -func (b *builtin) SecretListBuild(repo *model.Repo, build *model.Build) ([]*model.Secret, error) { +func (b *builtin) SecretListPipeline(repo *model.Repo, pipeline *model.Pipeline) ([]*model.Secret, error) { s, err := b.store.SecretList(repo, true) if err != nil { return nil, err diff --git a/server/queue/fifo.go b/server/queue/fifo.go index f8d2a036c..8b0e9a35e 100644 --- a/server/queue/fifo.go +++ b/server/queue/fifo.go @@ -1,3 +1,17 @@ +// Copyright 2022 Woodpecker Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package queue import ( @@ -241,7 +255,7 @@ func (q *fifo) process() { } }() - q.resubmitExpiredBuilds() + q.resubmitExpiredPipelines() q.filterWaiting() for pending, worker := q.assignToWorker(); pending != nil && worker != nil; pending, worker = q.assignToWorker() { task := pending.Value.(*Task) @@ -303,7 +317,7 @@ func (q *fifo) assignToWorker() (*list.Element, *worker) { return nil, nil } -func (q *fifo) resubmitExpiredBuilds() { +func (q *fifo) resubmitExpiredPipelines() { for id, state := range q.running { if time.Now().After(state.deadline) { q.pending.PushFront(state.item) diff --git a/server/remote/bitbucket/bitbucket.go b/server/remote/bitbucket/bitbucket.go index a41cb64c7..d155273ff 100644 --- a/server/remote/bitbucket/bitbucket.go +++ b/server/remote/bitbucket/bitbucket.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -213,27 +214,27 @@ func (c *config) Perm(ctx context.Context, u *model.User, r *model.Repo) (*model } // File fetches the file from the Bitbucket repository and returns its contents. -func (c *config) File(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, f string) ([]byte, error) { - config, err := c.newClient(ctx, u).FindSource(r.Owner, r.Name, b.Commit, f) +func (c *config) File(ctx context.Context, u *model.User, r *model.Repo, p *model.Pipeline, f string) ([]byte, error) { + config, err := c.newClient(ctx, u).FindSource(r.Owner, r.Name, p.Commit, f) if err != nil { return nil, err } return []byte(*config), err } -func (c *config) Dir(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, f string) ([]*remote.FileMeta, error) { +func (c *config) Dir(ctx context.Context, u *model.User, r *model.Repo, p *model.Pipeline, f string) ([]*remote.FileMeta, error) { return nil, fmt.Errorf("Not implemented") } -// Status creates a build status for the Bitbucket commit. -func (c *config) Status(ctx context.Context, user *model.User, repo *model.Repo, build *model.Build, proc *model.Proc) error { - status := internal.BuildStatus{ - State: convertStatus(build.Status), - Desc: common.GetBuildStatusDescription(build.Status), +// Status creates a pipeline status for the Bitbucket commit. +func (c *config) Status(ctx context.Context, user *model.User, repo *model.Repo, pipeline *model.Pipeline, proc *model.Proc) error { + status := internal.PipelineStatus{ + State: convertStatus(pipeline.Status), + Desc: common.GetPipelineStatusDescription(pipeline.Status), Key: "Woodpecker", - URL: common.GetBuildStatusLink(repo, build, nil), + URL: common.GetPipelineStatusLink(repo, pipeline, nil), } - return c.newClient(ctx, user).CreateStatus(repo.Owner, repo.Name, build.Commit, &status) + return c.newClient(ctx, user).CreateStatus(repo.Owner, repo.Name, pipeline.Commit, &status) } // Activate activates the repository by registering repository push hooks with @@ -301,8 +302,8 @@ func (c *config) BranchHead(ctx context.Context, u *model.User, r *model.Repo, b } // Hook parses the incoming Bitbucket hook and returns the Repository and -// Build details. If the hook is unsupported nil values are returned. -func (c *config) Hook(ctx context.Context, req *http.Request) (*model.Repo, *model.Build, error) { +// Pipeline details. If the hook is unsupported nil values are returned. +func (c *config) Hook(ctx context.Context, req *http.Request) (*model.Repo, *model.Pipeline, error) { return parseHook(req) } diff --git a/server/remote/bitbucket/bitbucket_test.go b/server/remote/bitbucket/bitbucket_test.go index b73a6c5d5..f2b99fbdf 100644 --- a/server/remote/bitbucket/bitbucket_test.go +++ b/server/remote/bitbucket/bitbucket_test.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -195,12 +196,12 @@ func Test_bitbucket(t *testing.T) { g.Describe("When downloading a file", func() { g.It("Should return the bytes", func() { - raw, err := c.File(ctx, fakeUser, fakeRepo, fakeBuild, "file") + raw, err := c.File(ctx, fakeUser, fakeRepo, fakePipeline, "file") g.Assert(err).IsNil() g.Assert(len(raw) != 0).IsTrue() }) g.It("Should handle not found error", func() { - _, err := c.File(ctx, fakeUser, fakeRepo, fakeBuild, "file_not_found") + _, err := c.File(ctx, fakeUser, fakeRepo, fakePipeline, "file_not_found") g.Assert(err).IsNotNil() }) }) @@ -254,7 +255,7 @@ func Test_bitbucket(t *testing.T) { }) g.It("Should update the status", func() { - err := c.Status(ctx, fakeUser, fakeRepo, fakeBuild, fakeProc) + err := c.Status(ctx, fakeUser, fakeRepo, fakePipeline, fakeProc) g.Assert(err).IsNil() }) @@ -350,7 +351,7 @@ var ( FullName: "test_name/permission_admin", } - fakeBuild = &model.Build{ + fakePipeline = &model.Pipeline{ Commit: "9ecad50", } diff --git a/server/remote/bitbucket/convert.go b/server/remote/bitbucket/convert.go index 620819f78..552150bec 100644 --- a/server/remote/bitbucket/convert.go +++ b/server/remote/bitbucket/convert.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -129,9 +130,9 @@ func convertWorkspace(from *internal.Workspace) *model.Team { } // convertPullHook is a helper function used to convert a Bitbucket pull request -// hook to the Woodpecker build struct holding commit information. -func convertPullHook(from *internal.PullRequestHook) *model.Build { - return &model.Build{ +// hook to the Woodpecker pipeline struct holding commit information. +func convertPullHook(from *internal.PullRequestHook) *model.Pipeline { + return &model.Pipeline{ Event: model.EventPull, Commit: from.PullRequest.Dest.Commit.Hash, Ref: fmt.Sprintf("refs/heads/%s", from.PullRequest.Dest.Branch.Name), @@ -151,9 +152,9 @@ func convertPullHook(from *internal.PullRequestHook) *model.Build { } // convertPushHook is a helper function used to convert a Bitbucket push -// hook to the Woodpecker build struct holding commit information. -func convertPushHook(hook *internal.PushHook, change *internal.Change) *model.Build { - build := &model.Build{ +// hook to the Woodpecker pipeline struct holding commit information. +func convertPushHook(hook *internal.PushHook, change *internal.Change) *model.Pipeline { + pipeline := &model.Pipeline{ Commit: change.New.Target.Hash, Link: change.New.Target.Links.HTML.Href, Branch: change.New.Name, @@ -165,16 +166,16 @@ func convertPushHook(hook *internal.PushHook, change *internal.Change) *model.Bu } switch change.New.Type { case "tag", "annotated_tag", "bookmark": - build.Event = model.EventTag - build.Ref = fmt.Sprintf("refs/tags/%s", change.New.Name) + pipeline.Event = model.EventTag + pipeline.Ref = fmt.Sprintf("refs/tags/%s", change.New.Name) default: - build.Event = model.EventPush - build.Ref = fmt.Sprintf("refs/heads/%s", change.New.Name) + pipeline.Event = model.EventPush + pipeline.Ref = fmt.Sprintf("refs/heads/%s", change.New.Name) } if len(change.New.Target.Author.Raw) != 0 { - build.Email = extractEmail(change.New.Target.Author.Raw) + pipeline.Email = extractEmail(change.New.Target.Author.Raw) } - return build + return pipeline } // regex for git author fields ("name ") diff --git a/server/remote/bitbucket/convert_test.go b/server/remote/bitbucket/convert_test.go index e8104716a..381d82dc2 100644 --- a/server/remote/bitbucket/convert_test.go +++ b/server/remote/bitbucket/convert_test.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -114,7 +115,7 @@ func Test_helper(t *testing.T) { g.Assert(link).Equal("https://bitbucket.org/foo/bar.git") }) - g.It("should convert pull hook to build", func() { + g.It("should convert pull hook to pipeline", func() { hook := &internal.PullRequestHook{} hook.Actor.Login = "octocat" hook.Actor.Links.Avatar.Href = "https://..." @@ -127,21 +128,21 @@ func Test_helper(t *testing.T) { hook.PullRequest.Desc = "updated README" hook.PullRequest.Updated = time.Now() - build := convertPullHook(hook) - g.Assert(build.Event).Equal(model.EventPull) - g.Assert(build.Author).Equal(hook.Actor.Login) - g.Assert(build.Avatar).Equal(hook.Actor.Links.Avatar.Href) - g.Assert(build.Commit).Equal(hook.PullRequest.Dest.Commit.Hash) - g.Assert(build.Branch).Equal(hook.PullRequest.Dest.Branch.Name) - g.Assert(build.Link).Equal(hook.PullRequest.Links.HTML.Href) - g.Assert(build.Ref).Equal("refs/heads/master") - g.Assert(build.Refspec).Equal("change:master") - g.Assert(build.Remote).Equal("https://bitbucket.org/baz/bar") - g.Assert(build.Message).Equal(hook.PullRequest.Desc) - g.Assert(build.Timestamp).Equal(hook.PullRequest.Updated.Unix()) + pipeline := convertPullHook(hook) + g.Assert(pipeline.Event).Equal(model.EventPull) + g.Assert(pipeline.Author).Equal(hook.Actor.Login) + g.Assert(pipeline.Avatar).Equal(hook.Actor.Links.Avatar.Href) + g.Assert(pipeline.Commit).Equal(hook.PullRequest.Dest.Commit.Hash) + g.Assert(pipeline.Branch).Equal(hook.PullRequest.Dest.Branch.Name) + g.Assert(pipeline.Link).Equal(hook.PullRequest.Links.HTML.Href) + g.Assert(pipeline.Ref).Equal("refs/heads/master") + g.Assert(pipeline.Refspec).Equal("change:master") + g.Assert(pipeline.Remote).Equal("https://bitbucket.org/baz/bar") + g.Assert(pipeline.Message).Equal(hook.PullRequest.Desc) + g.Assert(pipeline.Timestamp).Equal(hook.PullRequest.Updated.Unix()) }) - g.It("should convert push hook to build", func() { + g.It("should convert push hook to pipeline", func() { change := internal.Change{} change.New.Target.Hash = "73f9c44d" change.New.Name = "master" @@ -154,29 +155,29 @@ func Test_helper(t *testing.T) { hook.Actor.Login = "octocat" hook.Actor.Links.Avatar.Href = "https://..." - build := convertPushHook(&hook, &change) - g.Assert(build.Event).Equal(model.EventPush) - g.Assert(build.Email).Equal("test@domain.tld") - g.Assert(build.Author).Equal(hook.Actor.Login) - g.Assert(build.Avatar).Equal(hook.Actor.Links.Avatar.Href) - g.Assert(build.Commit).Equal(change.New.Target.Hash) - g.Assert(build.Branch).Equal(change.New.Name) - g.Assert(build.Link).Equal(change.New.Target.Links.HTML.Href) - g.Assert(build.Ref).Equal("refs/heads/master") - g.Assert(build.Message).Equal(change.New.Target.Message) - g.Assert(build.Timestamp).Equal(change.New.Target.Date.Unix()) + pipeline := convertPushHook(&hook, &change) + g.Assert(pipeline.Event).Equal(model.EventPush) + g.Assert(pipeline.Email).Equal("test@domain.tld") + g.Assert(pipeline.Author).Equal(hook.Actor.Login) + g.Assert(pipeline.Avatar).Equal(hook.Actor.Links.Avatar.Href) + g.Assert(pipeline.Commit).Equal(change.New.Target.Hash) + g.Assert(pipeline.Branch).Equal(change.New.Name) + g.Assert(pipeline.Link).Equal(change.New.Target.Links.HTML.Href) + g.Assert(pipeline.Ref).Equal("refs/heads/master") + g.Assert(pipeline.Message).Equal(change.New.Target.Message) + g.Assert(pipeline.Timestamp).Equal(change.New.Target.Date.Unix()) }) - g.It("should convert tag hook to build", func() { + g.It("should convert tag hook to pipeline", func() { change := internal.Change{} change.New.Name = "v1.0.0" change.New.Type = "tag" hook := internal.PushHook{} - build := convertPushHook(&hook, &change) - g.Assert(build.Event).Equal(model.EventTag) - g.Assert(build.Ref).Equal("refs/tags/v1.0.0") + pipeline := convertPushHook(&hook, &change) + g.Assert(pipeline.Event).Equal(model.EventTag) + g.Assert(pipeline.Ref).Equal("refs/tags/v1.0.0") }) }) } diff --git a/server/remote/bitbucket/internal/client.go b/server/remote/bitbucket/internal/client.go index 8b051b51b..05df7ce9d 100644 --- a/server/remote/bitbucket/internal/client.go +++ b/server/remote/bitbucket/internal/client.go @@ -155,7 +155,7 @@ func (c *Client) FindSource(owner, name, revision, path string) (*string, error) return c.do(uri, get, nil, nil) } -func (c *Client) CreateStatus(owner, name, revision string, status *BuildStatus) error { +func (c *Client) CreateStatus(owner, name, revision string, status *PipelineStatus) error { uri := fmt.Sprintf(pathStatus, c.base, owner, name, revision) _, err := c.do(uri, post, status, nil) return err diff --git a/server/remote/bitbucket/internal/types.go b/server/remote/bitbucket/internal/types.go index 4139f8790..1b3ba5b39 100644 --- a/server/remote/bitbucket/internal/types.go +++ b/server/remote/bitbucket/internal/types.go @@ -43,7 +43,7 @@ type WorkspacesResp struct { Values []*Workspace `json:"values"` } -type BuildStatus struct { +type PipelineStatus struct { State string `json:"state"` Key string `json:"key"` Name string `json:"name,omitempty"` diff --git a/server/remote/bitbucket/parse.go b/server/remote/bitbucket/parse.go index 8d6e07601..499733a52 100644 --- a/server/remote/bitbucket/parse.go +++ b/server/remote/bitbucket/parse.go @@ -32,8 +32,8 @@ const ( ) // parseHook parses a Bitbucket hook from an http.Request request and returns -// Repo and Build detail. If a hook type is unsupported nil values are returned. -func parseHook(r *http.Request) (*model.Repo, *model.Build, error) { +// Repo and Pipeline detail. If a hook type is unsupported nil values are returned. +func parseHook(r *http.Request) (*model.Repo, *model.Pipeline, error) { payload, _ := io.ReadAll(r.Body) switch r.Header.Get(hookEvent) { @@ -45,9 +45,9 @@ func parseHook(r *http.Request) (*model.Repo, *model.Build, error) { return nil, nil, nil } -// parsePushHook parses a push hook and returns the Repo and Build details. +// parsePushHook parses a push hook and returns the Repo and Pipeline details. // If the commit type is unsupported nil values are returned. -func parsePushHook(payload []byte) (*model.Repo, *model.Build, error) { +func parsePushHook(payload []byte) (*model.Repo, *model.Pipeline, error) { hook := internal.PushHook{} err := json.Unmarshal(payload, &hook) @@ -64,9 +64,9 @@ func parsePushHook(payload []byte) (*model.Repo, *model.Build, error) { return nil, nil, nil } -// parsePullHook parses a pull request hook and returns the Repo and Build +// parsePullHook parses a pull request hook and returns the Repo and Pipeline // details. If the pull request is closed nil values are returned. -func parsePullHook(payload []byte) (*model.Repo, *model.Build, error) { +func parsePullHook(payload []byte) (*model.Repo, *model.Pipeline, error) { hook := internal.PullRequestHook{} if err := json.Unmarshal(payload, &hook); err != nil { diff --git a/server/remote/bitbucketserver/bitbucketserver.go b/server/remote/bitbucketserver/bitbucketserver.go index 7df224c08..2ff408c39 100644 --- a/server/remote/bitbucketserver/bitbucketserver.go +++ b/server/remote/bitbucketserver/bitbucketserver.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -178,29 +179,29 @@ func (c *Config) Perm(ctx context.Context, u *model.User, repo *model.Repo) (*mo return client.FindRepoPerms(repo.Owner, repo.Name) } -func (c *Config) File(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, f string) ([]byte, error) { +func (c *Config) File(ctx context.Context, u *model.User, r *model.Repo, p *model.Pipeline, f string) ([]byte, error) { client := internal.NewClientWithToken(ctx, c.URL, c.Consumer, u.Token) - return client.FindFileForRepo(r.Owner, r.Name, f, b.Ref) + return client.FindFileForRepo(r.Owner, r.Name, f, p.Ref) } -func (c *Config) Dir(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, f string) ([]*remote.FileMeta, error) { +func (c *Config) Dir(ctx context.Context, u *model.User, r *model.Repo, p *model.Pipeline, f string) ([]*remote.FileMeta, error) { return nil, fmt.Errorf("Not implemented") } // Status is not supported by the bitbucketserver driver. -func (c *Config) Status(ctx context.Context, user *model.User, repo *model.Repo, build *model.Build, proc *model.Proc) error { - status := internal.BuildStatus{ - State: convertStatus(build.Status), - Desc: common.GetBuildStatusDescription(build.Status), - Name: fmt.Sprintf("Woodpecker #%d - %s", build.Number, build.Branch), +func (c *Config) Status(ctx context.Context, user *model.User, repo *model.Repo, pipeline *model.Pipeline, proc *model.Proc) error { + status := internal.PipelineStatus{ + State: convertStatus(pipeline.Status), + Desc: common.GetPipelineStatusDescription(pipeline.Status), + Name: fmt.Sprintf("Woodpecker #%d - %s", pipeline.Number, pipeline.Branch), Key: "Woodpecker", - URL: common.GetBuildStatusLink(repo, build, nil), + URL: common.GetPipelineStatusLink(repo, pipeline, nil), } client := internal.NewClientWithToken(ctx, c.URL, c.Consumer, user.Token) - return client.CreateStatus(build.Commit, &status) + return client.CreateStatus(pipeline.Commit, &status) } func (c *Config) Netrc(user *model.User, r *model.Repo) (*model.Netrc, error) { @@ -247,7 +248,7 @@ func (c *Config) Deactivate(ctx context.Context, u *model.User, r *model.Repo, l return client.DeleteHook(r.Owner, r.Name, link) } -func (c *Config) Hook(ctx context.Context, r *http.Request) (*model.Repo, *model.Build, error) { +func (c *Config) Hook(ctx context.Context, r *http.Request) (*model.Repo, *model.Pipeline, error) { return parseHook(r, c.URL) } diff --git a/server/remote/bitbucketserver/convert.go b/server/remote/bitbucketserver/convert.go index 4978f196c..f2841f136 100644 --- a/server/remote/bitbucketserver/convert.go +++ b/server/remote/bitbucketserver/convert.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -79,8 +80,8 @@ func convertRepo(from *internal.Repo) *model.Repo { } // convertPushHook is a helper function used to convert a Bitbucket push -// hook to the Woodpecker build struct holding commit information. -func convertPushHook(hook *internal.PostHook, baseURL string) *model.Build { +// hook to the Woodpecker pipeline struct holding commit information. +func convertPushHook(hook *internal.PostHook, baseURL string) *model.Pipeline { branch := strings.TrimPrefix( strings.TrimPrefix( hook.RefChanges[0].RefID, @@ -95,7 +96,7 @@ func convertPushHook(hook *internal.PostHook, baseURL string) *model.Build { authorLabel = authorLabel[0:37] + "..." } - build := &model.Build{ + pipeline := &model.Pipeline{ Commit: hook.RefChanges[0].ToHash, // TODO check for index value Branch: branch, Message: hook.Changesets.Values[0].ToCommit.Message, // TODO check for index Values @@ -107,12 +108,12 @@ func convertPushHook(hook *internal.PostHook, baseURL string) *model.Build { Link: fmt.Sprintf("%s/projects/%s/repos/%s/commits/%s", baseURL, hook.Repository.Project.Key, hook.Repository.Slug, hook.RefChanges[0].ToHash), } if strings.HasPrefix(hook.RefChanges[0].RefID, "refs/tags/") { - build.Event = model.EventTag + pipeline.Event = model.EventTag } else { - build.Event = model.EventPush + pipeline.Event = model.EventPush } - return build + return pipeline } // convertUser is a helper function used to convert a Bitbucket user account diff --git a/server/remote/bitbucketserver/convert_test.go b/server/remote/bitbucketserver/convert_test.go index ffad3dde6..23601503d 100644 --- a/server/remote/bitbucketserver/convert_test.go +++ b/server/remote/bitbucketserver/convert_test.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -90,11 +91,11 @@ func Test_helper(t *testing.T) { Key: "octocat", } change.Repository.Slug = "hello-world" - build := convertPushHook(&change, "http://base.com") - g.Assert(build.Branch).Equal("") + pipeline := convertPushHook(&change, "http://base.com") + g.Assert(pipeline.Branch).Equal("") }) - g.It("should convert push hook to build", func() { + g.It("should convert push hook to pipeline", func() { change := internal.PostHook{} change.RefChanges = append(change.RefChanges, internal.RefChange{ @@ -112,19 +113,19 @@ func Test_helper(t *testing.T) { change.Repository.Project.Key = "octocat" change.Repository.Slug = "hello-world" - build := convertPushHook(&change, "http://base.com") - g.Assert(build.Event).Equal(model.EventPush) + pipeline := convertPushHook(&change, "http://base.com") + g.Assert(pipeline.Event).Equal(model.EventPush) // Ensuring the author label is not longer then 40 - g.Assert(build.Author).Equal("John Doe, Appleboy, Mary, Janet E. Da...") - g.Assert(build.Avatar).Equal(avatarLink("huh@huh.com")) - g.Assert(build.Commit).Equal("73f9c44d") - g.Assert(build.Branch).Equal("release/some-feature") - g.Assert(build.Link).Equal("http://base.com/projects/octocat/repos/hello-world/commits/73f9c44d") - g.Assert(build.Ref).Equal("refs/heads/release/some-feature") - g.Assert(build.Message).Equal("message") + g.Assert(pipeline.Author).Equal("John Doe, Appleboy, Mary, Janet E. Da...") + g.Assert(pipeline.Avatar).Equal(avatarLink("huh@huh.com")) + g.Assert(pipeline.Commit).Equal("73f9c44d") + g.Assert(pipeline.Branch).Equal("release/some-feature") + g.Assert(pipeline.Link).Equal("http://base.com/projects/octocat/repos/hello-world/commits/73f9c44d") + g.Assert(pipeline.Ref).Equal("refs/heads/release/some-feature") + g.Assert(pipeline.Message).Equal("message") }) - g.It("should convert tag hook to build", func() { + g.It("should convert tag hook to pipeline", func() { change := internal.PostHook{} change.RefChanges = append(change.RefChanges, internal.RefChange{ RefID: "refs/tags/v1", @@ -140,15 +141,15 @@ func Test_helper(t *testing.T) { change.Repository.Project.Key = "octocat" change.Repository.Slug = "hello-world" - build := convertPushHook(&change, "http://base.com") - g.Assert(build.Event).Equal(model.EventTag) - g.Assert(build.Author).Equal("John Doe") - g.Assert(build.Avatar).Equal(avatarLink("huh@huh.com")) - g.Assert(build.Commit).Equal("73f9c44d") - g.Assert(build.Branch).Equal("v1") - g.Assert(build.Link).Equal("http://base.com/projects/octocat/repos/hello-world/commits/73f9c44d") - g.Assert(build.Ref).Equal("refs/tags/v1") - g.Assert(build.Message).Equal("message") + pipeline := convertPushHook(&change, "http://base.com") + g.Assert(pipeline.Event).Equal(model.EventTag) + g.Assert(pipeline.Author).Equal("John Doe") + g.Assert(pipeline.Avatar).Equal(avatarLink("huh@huh.com")) + g.Assert(pipeline.Commit).Equal("73f9c44d") + g.Assert(pipeline.Branch).Equal("v1") + g.Assert(pipeline.Link).Equal("http://base.com/projects/octocat/repos/hello-world/commits/73f9c44d") + g.Assert(pipeline.Ref).Equal("refs/tags/v1") + g.Assert(pipeline.Message).Equal("message") }) }) } diff --git a/server/remote/bitbucketserver/internal/client.go b/server/remote/bitbucketserver/internal/client.go index 57c0efcda..256ac4bb9 100644 --- a/server/remote/bitbucketserver/internal/client.go +++ b/server/remote/bitbucketserver/internal/client.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -193,7 +194,7 @@ func (c *Client) CreateHook(owner, name, callBackLink string) error { return c.doPut(fmt.Sprintf(pathHookEnabled, c.base, owner, name, hookName), hookBytes) } -func (c *Client) CreateStatus(revision string, status *BuildStatus) error { +func (c *Client) CreateStatus(revision string, status *PipelineStatus) error { uri := fmt.Sprintf(pathStatus, c.base, revision) return c.doPost(uri, status) } @@ -274,7 +275,7 @@ func (c *Client) doPut(url string, body []byte) error { } // Helper function to help create the hook -func (c *Client) doPost(url string, status *BuildStatus) error { +func (c *Client) doPost(url string, status *PipelineStatus) error { // write it to the body of the request. var buf io.ReadWriter if status != nil { diff --git a/server/remote/bitbucketserver/internal/types.go b/server/remote/bitbucketserver/internal/types.go index 1c86e886a..d516c1065 100644 --- a/server/remote/bitbucketserver/internal/types.go +++ b/server/remote/bitbucketserver/internal/types.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -38,7 +39,7 @@ type SelfRefLink struct { Href string `json:"href"` } -type BuildStatus struct { +type PipelineStatus struct { State string `json:"state"` Key string `json:"key"` Name string `json:"name,omitempty"` diff --git a/server/remote/bitbucketserver/parse.go b/server/remote/bitbucketserver/parse.go index 8cb7f9390..bc87ce138 100644 --- a/server/remote/bitbucketserver/parse.go +++ b/server/remote/bitbucketserver/parse.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,14 +24,14 @@ import ( ) // parseHook parses a Bitbucket hook from an http.Request request and returns -// Repo and Build detail. TODO: find a way to support PR hooks -func parseHook(r *http.Request, baseURL string) (*model.Repo, *model.Build, error) { +// Repo and Pipeline detail. TODO: find a way to support PR hooks +func parseHook(r *http.Request, baseURL string) (*model.Repo, *model.Pipeline, error) { hook := new(internal.PostHook) if err := json.NewDecoder(r.Body).Decode(hook); err != nil { return nil, nil, err } - build := convertPushHook(hook, baseURL) + pipeline := convertPushHook(hook, baseURL) repo := convertRepo(&hook.Repository) - return repo, build, nil + return repo, pipeline, nil } diff --git a/server/remote/coding/coding.go b/server/remote/coding/coding.go index 86e79eac4..c74bb4340 100644 --- a/server/remote/coding/coding.go +++ b/server/remote/coding/coding.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -235,7 +236,7 @@ func (c *Coding) Perm(ctx context.Context, u *model.User, repo *model.Repo) (*mo // File fetches a file from the remote repository and returns in string // format. -func (c *Coding) File(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, f string) ([]byte, error) { +func (c *Coding) File(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, f string) ([]byte, error) { data, err := c.newClient(ctx, u).GetFile(r.Owner, r.Name, b.Commit, f) if err != nil { return nil, err @@ -243,12 +244,12 @@ func (c *Coding) File(ctx context.Context, u *model.User, r *model.Repo, b *mode return data, nil } -func (c *Coding) Dir(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, f string) ([]*remote.FileMeta, error) { +func (c *Coding) Dir(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, f string) ([]*remote.FileMeta, error) { return nil, fmt.Errorf("Not implemented") } // Status sends the commit status to the remote system. -func (c *Coding) Status(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, proc *model.Proc) error { +func (c *Coding) Status(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, proc *model.Proc) error { // EMPTY: not implemented in Coding OAuth API return nil } @@ -301,12 +302,12 @@ func (c *Coding) BranchHead(ctx context.Context, u *model.User, r *model.Repo, b // Hook parses the post-commit hook from the Request body and returns the // required data in a standard format. -func (c *Coding) Hook(ctx context.Context, r *http.Request) (*model.Repo, *model.Build, error) { - repo, build, err := parseHook(r) - if build != nil { - build.Avatar = c.resourceLink(build.Avatar) +func (c *Coding) Hook(ctx context.Context, r *http.Request) (*model.Repo, *model.Pipeline, error) { + repo, pipeline, err := parseHook(r) + if pipeline != nil { + pipeline.Avatar = c.resourceLink(pipeline.Avatar) } - return repo, build, err + return repo, pipeline, err } // OrgMembership returns if user is member of organization and if user diff --git a/server/remote/coding/coding_test.go b/server/remote/coding/coding_test.go index da27d9f18..1d18d74f0 100644 --- a/server/remote/coding/coding_test.go +++ b/server/remote/coding/coding_test.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -160,8 +161,8 @@ func Test_coding(t *testing.T) { }) g.Describe("When downloading a file", func() { - g.It("Should return file for specified build", func() { - data, err := c.File(ctx, fakeUser, fakeRepo, fakeBuild, ".woodpecker.yml") + g.It("Should return file for specified pipeline", func() { + data, err := c.File(ctx, fakeUser, fakeRepo, fakePipeline, ".woodpecker.yml") g.Assert(err).IsNil() g.Assert(string(data)).Equal("pipeline:\n test:\n image: golang:1.6\n commands:\n - go test\n") }) @@ -266,7 +267,7 @@ var ( Name: "not_found_project", } - fakeBuild = &model.Build{ + fakePipeline = &model.Pipeline{ Commit: "4504a072cc", } ) diff --git a/server/remote/coding/hook.go b/server/remote/coding/hook.go index fb84566f7..31196b0e5 100644 --- a/server/remote/coding/hook.go +++ b/server/remote/coding/hook.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -93,7 +94,7 @@ type MergeRequestHook struct { MergeRequest *MergeRequest `json:"merge_request"` } -func parseHook(r *http.Request) (*model.Repo, *model.Build, error) { +func parseHook(r *http.Request) (*model.Repo, *model.Pipeline, error) { raw, err := io.ReadAll(r.Body) defer r.Body.Close() if err != nil { @@ -147,14 +148,14 @@ func convertRepository(repo *Repository) (*model.Repo, error) { }, nil } -func parsePushHook(raw []byte) (*model.Repo, *model.Build, error) { +func parsePushHook(raw []byte) (*model.Repo, *model.Pipeline, error) { hook := &PushHook{} err := json.Unmarshal(raw, hook) if err != nil { return nil, nil, err } - // no build triggered when removing ref + // no pipeline triggered when removing ref if hook.After == "0000000000000000000000000000000000000000" { return nil, nil, nil } @@ -165,7 +166,7 @@ func parsePushHook(raw []byte) (*model.Repo, *model.Build, error) { } lastCommit := findLastCommit(hook.Commits, hook.After) - build := &model.Build{ + pipeline := &model.Pipeline{ Event: model.EventPush, Commit: hook.After, Ref: hook.Ref, @@ -177,10 +178,10 @@ func parsePushHook(raw []byte) (*model.Repo, *model.Build, error) { Author: hook.User.GlobalKey, Remote: hook.Repository.HTTPSURL, } - return repo, build, nil + return repo, pipeline, nil } -func parsePullRequestHook(raw []byte) (*model.Repo, *model.Build, error) { +func parsePullRequestHook(raw []byte) (*model.Repo, *model.Pipeline, error) { hook := &PullRequestHook{} err := json.Unmarshal(raw, hook) if err != nil { @@ -195,7 +196,7 @@ func parsePullRequestHook(raw []byte) (*model.Repo, *model.Build, error) { if err != nil { return nil, nil, err } - build := &model.Build{ + pipeline := &model.Pipeline{ Event: model.EventPull, Commit: hook.PullRequest.CommitSHA, Link: hook.PullRequest.WebURL, @@ -209,10 +210,10 @@ func parsePullRequestHook(raw []byte) (*model.Repo, *model.Build, error) { Refspec: fmt.Sprintf("%s:%s", hook.PullRequest.SourceBranch, hook.PullRequest.TargetBranch), } - return repo, build, nil + return repo, pipeline, nil } -func parseMergeReuqestHook(raw []byte) (*model.Repo, *model.Build, error) { +func parseMergeReuqestHook(raw []byte) (*model.Repo, *model.Pipeline, error) { hook := &MergeRequestHook{} err := json.Unmarshal(raw, hook) if err != nil { @@ -228,7 +229,7 @@ func parseMergeReuqestHook(raw []byte) (*model.Repo, *model.Build, error) { return nil, nil, err } - build := &model.Build{ + pipeline := &model.Pipeline{ Event: model.EventPull, Commit: hook.MergeRequest.CommitSHA, Link: hook.MergeRequest.WebURL, @@ -241,5 +242,5 @@ func parseMergeReuqestHook(raw []byte) (*model.Repo, *model.Build, error) { Remote: hook.Repository.HTTPSURL, Refspec: fmt.Sprintf("%s:%s", hook.MergeRequest.SourceBranch, hook.MergeRequest.TargetBranch), } - return repo, build, nil + return repo, pipeline, nil } diff --git a/server/remote/coding/hook_test.go b/server/remote/coding/hook_test.go index cfe86e2fe..adb859e8a 100644 --- a/server/remote/coding/hook_test.go +++ b/server/remote/coding/hook_test.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -47,7 +48,7 @@ func Test_hook(t *testing.T) { SCMKind: model.RepoGit, } - build := &model.Build{ + pipeline := &model.Pipeline{ Event: model.EventPush, Commit: "5b9912a6ff272e9c93a4c44c278fe9b359ed1ab4", Ref: "refs/heads/master", @@ -60,10 +61,10 @@ func Test_hook(t *testing.T) { Remote: "https://git.coding.net/demo1/test1.git", } - actualRepo, actualBuild, err := parseHook(r) + actualRepo, actualPipeline, err := parseHook(r) g.Assert(err).IsNil() g.Assert(actualRepo).Equal(repo) - g.Assert(actualBuild).Equal(build) + g.Assert(actualPipeline).Equal(pipeline) }) g.It("Should find last commit", func() { @@ -115,7 +116,7 @@ func Test_hook(t *testing.T) { SCMKind: model.RepoGit, } - build := &model.Build{ + pipeline := &model.Pipeline{ Event: model.EventPush, Commit: "5b9912a6ff272e9c93a4c44c278fe9b359ed1ab4", Ref: "refs/heads/master", @@ -128,17 +129,17 @@ func Test_hook(t *testing.T) { Remote: "https://git.coding.net/demo1/test1.git", } - actualRepo, actualBuild, err := parsePushHook([]byte(fixtures.PushHook)) + actualRepo, actualPipeline, err := parsePushHook([]byte(fixtures.PushHook)) g.Assert(err).IsNil() g.Assert(actualRepo).Equal(repo) - g.Assert(actualBuild).Equal(build) + g.Assert(actualPipeline).Equal(pipeline) }) g.It("Should parse delete branch push hook", func() { - actualRepo, actualBuild, err := parsePushHook([]byte(fixtures.DeleteBranchPushHook)) + actualRepo, actualPipeline, err := parsePushHook([]byte(fixtures.DeleteBranchPushHook)) g.Assert(err).IsNil() g.Assert(actualRepo).IsNil() - g.Assert(actualBuild).IsNil() + g.Assert(actualPipeline).IsNil() }) g.It("Should parse pull request hook", func() { @@ -151,7 +152,7 @@ func Test_hook(t *testing.T) { SCMKind: model.RepoGit, } - build := &model.Build{ + pipeline := &model.Pipeline{ Event: model.EventPull, Commit: "55e77b328b71d3ee4f9e70a5f67231b0acceeadc", Link: "https://coding.net/u/demo1/p/test2/git/pull/1", @@ -165,10 +166,10 @@ func Test_hook(t *testing.T) { Refspec: "master:master", } - actualRepo, actualBuild, err := parsePullRequestHook([]byte(fixtures.PullRequestHook)) + actualRepo, actualPipeline, err := parsePullRequestHook([]byte(fixtures.PullRequestHook)) g.Assert(err).IsNil() g.Assert(actualRepo).Equal(repo) - g.Assert(actualBuild).Equal(build) + g.Assert(actualPipeline).Equal(pipeline) }) g.It("Should parse merge request hook", func() { @@ -181,7 +182,7 @@ func Test_hook(t *testing.T) { SCMKind: model.RepoGit, } - build := &model.Build{ + pipeline := &model.Pipeline{ Event: model.EventPull, Commit: "74e6755580c34e9fd81dbcfcbd43ee5f30259436", Link: "https://coding.net/u/demo1/p/test1/git/merge/1", @@ -195,10 +196,10 @@ func Test_hook(t *testing.T) { Refspec: "branch1:master", } - actualRepo, actualBuild, err := parseMergeReuqestHook([]byte(fixtures.MergeRequestHook)) + actualRepo, actualPipeline, err := parseMergeReuqestHook([]byte(fixtures.MergeRequestHook)) g.Assert(err).IsNil() g.Assert(actualRepo).Equal(repo) - g.Assert(actualBuild).Equal(build) + g.Assert(actualPipeline).Equal(pipeline) }) }) } diff --git a/server/remote/coding/util.go b/server/remote/coding/util.go index abe8b4e3d..b388e9664 100644 --- a/server/remote/coding/util.go +++ b/server/remote/coding/util.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/server/remote/coding/util_test.go b/server/remote/coding/util_test.go index ae3ac410e..b1443fe65 100644 --- a/server/remote/coding/util_test.go +++ b/server/remote/coding/util_test.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/server/remote/common/status.go b/server/remote/common/status.go index 0e725ed11..ba41081b3 100644 --- a/server/remote/common/status.go +++ b/server/remote/common/status.go @@ -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 common import ( @@ -9,9 +23,9 @@ import ( "github.com/woodpecker-ci/woodpecker/server/model" ) -func GetBuildStatusContext(repo *model.Repo, build *model.Build, proc *model.Proc) string { - event := string(build.Event) - switch build.Event { +func GetPipelineStatusContext(repo *model.Repo, pipeline *model.Pipeline, proc *model.Proc) string { + event := string(pipeline.Event) + switch pipeline.Event { case model.EventPull: event = "pr" } @@ -35,9 +49,9 @@ func GetBuildStatusContext(repo *model.Repo, build *model.Build, proc *model.Pro return ctx.String() } -// GetBuildStatusDescription is a helper function that generates a description -// message for the current build status. -func GetBuildStatusDescription(status model.StatusValue) string { +// GetPipelineStatusDescription is a helper function that generates a description +// message for the current pipeline status. +func GetPipelineStatusDescription(status model.StatusValue) string { switch status { case model.StatusPending: return "Pipeline is pending" @@ -58,10 +72,10 @@ func GetBuildStatusDescription(status model.StatusValue) string { } } -func GetBuildStatusLink(repo *model.Repo, build *model.Build, proc *model.Proc) string { +func GetPipelineStatusLink(repo *model.Repo, pipeline *model.Pipeline, proc *model.Proc) string { if proc == nil { - return fmt.Sprintf("%s/%s/build/%d", server.Config.Server.Host, repo.FullName, build.Number) + return fmt.Sprintf("%s/%s/pipeline/%d", server.Config.Server.Host, repo.FullName, pipeline.Number) } - return fmt.Sprintf("%s/%s/build/%d/%d", server.Config.Server.Host, repo.FullName, build.Number, proc.PID) + return fmt.Sprintf("%s/%s/pipeline/%d/%d", server.Config.Server.Host, repo.FullName, pipeline.Number, proc.PID) } diff --git a/server/remote/common/status_test.go b/server/remote/common/status_test.go index c25c2168a..31588ca4f 100644 --- a/server/remote/common/status_test.go +++ b/server/remote/common/status_test.go @@ -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 common import ( @@ -9,7 +23,7 @@ import ( "github.com/woodpecker-ci/woodpecker/server/model" ) -func TestGetBuildStatusContext(t *testing.T) { +func TestGetPipelineStatusContext(t *testing.T) { origFormat := server.Config.Server.StatusContextFormat origCtx := server.Config.Server.StatusContext defer func() { @@ -18,18 +32,18 @@ func TestGetBuildStatusContext(t *testing.T) { }() repo := &model.Repo{Owner: "user1", Name: "repo1"} - build := &model.Build{Event: model.EventPull} + pipeline := &model.Pipeline{Event: model.EventPull} proc := &model.Proc{Name: "lint"} - assert.EqualValues(t, "", GetBuildStatusContext(repo, build, proc)) + assert.EqualValues(t, "", GetPipelineStatusContext(repo, pipeline, proc)) server.Config.Server.StatusContext = "ci/woodpecker" server.Config.Server.StatusContextFormat = "{{ .context }}/{{ .event }}/{{ .pipeline }}" - assert.EqualValues(t, "ci/woodpecker/pr/lint", GetBuildStatusContext(repo, build, proc)) - build.Event = model.EventPush - assert.EqualValues(t, "ci/woodpecker/push/lint", GetBuildStatusContext(repo, build, proc)) + assert.EqualValues(t, "ci/woodpecker/pr/lint", GetPipelineStatusContext(repo, pipeline, proc)) + pipeline.Event = model.EventPush + assert.EqualValues(t, "ci/woodpecker/push/lint", GetPipelineStatusContext(repo, pipeline, proc)) server.Config.Server.StatusContext = "ci" server.Config.Server.StatusContextFormat = "{{ .context }}:{{ .owner }}/{{ .repo }}:{{ .event }}:{{ .pipeline }}" - assert.EqualValues(t, "ci:user1/repo1:push:lint", GetBuildStatusContext(repo, build, proc)) + assert.EqualValues(t, "ci:user1/repo1:push:lint", GetPipelineStatusContext(repo, pipeline, proc)) } diff --git a/server/remote/common/utils.go b/server/remote/common/utils.go index 730c7c0cc..4249db9b7 100644 --- a/server/remote/common/utils.go +++ b/server/remote/common/utils.go @@ -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 common import ( diff --git a/server/remote/common/utils_test.go b/server/remote/common/utils_test.go index 81121b379..d8f085f97 100644 --- a/server/remote/common/utils_test.go +++ b/server/remote/common/utils_test.go @@ -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 common_test import ( diff --git a/server/remote/gitea/gitea.go b/server/remote/gitea/gitea.go index 196d0526f..a13517fce 100644 --- a/server/remote/gitea/gitea.go +++ b/server/remote/gitea/gitea.go @@ -1,5 +1,6 @@ -// Copyright 2018 Drone.IO Inc. +// Copyright 2022 Woodpecker Authors // Copyright 2021 Informatyka Boguslawski sp. z o.o. sp.k., http://www.ib.pl/ +// Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -280,7 +281,7 @@ func (c *Gitea) Perm(ctx context.Context, u *model.User, r *model.Repo) (*model. } // File fetches the file from the Gitea repository and returns its contents. -func (c *Gitea) File(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, f string) ([]byte, error) { +func (c *Gitea) File(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, f string) ([]byte, error) { client, err := c.newClientToken(ctx, u.Token) if err != nil { return nil, err @@ -290,7 +291,7 @@ func (c *Gitea) File(ctx context.Context, u *model.User, r *model.Repo, b *model return cfg, err } -func (c *Gitea) Dir(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, f string) ([]*remote.FileMeta, error) { +func (c *Gitea) Dir(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, f string) ([]*remote.FileMeta, error) { var configs []*remote.FileMeta client, err := c.newClientToken(ctx, u.Token) @@ -325,7 +326,7 @@ func (c *Gitea) Dir(ctx context.Context, u *model.User, r *model.Repo, b *model. } // Status is supported by the Gitea driver. -func (c *Gitea) Status(ctx context.Context, user *model.User, repo *model.Repo, build *model.Build, proc *model.Proc) error { +func (c *Gitea) Status(ctx context.Context, user *model.User, repo *model.Repo, pipeline *model.Pipeline, proc *model.Proc) error { client, err := c.newClientToken(ctx, user.Token) if err != nil { return err @@ -334,12 +335,12 @@ func (c *Gitea) Status(ctx context.Context, user *model.User, repo *model.Repo, _, _, err = client.CreateStatus( repo.Owner, repo.Name, - build.Commit, + pipeline.Commit, gitea.CreateStatusOption{ State: getStatus(proc.State), - TargetURL: common.GetBuildStatusLink(repo, build, proc), - Description: common.GetBuildStatusDescription(proc.State), - Context: common.GetBuildStatusContext(repo, build, proc), + TargetURL: common.GetPipelineStatusLink(repo, pipeline, proc), + Description: common.GetPipelineStatusDescription(proc.State), + Context: common.GetPipelineStatusContext(repo, pipeline, proc), }, ) return err @@ -471,9 +472,9 @@ func (c *Gitea) BranchHead(ctx context.Context, u *model.User, r *model.Repo, br return b.Commit.ID, nil } -// Hook parses the incoming Gitea hook and returns the Repository and Build +// Hook parses the incoming Gitea hook and returns the Repository and Pipeline // details. If the hook is unsupported nil values are returned. -func (c *Gitea) Hook(ctx context.Context, r *http.Request) (*model.Repo, *model.Build, error) { +func (c *Gitea) Hook(ctx context.Context, r *http.Request) (*model.Repo, *model.Pipeline, error) { return parseHook(r) } diff --git a/server/remote/gitea/gitea_test.go b/server/remote/gitea/gitea_test.go index aa57cb6af..6e8bd3561 100644 --- a/server/remote/gitea/gitea_test.go +++ b/server/remote/gitea/gitea_test.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -131,13 +132,13 @@ func Test_gitea(t *testing.T) { }) g.It("Should return a repository file", func() { - raw, err := c.File(ctx, fakeUser, fakeRepo, fakeBuild, ".woodpecker.yml") + raw, err := c.File(ctx, fakeUser, fakeRepo, fakePipeline, ".woodpecker.yml") g.Assert(err).IsNil() g.Assert(string(raw)).Equal("{ platform: linux/amd64 }") }) - g.It("Should return nil from send build status", func() { - err := c.Status(ctx, fakeUser, fakeRepo, fakeBuild, fakeProc) + g.It("Should return nil from send pipeline status", func() { + err := c.Status(ctx, fakeUser, fakeRepo, fakePipeline, fakeProc) g.Assert(err).IsNil() }) @@ -181,7 +182,7 @@ var ( FullName: "test_name/repo_not_found", } - fakeBuild = &model.Build{ + fakePipeline = &model.Pipeline{ Commit: "9ecad50", } diff --git a/server/remote/gitea/helper.go b/server/remote/gitea/helper.go index 90622ea74..76fdc4356 100644 --- a/server/remote/gitea/helper.go +++ b/server/remote/gitea/helper.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -66,8 +67,8 @@ func toTeam(from *gitea.Organization, link string) *model.Team { } } -// helper function that extracts the Build data from a Gitea push hook -func buildFromPush(hook *pushHook) *model.Build { +// helper function that extracts the Pipeline data from a Gitea push hook +func pipelineFromPush(hook *pushHook) *model.Pipeline { avatar := expandAvatar( hook.Repo.HTMLURL, fixMalformedAvatar(hook.Sender.AvatarURL), @@ -85,7 +86,7 @@ func buildFromPush(hook *pushHook) *model.Build { link = hook.Commits[0].URL } - return &model.Build{ + return &model.Pipeline{ Event: model.EventPush, Commit: hook.After, Ref: hook.Ref, @@ -117,14 +118,14 @@ func getChangedFilesFromPushHook(hook *pushHook) []string { return utils.DedupStrings(files) } -// helper function that extracts the Build data from a Gitea tag hook -func buildFromTag(hook *pushHook) *model.Build { +// helper function that extracts the Pipeline data from a Gitea tag hook +func pipelineFromTag(hook *pushHook) *model.Pipeline { avatar := expandAvatar( hook.Repo.HTMLURL, fixMalformedAvatar(hook.Sender.AvatarURL), ) - return &model.Build{ + return &model.Pipeline{ Event: model.EventTag, Commit: hook.Sha, Ref: fmt.Sprintf("refs/tags/%s", hook.Ref), @@ -138,13 +139,13 @@ func buildFromTag(hook *pushHook) *model.Build { } } -// helper function that extracts the Build data from a Gitea pull_request hook -func buildFromPullRequest(hook *pullRequestHook) *model.Build { +// helper function that extracts the Pipeline data from a Gitea pull_request hook +func pipelineFromPullRequest(hook *pullRequestHook) *model.Pipeline { avatar := expandAvatar( hook.Repo.HTMLURL, fixMalformedAvatar(hook.PullRequest.Poster.AvatarURL), ) - build := &model.Build{ + pipeline := &model.Pipeline{ Event: model.EventPull, Commit: hook.PullRequest.Head.Sha, Link: hook.PullRequest.URL, @@ -160,7 +161,7 @@ func buildFromPullRequest(hook *pullRequestHook) *model.Build { hook.PullRequest.Base.Ref, ), } - return build + return pipeline } // helper function that parses a push hook from a read closer. diff --git a/server/remote/gitea/helper_test.go b/server/remote/gitea/helper_test.go index 949f4b080..fdc23ed7b 100644 --- a/server/remote/gitea/helper_test.go +++ b/server/remote/gitea/helper_test.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -91,19 +92,19 @@ func Test_parse(t *testing.T) { g.Assert(hook.PullRequest.Head.Ref).Equal("feature/changes") }) - g.It("Should return a Build struct from a push hook", func() { + g.It("Should return a Pipeline struct from a push hook", func() { buf := bytes.NewBufferString(fixtures.HookPush) hook, _ := parsePush(buf) - build := buildFromPush(hook) - g.Assert(build.Event).Equal(model.EventPush) - g.Assert(build.Commit).Equal(hook.After) - g.Assert(build.Ref).Equal(hook.Ref) - g.Assert(build.Link).Equal(hook.Commits[0].URL) - g.Assert(build.Branch).Equal("master") - g.Assert(build.Message).Equal(hook.Commits[0].Message) - g.Assert(build.Avatar).Equal("http://1.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87") - g.Assert(build.Author).Equal(hook.Sender.UserName) - g.Assert(utils.EqualStringSlice(build.ChangedFiles, []string{"CHANGELOG.md", "app/controller/application.rb"})).IsTrue() + pipeline := pipelineFromPush(hook) + g.Assert(pipeline.Event).Equal(model.EventPush) + g.Assert(pipeline.Commit).Equal(hook.After) + g.Assert(pipeline.Ref).Equal(hook.Ref) + g.Assert(pipeline.Link).Equal(hook.Commits[0].URL) + g.Assert(pipeline.Branch).Equal("master") + g.Assert(pipeline.Message).Equal(hook.Commits[0].Message) + g.Assert(pipeline.Avatar).Equal("http://1.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87") + g.Assert(pipeline.Author).Equal(hook.Sender.UserName) + g.Assert(utils.EqualStringSlice(pipeline.ChangedFiles, []string{"CHANGELOG.md", "app/controller/application.rb"})).IsTrue() }) g.It("Should return a Repo struct from a push hook", func() { @@ -116,31 +117,31 @@ func Test_parse(t *testing.T) { g.Assert(repo.Link).Equal(hook.Repo.HTMLURL) }) - g.It("Should return a Build struct from a tag hook", func() { + g.It("Should return a Pipeline struct from a tag hook", func() { buf := bytes.NewBufferString(fixtures.HookPushTag) hook, _ := parsePush(buf) - build := buildFromTag(hook) - g.Assert(build.Event).Equal(model.EventTag) - g.Assert(build.Commit).Equal(hook.Sha) - g.Assert(build.Ref).Equal("refs/tags/v1.0.0") - g.Assert(build.Branch).Equal("refs/tags/v1.0.0") - g.Assert(build.Link).Equal("http://gitea.golang.org/gordon/hello-world/src/tag/v1.0.0") - g.Assert(build.Message).Equal("created tag v1.0.0") + pipeline := pipelineFromTag(hook) + g.Assert(pipeline.Event).Equal(model.EventTag) + g.Assert(pipeline.Commit).Equal(hook.Sha) + g.Assert(pipeline.Ref).Equal("refs/tags/v1.0.0") + g.Assert(pipeline.Branch).Equal("refs/tags/v1.0.0") + g.Assert(pipeline.Link).Equal("http://gitea.golang.org/gordon/hello-world/src/tag/v1.0.0") + g.Assert(pipeline.Message).Equal("created tag v1.0.0") }) - g.It("Should return a Build struct from a pull_request hook", func() { + g.It("Should return a Pipeline struct from a pull_request hook", func() { buf := bytes.NewBufferString(fixtures.HookPullRequest) hook, _ := parsePullRequest(buf) - build := buildFromPullRequest(hook) - g.Assert(build.Event).Equal(model.EventPull) - g.Assert(build.Commit).Equal(hook.PullRequest.Head.Sha) - g.Assert(build.Ref).Equal("refs/pull/1/head") - g.Assert(build.Link).Equal(hook.PullRequest.URL) - g.Assert(build.Branch).Equal("master") - g.Assert(build.Refspec).Equal("feature/changes:master") - g.Assert(build.Message).Equal(hook.PullRequest.Title) - g.Assert(build.Avatar).Equal("http://1.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87") - g.Assert(build.Author).Equal(hook.PullRequest.Poster.UserName) + pipeline := pipelineFromPullRequest(hook) + g.Assert(pipeline.Event).Equal(model.EventPull) + g.Assert(pipeline.Commit).Equal(hook.PullRequest.Head.Sha) + g.Assert(pipeline.Ref).Equal("refs/pull/1/head") + g.Assert(pipeline.Link).Equal(hook.PullRequest.URL) + g.Assert(pipeline.Branch).Equal("master") + g.Assert(pipeline.Refspec).Equal("feature/changes:master") + g.Assert(pipeline.Message).Equal(hook.PullRequest.Title) + g.Assert(pipeline.Avatar).Equal("http://1.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87") + g.Assert(pipeline.Author).Equal(hook.PullRequest.Poster.UserName) }) g.It("Should return a Repo struct from a pull_request hook", func() { diff --git a/server/remote/gitea/parse.go b/server/remote/gitea/parse.go index e107c93d6..65599d729 100644 --- a/server/remote/gitea/parse.go +++ b/server/remote/gitea/parse.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -38,8 +39,8 @@ const ( ) // parseHook parses a Gitea hook from an http.Request request and returns -// Repo and Build detail. If a hook type is unsupported nil values are returned. -func parseHook(r *http.Request) (*model.Repo, *model.Build, error) { +// Repo and Pipeline detail. If a hook type is unsupported nil values are returned. +func parseHook(r *http.Request) (*model.Repo, *model.Pipeline, error) { switch r.Header.Get(hookEvent) { case hookPush: return parsePushHook(r.Body) @@ -51,9 +52,9 @@ func parseHook(r *http.Request) (*model.Repo, *model.Build, error) { return nil, nil, nil } -// parsePushHook parses a push hook and returns the Repo and Build details. +// parsePushHook parses a push hook and returns the Repo and Pipeline details. // If the commit type is unsupported nil values are returned. -func parsePushHook(payload io.Reader) (repo *model.Repo, build *model.Build, err error) { +func parsePushHook(payload io.Reader) (repo *model.Repo, pipeline *model.Pipeline, err error) { push, err := parsePush(payload) if err != nil { return nil, nil, err @@ -70,13 +71,13 @@ func parsePushHook(payload io.Reader) (repo *model.Repo, build *model.Build, err } repo = toRepo(push.Repo) - build = buildFromPush(push) - return repo, build, err + pipeline = pipelineFromPush(push) + return repo, pipeline, err } -// parseCreatedHook parses a push hook and returns the Repo and Build details. +// parseCreatedHook parses a push hook and returns the Repo and Pipeline details. // If the commit type is unsupported nil values are returned. -func parseCreatedHook(payload io.Reader) (repo *model.Repo, build *model.Build, err error) { +func parseCreatedHook(payload io.Reader) (repo *model.Repo, pipeline *model.Pipeline, err error) { push, err := parsePush(payload) if err != nil { return nil, nil, err @@ -87,15 +88,15 @@ func parseCreatedHook(payload io.Reader) (repo *model.Repo, build *model.Build, } repo = toRepo(push.Repo) - build = buildFromTag(push) - return repo, build, nil + pipeline = pipelineFromTag(push) + return repo, pipeline, nil } -// parsePullRequestHook parses a pull_request hook and returns the Repo and Build details. -func parsePullRequestHook(payload io.Reader) (*model.Repo, *model.Build, error) { +// parsePullRequestHook parses a pull_request hook and returns the Repo and Pipeline details. +func parsePullRequestHook(payload io.Reader) (*model.Repo, *model.Pipeline, error) { var ( - repo *model.Repo - build *model.Build + repo *model.Repo + pipeline *model.Pipeline ) pr, err := parsePullRequest(payload) @@ -103,7 +104,7 @@ func parsePullRequestHook(payload io.Reader) (*model.Repo, *model.Build, error) return nil, nil, err } - // Don't trigger builds for non-code changes, or if PR is not open + // Don't trigger pipelines for non-code changes, or if PR is not open if pr.Action != actionOpen && pr.Action != actionSync { return nil, nil, nil } @@ -112,6 +113,6 @@ func parsePullRequestHook(payload io.Reader) (*model.Repo, *model.Build, error) } repo = toRepo(pr.Repo) - build = buildFromPullRequest(pr) - return repo, build, err + pipeline = pipelineFromPullRequest(pr) + return repo, pipeline, err } diff --git a/server/remote/gitea/parse_test.go b/server/remote/gitea/parse_test.go index 1f6b83578..fc8403f44 100644 --- a/server/remote/gitea/parse_test.go +++ b/server/remote/gitea/parse_test.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -40,7 +41,7 @@ func Test_parser(t *testing.T) { g.Assert(err).IsNil() }) g.Describe("given a push hook", func() { - g.It("should extract repository and build details", func() { + g.It("should extract repository and pipeline details", func() { buf := bytes.NewBufferString(fixtures.HookPush) req, _ := http.NewRequest("POST", "/hook", buf) req.Header = http.Header{} @@ -54,7 +55,7 @@ func Test_parser(t *testing.T) { }) }) g.Describe("given a push hook from an branch creation", func() { - g.It("should extract repository and build details", func() { + g.It("should extract repository and pipeline details", func() { buf := bytes.NewBufferString(fixtures.HookPushBranch) req, _ := http.NewRequest("POST", "/hook", buf) req.Header = http.Header{} diff --git a/server/remote/gitea/types.go b/server/remote/gitea/types.go index 8f0cf4a3d..b09d5daa1 100644 --- a/server/remote/gitea/types.go +++ b/server/remote/gitea/types.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/server/remote/github/convert.go b/server/remote/github/convert.go index 0d4aa90f0..67779e107 100644 --- a/server/remote/github/convert.go +++ b/server/remote/github/convert.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -32,11 +33,11 @@ const ( ) const ( - descPending = "this build is pending" - descSuccess = "the build was successful" - descFailure = "the build failed" - descBlocked = "the build requires approval" - descDeclined = "the build was rejected" + descPending = "this pipeline is pending" + descSuccess = "the pipeline was successful" + descFailure = "the pipeline failed" + descBlocked = "the pipeline requires approval" + descDeclined = "the pipeline was rejected" descError = "oops, something went wrong" ) diff --git a/server/remote/github/convert_test.go b/server/remote/github/convert_test.go index 12d5d9906..d415d7363 100644 --- a/server/remote/github/convert_test.go +++ b/server/remote/github/convert_test.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -204,20 +205,20 @@ func Test_helper(t *testing.T) { Login: github.String("octocat"), }, } - pull, _, build, err := parsePullHook(from, true) + pull, _, pipeline, err := parsePullHook(from, true) g.Assert(err).IsNil() g.Assert(pull).IsNotNil() - g.Assert(build.Event).Equal(model.EventPull) - g.Assert(build.Branch).Equal(*from.PullRequest.Base.Ref) - g.Assert(build.Ref).Equal("refs/pull/42/merge") - g.Assert(build.Refspec).Equal("changes:master") - g.Assert(build.Remote).Equal("https://github.com/octocat/hello-world-fork") - g.Assert(build.Commit).Equal(*from.PullRequest.Head.SHA) - g.Assert(build.Message).Equal(*from.PullRequest.Title) - g.Assert(build.Title).Equal(*from.PullRequest.Title) - g.Assert(build.Author).Equal(*from.PullRequest.User.Login) - g.Assert(build.Avatar).Equal(*from.PullRequest.User.AvatarURL) - g.Assert(build.Sender).Equal(*from.Sender.Login) + g.Assert(pipeline.Event).Equal(model.EventPull) + g.Assert(pipeline.Branch).Equal(*from.PullRequest.Base.Ref) + g.Assert(pipeline.Ref).Equal("refs/pull/42/merge") + g.Assert(pipeline.Refspec).Equal("changes:master") + g.Assert(pipeline.Remote).Equal("https://github.com/octocat/hello-world-fork") + g.Assert(pipeline.Commit).Equal(*from.PullRequest.Head.SHA) + g.Assert(pipeline.Message).Equal(*from.PullRequest.Title) + g.Assert(pipeline.Title).Equal(*from.PullRequest.Title) + g.Assert(pipeline.Author).Equal(*from.PullRequest.User.Login) + g.Assert(pipeline.Avatar).Equal(*from.PullRequest.User.AvatarURL) + g.Assert(pipeline.Sender).Equal(*from.Sender.Login) }) g.It("should convert a deployment from webhook", func() { @@ -231,16 +232,16 @@ func Test_helper(t *testing.T) { from.Sender.Login = github.String("octocat") from.Sender.AvatarURL = github.String("https://avatars1.githubusercontent.com/u/583231") - _, build, err := parseDeployHook(from) + _, pipeline, err := parseDeployHook(from) g.Assert(err).IsNil() - g.Assert(build.Event).Equal(model.EventDeploy) - g.Assert(build.Branch).Equal("master") - g.Assert(build.Ref).Equal("refs/heads/master") - g.Assert(build.Commit).Equal(*from.Deployment.SHA) - g.Assert(build.Message).Equal(*from.Deployment.Description) - g.Assert(build.Link).Equal(*from.Deployment.URL) - g.Assert(build.Author).Equal(*from.Sender.Login) - g.Assert(build.Avatar).Equal(*from.Sender.AvatarURL) + g.Assert(pipeline.Event).Equal(model.EventDeploy) + g.Assert(pipeline.Branch).Equal("master") + g.Assert(pipeline.Ref).Equal("refs/heads/master") + g.Assert(pipeline.Commit).Equal(*from.Deployment.SHA) + g.Assert(pipeline.Message).Equal(*from.Deployment.Description) + g.Assert(pipeline.Link).Equal(*from.Deployment.URL) + g.Assert(pipeline.Author).Equal(*from.Sender.Login) + g.Assert(pipeline.Avatar).Equal(*from.Sender.AvatarURL) }) g.It("should convert a push from webhook", func() { @@ -254,39 +255,39 @@ func Test_helper(t *testing.T) { from.HeadCommit.ID = github.String("f72fc19") from.Ref = github.String("refs/heads/master") - _, build, err := parsePushHook(from) + _, pipeline, err := parsePushHook(from) g.Assert(err).IsNil() - g.Assert(build.Event).Equal(model.EventPush) - g.Assert(build.Branch).Equal("master") - g.Assert(build.Ref).Equal("refs/heads/master") - g.Assert(build.Commit).Equal(*from.HeadCommit.ID) - g.Assert(build.Message).Equal(*from.HeadCommit.Message) - g.Assert(build.Link).Equal(*from.HeadCommit.URL) - g.Assert(build.Author).Equal(*from.Sender.Login) - g.Assert(build.Avatar).Equal(*from.Sender.AvatarURL) - g.Assert(build.Email).Equal(*from.HeadCommit.Author.Email) - g.Assert(build.Remote).Equal(*from.Repo.CloneURL) + g.Assert(pipeline.Event).Equal(model.EventPush) + g.Assert(pipeline.Branch).Equal("master") + g.Assert(pipeline.Ref).Equal("refs/heads/master") + g.Assert(pipeline.Commit).Equal(*from.HeadCommit.ID) + g.Assert(pipeline.Message).Equal(*from.HeadCommit.Message) + g.Assert(pipeline.Link).Equal(*from.HeadCommit.URL) + g.Assert(pipeline.Author).Equal(*from.Sender.Login) + g.Assert(pipeline.Avatar).Equal(*from.Sender.AvatarURL) + g.Assert(pipeline.Email).Equal(*from.HeadCommit.Author.Email) + g.Assert(pipeline.Remote).Equal(*from.Repo.CloneURL) }) g.It("should convert a tag from webhook", func() { from := &github.PushEvent{} from.Ref = github.String("refs/tags/v1.0.0") - _, build, err := parsePushHook(from) + _, pipeline, err := parsePushHook(from) g.Assert(err).IsNil() - g.Assert(build.Event).Equal(model.EventTag) - g.Assert(build.Ref).Equal("refs/tags/v1.0.0") + g.Assert(pipeline.Event).Equal(model.EventTag) + g.Assert(pipeline.Ref).Equal("refs/tags/v1.0.0") }) - g.It("should convert tag's base branch from webhook to build's branch ", func() { + g.It("should convert tag's base branch from webhook to pipeline's branch ", func() { from := &github.PushEvent{} from.Ref = github.String("refs/tags/v1.0.0") from.BaseRef = github.String("refs/heads/master") - _, build, err := parsePushHook(from) + _, pipeline, err := parsePushHook(from) g.Assert(err).IsNil() - g.Assert(build.Event).Equal(model.EventTag) - g.Assert(build.Branch).Equal("master") + g.Assert(pipeline.Event).Equal(model.EventTag) + g.Assert(pipeline.Branch).Equal("master") }) g.It("should not convert tag's base_ref from webhook if not prefixed with 'ref/heads/'", func() { @@ -294,10 +295,10 @@ func Test_helper(t *testing.T) { from.Ref = github.String("refs/tags/v1.0.0") from.BaseRef = github.String("refs/refs/master") - _, build, err := parsePushHook(from) + _, pipeline, err := parsePushHook(from) g.Assert(err).IsNil() - g.Assert(build.Event).Equal(model.EventTag) - g.Assert(build.Branch).Equal("refs/tags/v1.0.0") + g.Assert(pipeline.Event).Equal(model.EventTag) + g.Assert(pipeline.Branch).Equal("refs/tags/v1.0.0") }) }) } diff --git a/server/remote/github/github.go b/server/remote/github/github.go index 3c26582ec..f3c1a99ed 100644 --- a/server/remote/github/github.go +++ b/server/remote/github/github.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -218,7 +219,7 @@ func (c *client) Perm(ctx context.Context, u *model.User, r *model.Repo) (*model } // File fetches the file from the GitHub repository and returns its contents. -func (c *client) File(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, f string) ([]byte, error) { +func (c *client) File(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, f string) ([]byte, error) { client := c.newClientToken(ctx, u.Token) opts := new(github.RepositoryContentGetOptions) @@ -234,7 +235,7 @@ func (c *client) File(ctx context.Context, u *model.User, r *model.Repo, b *mode return []byte(data), err } -func (c *client) Dir(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, f string) ([]*remote.FileMeta, error) { +func (c *client) Dir(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, f string) ([]*remote.FileMeta, error) { client := c.newClientToken(ctx, u.Token) opts := new(github.RepositoryContentGetOptions) @@ -436,29 +437,29 @@ var reDeploy = regexp.MustCompile(`.+/deployments/(\d+)`) // Status sends the commit status to the remote system. // An example would be the GitHub pull request status. -func (c *client) Status(ctx context.Context, user *model.User, repo *model.Repo, build *model.Build, proc *model.Proc) error { +func (c *client) Status(ctx context.Context, user *model.User, repo *model.Repo, pipeline *model.Pipeline, proc *model.Proc) error { client := c.newClientToken(ctx, user.Token) - if build.Event == model.EventDeploy { - matches := reDeploy.FindStringSubmatch(build.Link) + if pipeline.Event == model.EventDeploy { + matches := reDeploy.FindStringSubmatch(pipeline.Link) if len(matches) != 2 { return nil } id, _ := strconv.Atoi(matches[1]) _, _, err := client.Repositories.CreateDeploymentStatus(ctx, repo.Owner, repo.Name, int64(id), &github.DeploymentStatusRequest{ - State: github.String(convertStatus(build.Status)), - Description: github.String(common.GetBuildStatusDescription(build.Status)), - LogURL: github.String(common.GetBuildStatusLink(repo, build, nil)), + State: github.String(convertStatus(pipeline.Status)), + Description: github.String(common.GetPipelineStatusDescription(pipeline.Status)), + LogURL: github.String(common.GetPipelineStatusLink(repo, pipeline, nil)), }) return err } - _, _, err := client.Repositories.CreateStatus(ctx, repo.Owner, repo.Name, build.Commit, &github.RepoStatus{ - Context: github.String(common.GetBuildStatusContext(repo, build, proc)), + _, _, err := client.Repositories.CreateStatus(ctx, repo.Owner, repo.Name, pipeline.Commit, &github.RepoStatus{ + Context: github.String(common.GetPipelineStatusContext(repo, pipeline, proc)), State: github.String(convertStatus(proc.State)), - Description: github.String(common.GetBuildStatusDescription(proc.State)), - TargetURL: github.String(common.GetBuildStatusLink(repo, build, proc)), + Description: github.String(common.GetPipelineStatusDescription(proc.State)), + TargetURL: github.String(common.GetPipelineStatusLink(repo, pipeline, proc)), }) return err } @@ -521,27 +522,27 @@ func (c *client) BranchHead(ctx context.Context, u *model.User, r *model.Repo, b // Hook parses the post-commit hook from the Request body // and returns the required data in a standard format. -func (c *client) Hook(ctx context.Context, r *http.Request) (*model.Repo, *model.Build, error) { - pull, repo, build, err := parseHook(r, c.MergeRef) +func (c *client) Hook(ctx context.Context, r *http.Request) (*model.Repo, *model.Pipeline, error) { + pull, repo, pipeline, err := parseHook(r, c.MergeRef) if err != nil { return nil, nil, err } - if pull != nil && len(build.ChangedFiles) == 0 { - build, err = c.loadChangedFilesFromPullRequest(ctx, pull, repo, build) + if pull != nil && len(pipeline.ChangedFiles) == 0 { + pipeline, err = c.loadChangedFilesFromPullRequest(ctx, pull, repo, pipeline) if err != nil { return nil, nil, err } } - return repo, build, nil + return repo, pipeline, nil } -func (c *client) loadChangedFilesFromPullRequest(ctx context.Context, pull *github.PullRequest, tmpRepo *model.Repo, build *model.Build) (*model.Build, error) { +func (c *client) loadChangedFilesFromPullRequest(ctx context.Context, pull *github.PullRequest, tmpRepo *model.Repo, pipeline *model.Pipeline) (*model.Pipeline, error) { _store, ok := store.TryFromContext(ctx) if !ok { log.Error().Msg("could not get store from context") - return build, nil + return pipeline, nil } repo, err := _store.GetRepoNameFallback(tmpRepo.RemoteID, tmpRepo.FullName) @@ -568,7 +569,7 @@ func (c *client) loadChangedFilesFromPullRequest(ctx context.Context, pull *gith opts.Page = resp.NextPage } - build.ChangedFiles = utils.DedupStrings(fileList) + pipeline.ChangedFiles = utils.DedupStrings(fileList) - return build, nil + return pipeline, nil } diff --git a/server/remote/github/github_test.go b/server/remote/github/github_test.go index c3b72076a..d5b33cf1d 100644 --- a/server/remote/github/github_test.go +++ b/server/remote/github/github_test.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/server/remote/github/parse.go b/server/remote/github/parse.go index d58e4c162..d10621cb6 100644 --- a/server/remote/github/parse.go +++ b/server/remote/github/parse.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -37,8 +38,8 @@ const ( ) // parseHook parses a GitHub hook from an http.Request request and returns -// Repo and Build detail. If a hook type is unsupported nil values are returned. -func parseHook(r *http.Request, merge bool) (*github.PullRequest, *model.Repo, *model.Build, error) { +// Repo and Pipeline detail. If a hook type is unsupported nil values are returned. +func parseHook(r *http.Request, merge bool) (*github.PullRequest, *model.Repo, *model.Pipeline, error) { var reader io.Reader = r.Body if payload := r.FormValue(hookField); payload != "" { @@ -57,25 +58,25 @@ func parseHook(r *http.Request, merge bool) (*github.PullRequest, *model.Repo, * switch hook := payload.(type) { case *github.PushEvent: - repo, build, err := parsePushHook(hook) - return nil, repo, build, err + repo, pipeline, err := parsePushHook(hook) + return nil, repo, pipeline, err case *github.DeploymentEvent: - repo, build, err := parseDeployHook(hook) - return nil, repo, build, err + repo, pipeline, err := parseDeployHook(hook) + return nil, repo, pipeline, err case *github.PullRequestEvent: return parsePullHook(hook, merge) } return nil, nil, nil, nil } -// parsePushHook parses a push hook and returns the Repo and Build details. +// parsePushHook parses a push hook and returns the Repo and Pipeline details. // If the commit type is unsupported nil values are returned. -func parsePushHook(hook *github.PushEvent) (*model.Repo, *model.Build, error) { +func parsePushHook(hook *github.PushEvent) (*model.Repo, *model.Pipeline, error) { if hook.Deleted != nil && *hook.Deleted { return nil, nil, nil } - build := &model.Build{ + pipeline := &model.Pipeline{ Event: model.EventPush, Commit: hook.GetHeadCommit().GetID(), Ref: hook.GetRef(), @@ -90,31 +91,31 @@ func parsePushHook(hook *github.PushEvent) (*model.Repo, *model.Build, error) { ChangedFiles: getChangedFilesFromCommits(hook.Commits), } - if len(build.Author) == 0 { - build.Author = hook.GetHeadCommit().GetAuthor().GetLogin() + if len(pipeline.Author) == 0 { + pipeline.Author = hook.GetHeadCommit().GetAuthor().GetLogin() } - // if len(build.Email) == 0 { + // if len(pipeline.Email) == 0 { // TODO: default to gravatar? // } - if strings.HasPrefix(build.Ref, "refs/tags/") { + if strings.HasPrefix(pipeline.Ref, "refs/tags/") { // just kidding, this is actually a tag event. Why did this come as a push // event we'll never know! - build.Event = model.EventTag - build.ChangedFiles = nil + pipeline.Event = model.EventTag + pipeline.ChangedFiles = nil // For tags, if the base_ref (tag's base branch) is set, we're using it - // as build's branch so that we can filter events base on it + // as pipeline's branch so that we can filter events base on it if strings.HasPrefix(hook.GetBaseRef(), "refs/heads/") { - build.Branch = strings.Replace(hook.GetBaseRef(), "refs/heads/", "", -1) + pipeline.Branch = strings.Replace(hook.GetBaseRef(), "refs/heads/", "", -1) } } - return convertRepoHook(hook.GetRepo()), build, nil + return convertRepoHook(hook.GetRepo()), pipeline, nil } -// parseDeployHook parses a deployment and returns the Repo and Build details. +// parseDeployHook parses a deployment and returns the Repo and Pipeline details. // If the commit type is unsupported nil values are returned. -func parseDeployHook(hook *github.DeploymentEvent) (*model.Repo, *model.Build, error) { - build := &model.Build{ +func parseDeployHook(hook *github.DeploymentEvent) (*model.Repo, *model.Pipeline, error) { + pipeline := &model.Pipeline{ Event: model.EventDeploy, Commit: hook.GetDeployment().GetSHA(), Link: hook.GetDeployment().GetURL(), @@ -127,24 +128,24 @@ func parseDeployHook(hook *github.DeploymentEvent) (*model.Repo, *model.Build, e Sender: hook.GetSender().GetLogin(), } // if the ref is a sha or short sha we need to manually construct the ref. - if strings.HasPrefix(build.Commit, build.Ref) || build.Commit == build.Ref { - build.Branch = hook.GetRepo().GetDefaultBranch() - if build.Branch == "" { - build.Branch = defaultBranch + if strings.HasPrefix(pipeline.Commit, pipeline.Ref) || pipeline.Commit == pipeline.Ref { + pipeline.Branch = hook.GetRepo().GetDefaultBranch() + if pipeline.Branch == "" { + pipeline.Branch = defaultBranch } - build.Ref = fmt.Sprintf("refs/heads/%s", build.Branch) + pipeline.Ref = fmt.Sprintf("refs/heads/%s", pipeline.Branch) } // if the ref is a branch we should make sure it has refs/heads prefix - if !strings.HasPrefix(build.Ref, "refs/") { // branch or tag - build.Ref = fmt.Sprintf("refs/heads/%s", build.Branch) + if !strings.HasPrefix(pipeline.Ref, "refs/") { // branch or tag + pipeline.Ref = fmt.Sprintf("refs/heads/%s", pipeline.Branch) } - return convertRepo(hook.GetRepo()), build, nil + return convertRepo(hook.GetRepo()), pipeline, nil } -// parsePullHook parses a pull request hook and returns the Repo and Build +// parsePullHook parses a pull request hook and returns the Repo and Pipeline // details. If the pull request is closed nil values are returned. -func parsePullHook(hook *github.PullRequestEvent, merge bool) (*github.PullRequest, *model.Repo, *model.Build, error) { +func parsePullHook(hook *github.PullRequestEvent, merge bool) (*github.PullRequest, *model.Repo, *model.Pipeline, error) { // only listen to new merge-requests and pushes to open ones if hook.GetAction() != actionOpen && hook.GetAction() != actionSync { return nil, nil, nil, nil @@ -153,7 +154,7 @@ func parsePullHook(hook *github.PullRequestEvent, merge bool) (*github.PullReque return nil, nil, nil, nil } - build := &model.Build{ + pipeline := &model.Pipeline{ Event: model.EventPull, Commit: hook.GetPullRequest().GetHead().GetSHA(), Link: hook.GetPullRequest().GetHTMLURL(), @@ -171,10 +172,10 @@ func parsePullHook(hook *github.PullRequestEvent, merge bool) (*github.PullReque ), } if merge { - build.Ref = fmt.Sprintf(mergeRefs, hook.GetPullRequest().GetNumber()) + pipeline.Ref = fmt.Sprintf(mergeRefs, hook.GetPullRequest().GetNumber()) } - return hook.GetPullRequest(), convertRepo(hook.GetRepo()), build, nil + return hook.GetPullRequest(), convertRepo(hook.GetRepo()), pipeline, nil } func getChangedFilesFromCommits(commits []*github.HeadCommit) []string { diff --git a/server/remote/github/parse_test.go b/server/remote/github/parse_test.go index 862a3c0a0..7d988a573 100644 --- a/server/remote/github/parse_test.go +++ b/server/remote/github/parse_test.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -62,7 +63,7 @@ func Test_parser(t *testing.T) { g.Assert(err).IsNil() g.Assert(p).IsNil() }) - g.It("should extract repository and build details", func() { + g.It("should extract repository and pipeline details", func() { req := testHookRequest([]byte(fixtures.HookPush), hookPush) p, r, b, err := parseHook(req, false) g.Assert(err).IsNil() @@ -92,7 +93,7 @@ func Test_parser(t *testing.T) { g.Assert(err).IsNil() g.Assert(p).IsNil() }) - g.It("should extract repository and build details", func() { + g.It("should extract repository and pipeline details", func() { req := testHookRequest([]byte(fixtures.HookPullRequest), hookPull) p, r, b, err := parseHook(req, false) g.Assert(err).IsNil() @@ -104,7 +105,7 @@ func Test_parser(t *testing.T) { }) g.Describe("given a deployment hook", func() { - g.It("should extract repository and build details", func() { + g.It("should extract repository and pipeline details", func() { req := testHookRequest([]byte(fixtures.HookDeploy), hookDeploy) p, r, b, err := parseHook(req, false) g.Assert(err).IsNil() diff --git a/server/remote/gitlab/convert.go b/server/remote/gitlab/convert.go index c6123c3fd..67670275a 100644 --- a/server/remote/gitlab/convert.go +++ b/server/remote/gitlab/convert.go @@ -60,9 +60,9 @@ func (g *Gitlab) convertGitlabRepo(_repo *gitlab.Project) (*model.Repo, error) { return repo, nil } -func convertMergeRequestHook(hook *gitlab.MergeEvent, req *http.Request) (int, *model.Repo, *model.Build, error) { +func convertMergeRequestHook(hook *gitlab.MergeEvent, req *http.Request) (int, *model.Repo, *model.Pipeline, error) { repo := &model.Repo{} - build := &model.Build{} + pipeline := &model.Pipeline{} target := hook.ObjectAttributes.Target source := hook.ObjectAttributes.Source @@ -107,35 +107,35 @@ func convertMergeRequestHook(hook *gitlab.MergeEvent, req *http.Request) (int, * repo.Avatar = target.AvatarURL } - build.Event = model.EventPull + pipeline.Event = model.EventPull lastCommit := obj.LastCommit - build.Message = lastCommit.Message - build.Commit = lastCommit.ID - build.Remote = obj.Source.HTTPURL + pipeline.Message = lastCommit.Message + pipeline.Commit = lastCommit.ID + pipeline.Remote = obj.Source.HTTPURL - build.Ref = fmt.Sprintf(mergeRefs, obj.IID) - build.Branch = obj.SourceBranch + pipeline.Ref = fmt.Sprintf(mergeRefs, obj.IID) + pipeline.Branch = obj.SourceBranch author := lastCommit.Author - build.Author = author.Name - build.Email = author.Email + pipeline.Author = author.Name + pipeline.Email = author.Email - if len(build.Email) != 0 { - build.Avatar = getUserAvatar(build.Email) + if len(pipeline.Email) != 0 { + pipeline.Avatar = getUserAvatar(pipeline.Email) } - build.Title = obj.Title - build.Link = obj.URL + pipeline.Title = obj.Title + pipeline.Link = obj.URL - return obj.IID, repo, build, nil + return obj.IID, repo, pipeline, nil } -func convertPushHook(hook *gitlab.PushEvent) (*model.Repo, *model.Build, error) { +func convertPushHook(hook *gitlab.PushEvent) (*model.Repo, *model.Pipeline, error) { repo := &model.Repo{} - build := &model.Build{} + pipeline := &model.Pipeline{} var err error if repo.Owner, repo.Name, err = extractFromPath(hook.Project.PathWithNamespace); err != nil { @@ -158,21 +158,21 @@ func convertPushHook(hook *gitlab.PushEvent) (*model.Repo, *model.Build, error) repo.IsSCMPrivate = false } - build.Event = model.EventPush - build.Commit = hook.After - build.Branch = strings.TrimPrefix(hook.Ref, "refs/heads/") - build.Ref = hook.Ref + pipeline.Event = model.EventPush + pipeline.Commit = hook.After + pipeline.Branch = strings.TrimPrefix(hook.Ref, "refs/heads/") + pipeline.Ref = hook.Ref // assume a capacity of 4 changed files per commit files := make([]string, 0, len(hook.Commits)*4) for _, cm := range hook.Commits { if hook.After == cm.ID { - build.Author = cm.Author.Name - build.Email = cm.Author.Email - build.Message = cm.Message - build.Timestamp = cm.Timestamp.Unix() - if len(build.Email) != 0 { - build.Avatar = getUserAvatar(build.Email) + pipeline.Author = cm.Author.Name + pipeline.Email = cm.Author.Email + pipeline.Message = cm.Message + pipeline.Timestamp = cm.Timestamp.Unix() + if len(pipeline.Email) != 0 { + pipeline.Avatar = getUserAvatar(pipeline.Email) } } @@ -180,14 +180,14 @@ func convertPushHook(hook *gitlab.PushEvent) (*model.Repo, *model.Build, error) files = append(files, cm.Removed...) files = append(files, cm.Modified...) } - build.ChangedFiles = utils.DedupStrings(files) + pipeline.ChangedFiles = utils.DedupStrings(files) - return repo, build, nil + return repo, pipeline, nil } -func convertTagHook(hook *gitlab.TagEvent) (*model.Repo, *model.Build, error) { +func convertTagHook(hook *gitlab.TagEvent) (*model.Repo, *model.Pipeline, error) { repo := &model.Repo{} - build := &model.Build{} + pipeline := &model.Pipeline{} var err error if repo.Owner, repo.Name, err = extractFromPath(hook.Project.PathWithNamespace); err != nil { @@ -210,25 +210,25 @@ func convertTagHook(hook *gitlab.TagEvent) (*model.Repo, *model.Build, error) { repo.IsSCMPrivate = false } - build.Event = model.EventTag - build.Commit = hook.After - build.Branch = strings.TrimPrefix(hook.Ref, "refs/heads/") - build.Ref = hook.Ref + pipeline.Event = model.EventTag + pipeline.Commit = hook.After + pipeline.Branch = strings.TrimPrefix(hook.Ref, "refs/heads/") + pipeline.Ref = hook.Ref for _, cm := range hook.Commits { if hook.After == cm.ID { - build.Author = cm.Author.Name - build.Email = cm.Author.Email - build.Message = cm.Message - build.Timestamp = cm.Timestamp.Unix() - if len(build.Email) != 0 { - build.Avatar = getUserAvatar(build.Email) + pipeline.Author = cm.Author.Name + pipeline.Email = cm.Author.Email + pipeline.Message = cm.Message + pipeline.Timestamp = cm.Timestamp.Unix() + if len(pipeline.Email) != 0 { + pipeline.Avatar = getUserAvatar(pipeline.Email) } break } } - return repo, build, nil + return repo, pipeline, nil } func getUserAvatar(email string) string { diff --git a/server/remote/gitlab/gitlab.go b/server/remote/gitlab/gitlab.go index c086f9f9c..233c06e9e 100644 --- a/server/remote/gitlab/gitlab.go +++ b/server/remote/gitlab/gitlab.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -324,7 +325,7 @@ func (g *Gitlab) Perm(ctx context.Context, user *model.User, r *model.Repo) (*mo } // File fetches a file from the remote repository and returns in string format. -func (g *Gitlab) File(ctx context.Context, user *model.User, repo *model.Repo, build *model.Build, fileName string) ([]byte, error) { +func (g *Gitlab) File(ctx context.Context, user *model.User, repo *model.Repo, pipeline *model.Pipeline, fileName string) ([]byte, error) { client, err := newClient(g.URL, user.Token, g.SkipVerify) if err != nil { return nil, err @@ -333,12 +334,12 @@ func (g *Gitlab) File(ctx context.Context, user *model.User, repo *model.Repo, b if err != nil { return nil, err } - file, _, err := client.RepositoryFiles.GetRawFile(_repo.ID, fileName, &gitlab.GetRawFileOptions{Ref: &build.Commit}, gitlab.WithContext(ctx)) + file, _, err := client.RepositoryFiles.GetRawFile(_repo.ID, fileName, &gitlab.GetRawFileOptions{Ref: &pipeline.Commit}, gitlab.WithContext(ctx)) return file, err } // Dir fetches a folder from the remote repository -func (g *Gitlab) Dir(ctx context.Context, user *model.User, repo *model.Repo, build *model.Build, path string) ([]*remote.FileMeta, error) { +func (g *Gitlab) Dir(ctx context.Context, user *model.User, repo *model.Repo, pipeline *model.Pipeline, path string) ([]*remote.FileMeta, error) { client, err := newClient(g.URL, user.Token, g.SkipVerify) if err != nil { return nil, err @@ -352,7 +353,7 @@ func (g *Gitlab) Dir(ctx context.Context, user *model.User, repo *model.Repo, bu opts := &gitlab.ListTreeOptions{ ListOptions: gitlab.ListOptions{PerPage: perPage}, Path: &path, - Ref: &build.Commit, + Ref: &pipeline.Commit, Recursive: gitlab.Bool(false), } @@ -367,7 +368,7 @@ func (g *Gitlab) Dir(ctx context.Context, user *model.User, repo *model.Repo, bu if batch[i].Type != "blob" { // no file continue } - data, err := g.File(ctx, user, repo, build, batch[i].Path) + data, err := g.File(ctx, user, repo, pipeline, batch[i].Path) if err != nil { return nil, err } @@ -386,7 +387,7 @@ func (g *Gitlab) Dir(ctx context.Context, user *model.User, repo *model.Repo, bu } // Status sends the commit status back to gitlab. -func (g *Gitlab) Status(ctx context.Context, user *model.User, repo *model.Repo, build *model.Build, proc *model.Proc) error { +func (g *Gitlab) Status(ctx context.Context, user *model.User, repo *model.Repo, pipeline *model.Pipeline, proc *model.Proc) error { client, err := newClient(g.URL, user.Token, g.SkipVerify) if err != nil { return err @@ -397,11 +398,11 @@ func (g *Gitlab) Status(ctx context.Context, user *model.User, repo *model.Repo, return err } - _, _, err = client.Commits.SetCommitStatus(_repo.ID, build.Commit, &gitlab.SetCommitStatusOptions{ + _, _, err = client.Commits.SetCommitStatus(_repo.ID, pipeline.Commit, &gitlab.SetCommitStatusOptions{ State: getStatus(proc.State), - Description: gitlab.String(common.GetBuildStatusDescription(proc.State)), - TargetURL: gitlab.String(common.GetBuildStatusLink(repo, build, proc)), - Context: gitlab.String(common.GetBuildStatusContext(repo, build, proc)), + Description: gitlab.String(common.GetPipelineStatusDescription(proc.State)), + TargetURL: gitlab.String(common.GetPipelineStatusLink(repo, pipeline, proc)), + Context: gitlab.String(common.GetPipelineStatusContext(repo, pipeline, proc)), }, gitlab.WithContext(ctx)) return err @@ -584,7 +585,7 @@ func (g *Gitlab) BranchHead(ctx context.Context, u *model.User, r *model.Repo, b // Hook parses the post-commit hook from the Request body // and returns the required data in a standard format. -func (g *Gitlab) Hook(ctx context.Context, req *http.Request) (*model.Repo, *model.Build, error) { +func (g *Gitlab) Hook(ctx context.Context, req *http.Request) (*model.Repo, *model.Pipeline, error) { defer req.Body.Close() payload, err := io.ReadAll(req.Body) if err != nil { @@ -598,16 +599,16 @@ func (g *Gitlab) Hook(ctx context.Context, req *http.Request) (*model.Repo, *mod switch event := parsed.(type) { case *gitlab.MergeEvent: - mergeIID, repo, build, err := convertMergeRequestHook(event, req) + mergeIID, repo, pipeline, err := convertMergeRequestHook(event, req) if err != nil { return nil, nil, err } - if build, err = g.loadChangedFilesFromMergeRequest(ctx, repo, build, mergeIID); err != nil { + if pipeline, err = g.loadChangedFilesFromMergeRequest(ctx, repo, pipeline, mergeIID); err != nil { return nil, nil, err } - return repo, build, nil + return repo, pipeline, nil case *gitlab.PushEvent: return convertPushHook(event) case *gitlab.TagEvent: @@ -673,11 +674,11 @@ func (g *Gitlab) OrgMembership(ctx context.Context, u *model.User, owner string) return &model.OrgPerm{}, nil } -func (g *Gitlab) loadChangedFilesFromMergeRequest(ctx context.Context, tmpRepo *model.Repo, build *model.Build, mergeIID int) (*model.Build, error) { +func (g *Gitlab) loadChangedFilesFromMergeRequest(ctx context.Context, tmpRepo *model.Repo, pipeline *model.Pipeline, mergeIID int) (*model.Pipeline, error) { _store, ok := store.TryFromContext(ctx) if !ok { log.Error().Msg("could not get store from context") - return build, nil + return pipeline, nil } repo, err := _store.GetRepoNameFallback(tmpRepo.RemoteID, tmpRepo.FullName) @@ -709,7 +710,7 @@ func (g *Gitlab) loadChangedFilesFromMergeRequest(ctx context.Context, tmpRepo * for _, file := range changes.Changes { files = append(files, file.NewPath, file.OldPath) } - build.ChangedFiles = utils.DedupStrings(files) + pipeline.ChangedFiles = utils.DedupStrings(files) - return build, nil + return pipeline, nil } diff --git a/server/remote/gitlab/gitlab_test.go b/server/remote/gitlab/gitlab_test.go index 7cc84050f..e6dd66b59 100644 --- a/server/remote/gitlab/gitlab_test.go +++ b/server/remote/gitlab/gitlab_test.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -169,16 +170,16 @@ func Test_Gitlab(t *testing.T) { ) req.Header = testdata.ServiceHookHeaders - hookRepo, build, err := client.Hook(ctx, req) + hookRepo, pipeline, err := client.Hook(ctx, req) assert.NoError(t, err) - if assert.NotNil(t, hookRepo) && assert.NotNil(t, build) { - assert.Equal(t, build.Event, model.EventPush) + if assert.NotNil(t, hookRepo) && assert.NotNil(t, pipeline) { + assert.Equal(t, pipeline.Event, model.EventPush) assert.Equal(t, "test", hookRepo.Owner) assert.Equal(t, "woodpecker", hookRepo.Name) assert.Equal(t, "http://example.com/uploads/project/avatar/555/Outh-20-Logo.jpg", hookRepo.Avatar) assert.Equal(t, "develop", hookRepo.Branch) - assert.Equal(t, "refs/heads/master", build.Ref) - assert.Equal(t, []string{"cmd/cli/main.go"}, build.ChangedFiles) + assert.Equal(t, "refs/heads/master", pipeline.Ref) + assert.Equal(t, []string{"cmd/cli/main.go"}, pipeline.ChangedFiles) } }) }) @@ -192,15 +193,15 @@ func Test_Gitlab(t *testing.T) { ) req.Header = testdata.ServiceHookHeaders - hookRepo, build, err := client.Hook(ctx, req) + hookRepo, pipeline, err := client.Hook(ctx, req) assert.NoError(t, err) - if assert.NotNil(t, hookRepo) && assert.NotNil(t, build) { + if assert.NotNil(t, hookRepo) && assert.NotNil(t, pipeline) { assert.Equal(t, "test", hookRepo.Owner) assert.Equal(t, "woodpecker", hookRepo.Name) assert.Equal(t, "http://example.com/uploads/project/avatar/555/Outh-20-Logo.jpg", hookRepo.Avatar) assert.Equal(t, "develop", hookRepo.Branch) - assert.Equal(t, "refs/tags/v22", build.Ref) - assert.Len(t, build.ChangedFiles, 0) + assert.Equal(t, "refs/tags/v22", pipeline.Ref) + assert.Len(t, pipeline.ChangedFiles, 0) } }) }) @@ -215,15 +216,15 @@ func Test_Gitlab(t *testing.T) { req.Header = testdata.ServiceHookHeaders // TODO: insert fake store into context to retrieve user & repo, this will activate fetching of ChangedFiles - hookRepo, build, err := client.Hook(ctx, req) + hookRepo, pipeline, err := client.Hook(ctx, req) assert.NoError(t, err) - if assert.NotNil(t, hookRepo) && assert.NotNil(t, build) { + if assert.NotNil(t, hookRepo) && assert.NotNil(t, pipeline) { assert.Equal(t, "http://example.com/uploads/project/avatar/555/Outh-20-Logo.jpg", hookRepo.Avatar) assert.Equal(t, "main", hookRepo.Branch) assert.Equal(t, "anbraten", hookRepo.Owner) assert.Equal(t, "woodpecker", hookRepo.Name) - assert.Equal(t, "Update client.go 🎉", build.Title) - assert.Len(t, build.ChangedFiles, 0) // see L217 + assert.Equal(t, "Update client.go 🎉", pipeline.Title) + assert.Len(t, pipeline.ChangedFiles, 0) // see L217 } }) }) diff --git a/server/remote/gitlab/helper.go b/server/remote/gitlab/helper.go index 8f03abd09..edc9bbc88 100644 --- a/server/remote/gitlab/helper.go +++ b/server/remote/gitlab/helper.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/server/remote/gogs/gogs.go b/server/remote/gogs/gogs.go index 1f8ef4b6d..a892320ce 100644 --- a/server/remote/gogs/gogs.go +++ b/server/remote/gogs/gogs.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -185,7 +186,7 @@ func (c *client) Perm(ctx context.Context, u *model.User, r *model.Repo) (*model } // File fetches the file from the Gogs repository and returns its contents. -func (c *client) File(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, f string) ([]byte, error) { +func (c *client) File(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, f string) ([]byte, error) { client := c.newClientToken(u.Token) ref := b.Commit @@ -208,12 +209,12 @@ func (c *client) File(ctx context.Context, u *model.User, r *model.Repo, b *mode return cfg, err } -func (c *client) Dir(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, f string) ([]*remote.FileMeta, error) { +func (c *client) Dir(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, f string) ([]*remote.FileMeta, error) { return nil, fmt.Errorf("Not implemented") } // Status is not supported by the Gogs driver. -func (c *client) Status(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, proc *model.Proc) error { +func (c *client) Status(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, proc *model.Proc) error { return nil } @@ -297,9 +298,9 @@ func (c *client) BranchHead(ctx context.Context, u *model.User, r *model.Repo, b return b.Commit.ID, nil } -// Hook parses the incoming Gogs hook and returns the Repository and Build +// Hook parses the incoming Gogs hook and returns the Repository and Pipeline // details. If the hook is unsupported nil values are returned. -func (c *client) Hook(ctx context.Context, r *http.Request) (*model.Repo, *model.Build, error) { +func (c *client) Hook(ctx context.Context, r *http.Request) (*model.Repo, *model.Pipeline, error) { return parseHook(r, c.PrivateMode) } diff --git a/server/remote/gogs/gogs_test.go b/server/remote/gogs/gogs_test.go index e922853bb..1e35cbb21 100644 --- a/server/remote/gogs/gogs_test.go +++ b/server/remote/gogs/gogs_test.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -135,13 +136,13 @@ func Test_gogs(t *testing.T) { }) g.It("Should return a repository file", func() { - raw, err := c.File(ctx, fakeUser, fakeRepo, fakeBuild, ".woodpecker.yml") + raw, err := c.File(ctx, fakeUser, fakeRepo, fakePipeline, ".woodpecker.yml") g.Assert(err).IsNil() g.Assert(string(raw)).Equal("{ platform: linux/amd64 }") }) g.It("Should return a repository file from a ref", func() { - raw, err := c.File(ctx, fakeUser, fakeRepo, fakeBuildWithRef, ".woodpecker.yml") + raw, err := c.File(ctx, fakeUser, fakeRepo, fakePipelineWithRef, ".woodpecker.yml") g.Assert(err).IsNil() g.Assert(string(raw)).Equal("{ platform: linux/amd64 }") }) @@ -195,11 +196,11 @@ var ( FullName: "test_name/repo_not_found", } - fakeBuild = &model.Build{ + fakePipeline = &model.Pipeline{ Commit: "9ecad50", } - fakeBuildWithRef = &model.Build{ + fakePipelineWithRef = &model.Pipeline{ Ref: "refs/tags/v1.0.0", } ) diff --git a/server/remote/gogs/helper.go b/server/remote/gogs/helper.go index e0b580a72..727e64971 100644 --- a/server/remote/gogs/helper.go +++ b/server/remote/gogs/helper.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -65,8 +66,8 @@ func toTeam(from *gogs.Organization, link string) *model.Team { } } -// helper function that extracts the Build data from a Gogs push hook -func buildFromPush(hook *pushHook) *model.Build { +// helper function that extracts the Pipeline data from a Gogs push hook +func pipelineFromPush(hook *pushHook) *model.Pipeline { avatar := expandAvatar( hook.Repo.HTMLURL, fixMalformedAvatar(hook.Sender.AvatarUrl), @@ -80,7 +81,7 @@ func buildFromPush(hook *pushHook) *model.Build { sender = hook.Sender.Login } - return &model.Build{ + return &model.Pipeline{ Event: model.EventPush, Commit: hook.After, Ref: hook.Ref, @@ -95,8 +96,8 @@ func buildFromPush(hook *pushHook) *model.Build { } } -// helper function that extracts the Build data from a Gogs tag hook -func buildFromTag(hook *pushHook) *model.Build { +// helper function that extracts the pipeline data from a Gogs tag hook +func pipelineFromTag(hook *pushHook) *model.Pipeline { avatar := expandAvatar( hook.Repo.HTMLURL, fixMalformedAvatar(hook.Sender.AvatarUrl), @@ -110,7 +111,7 @@ func buildFromTag(hook *pushHook) *model.Build { sender = hook.Sender.Login } - return &model.Build{ + return &model.Pipeline{ Event: model.EventTag, Commit: hook.After, Ref: fmt.Sprintf("refs/tags/%s", hook.Ref), @@ -124,8 +125,8 @@ func buildFromTag(hook *pushHook) *model.Build { } } -// helper function that extracts the Build data from a Gogs pull_request hook -func buildFromPullRequest(hook *pullRequestHook) *model.Build { +// helper function that extracts the Pipeline data from a Gogs pull_request hook +func pipelineFromPullRequest(hook *pullRequestHook) *model.Pipeline { avatar := expandAvatar( hook.Repo.HTMLURL, fixMalformedAvatar(hook.PullRequest.User.AvatarUrl), @@ -134,7 +135,7 @@ func buildFromPullRequest(hook *pullRequestHook) *model.Build { if sender == "" { sender = hook.Sender.Login } - build := &model.Build{ + pipeline := &model.Pipeline{ Event: model.EventPull, Commit: hook.PullRequest.Head.Sha, Link: hook.PullRequest.URL, @@ -150,7 +151,7 @@ func buildFromPullRequest(hook *pullRequestHook) *model.Build { hook.PullRequest.BaseBranch, ), } - return build + return pipeline } // helper function that parses a push hook from a read closer. diff --git a/server/remote/gogs/helper_test.go b/server/remote/gogs/helper_test.go index 65f2ed281..c37650767 100644 --- a/server/remote/gogs/helper_test.go +++ b/server/remote/gogs/helper_test.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -89,18 +90,18 @@ func Test_parse(t *testing.T) { g.Assert(hook.PullRequest.Head.Ref).Equal("feature/changes") }) - g.It("Should return a Build struct from a push hook", func() { + g.It("Should return a Pipeline struct from a push hook", func() { buf := bytes.NewBufferString(fixtures.HookPush) hook, _ := parsePush(buf) - build := buildFromPush(hook) - g.Assert(build.Event).Equal(model.EventPush) - g.Assert(build.Commit).Equal(hook.After) - g.Assert(build.Ref).Equal(hook.Ref) - g.Assert(build.Link).Equal(hook.Compare) - g.Assert(build.Branch).Equal("master") - g.Assert(build.Message).Equal(hook.Commits[0].Message) - g.Assert(build.Avatar).Equal("http://1.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87") - g.Assert(build.Author).Equal(hook.Sender.Login) + pipeline := pipelineFromPush(hook) + g.Assert(pipeline.Event).Equal(model.EventPush) + g.Assert(pipeline.Commit).Equal(hook.After) + g.Assert(pipeline.Ref).Equal(hook.Ref) + g.Assert(pipeline.Link).Equal(hook.Compare) + g.Assert(pipeline.Branch).Equal("master") + g.Assert(pipeline.Message).Equal(hook.Commits[0].Message) + g.Assert(pipeline.Avatar).Equal("http://1.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87") + g.Assert(pipeline.Author).Equal(hook.Sender.Login) }) g.It("Should return a Repo struct from a push hook", func() { @@ -113,18 +114,18 @@ func Test_parse(t *testing.T) { g.Assert(repo.Link).Equal(hook.Repo.HTMLURL) }) - g.It("Should return a Build struct from a pull_request hook", func() { + g.It("Should return a Pipeline struct from a pull_request hook", func() { buf := bytes.NewBufferString(fixtures.HookPullRequest) hook, _ := parsePullRequest(buf) - build := buildFromPullRequest(hook) - g.Assert(build.Event).Equal(model.EventPull) - g.Assert(build.Commit).Equal(hook.PullRequest.Head.Sha) - g.Assert(build.Ref).Equal("refs/pull/1/head") - g.Assert(build.Link).Equal(hook.PullRequest.URL) - g.Assert(build.Branch).Equal("master") - g.Assert(build.Message).Equal(hook.PullRequest.Title) - g.Assert(build.Avatar).Equal("http://1.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87") - g.Assert(build.Author).Equal(hook.PullRequest.User.UserName) + pipeline := pipelineFromPullRequest(hook) + g.Assert(pipeline.Event).Equal(model.EventPull) + g.Assert(pipeline.Commit).Equal(hook.PullRequest.Head.Sha) + g.Assert(pipeline.Ref).Equal("refs/pull/1/head") + g.Assert(pipeline.Link).Equal(hook.PullRequest.URL) + g.Assert(pipeline.Branch).Equal("master") + g.Assert(pipeline.Message).Equal(hook.PullRequest.Title) + g.Assert(pipeline.Avatar).Equal("http://1.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87") + g.Assert(pipeline.Author).Equal(hook.PullRequest.User.UserName) }) g.It("Should return a Repo struct from a pull_request hook", func() { diff --git a/server/remote/gogs/parse.go b/server/remote/gogs/parse.go index 9177247f6..d6af5227c 100644 --- a/server/remote/gogs/parse.go +++ b/server/remote/gogs/parse.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -37,8 +38,8 @@ const ( ) // parseHook parses a Bitbucket hook from an http.Request request and returns -// Repo and Build detail. If a hook type is unsupported nil values are returned. -func parseHook(r *http.Request, privateMode bool) (*model.Repo, *model.Build, error) { +// Repo and Pipeline detail. If a hook type is unsupported nil values are returned. +func parseHook(r *http.Request, privateMode bool) (*model.Repo, *model.Pipeline, error) { switch r.Header.Get(hookEvent) { case hookPush: return parsePushHook(r.Body, privateMode) @@ -50,12 +51,12 @@ func parseHook(r *http.Request, privateMode bool) (*model.Repo, *model.Build, er return nil, nil, nil } -// parsePushHook parses a push hook and returns the Repo and Build details. +// parsePushHook parses a push hook and returns the Repo and Pipeline details. // If the commit type is unsupported nil values are returned. -func parsePushHook(payload io.Reader, privateMode bool) (*model.Repo, *model.Build, error) { +func parsePushHook(payload io.Reader, privateMode bool) (*model.Repo, *model.Pipeline, error) { var ( - repo *model.Repo - build *model.Build + repo *model.Repo + pipeline *model.Pipeline ) push, err := parsePush(payload) @@ -69,16 +70,16 @@ func parsePushHook(payload io.Reader, privateMode bool) (*model.Repo, *model.Bui } repo = toRepo(push.Repo, privateMode) - build = buildFromPush(push) - return repo, build, err + pipeline = pipelineFromPush(push) + return repo, pipeline, err } -// parseCreatedHook parses a push hook and returns the Repo and Build details. +// parseCreatedHook parses a push hook and returns the Repo and Pipeline details. // If the commit type is unsupported nil values are returned. -func parseCreatedHook(payload io.Reader, privateMode bool) (*model.Repo, *model.Build, error) { +func parseCreatedHook(payload io.Reader, privateMode bool) (*model.Repo, *model.Pipeline, error) { var ( - repo *model.Repo - build *model.Build + repo *model.Repo + pipeline *model.Pipeline ) push, err := parsePush(payload) @@ -91,15 +92,15 @@ func parseCreatedHook(payload io.Reader, privateMode bool) (*model.Repo, *model. } repo = toRepo(push.Repo, privateMode) - build = buildFromTag(push) - return repo, build, err + pipeline = pipelineFromTag(push) + return repo, pipeline, err } -// parsePullRequestHook parses a pull_request hook and returns the Repo and Build details. -func parsePullRequestHook(payload io.Reader, privateMode bool) (*model.Repo, *model.Build, error) { +// parsePullRequestHook parses a pull_request hook and returns the Repo and Pipeline details. +func parsePullRequestHook(payload io.Reader, privateMode bool) (*model.Repo, *model.Pipeline, error) { var ( - repo *model.Repo - build *model.Build + repo *model.Repo + pipeline *model.Pipeline ) pr, err := parsePullRequest(payload) @@ -107,7 +108,7 @@ func parsePullRequestHook(payload io.Reader, privateMode bool) (*model.Repo, *mo return nil, nil, err } - // Don't trigger builds for non-code changes, or if PR is not open + // Don't trigger pipelines for non-code changes, or if PR is not open if pr.Action != actionOpen && pr.Action != actionSync { return nil, nil, nil } @@ -116,6 +117,6 @@ func parsePullRequestHook(payload io.Reader, privateMode bool) (*model.Repo, *mo } repo = toRepo(pr.Repo, privateMode) - build = buildFromPullRequest(pr) - return repo, build, err + pipeline = pipelineFromPullRequest(pr) + return repo, pipeline, err } diff --git a/server/remote/gogs/types.go b/server/remote/gogs/types.go index 69da82706..fa63e9e99 100644 --- a/server/remote/gogs/types.go +++ b/server/remote/gogs/types.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/server/remote/mocks/remote.go b/server/remote/mocks/remote.go index c7f4104b7..8c00b8d7c 100644 --- a/server/remote/mocks/remote.go +++ b/server/remote/mocks/remote.go @@ -112,11 +112,11 @@ func (_m *Remote) Deactivate(ctx context.Context, u *model.User, r *model.Repo, } // Dir provides a mock function with given fields: ctx, u, r, b, f -func (_m *Remote) Dir(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, f string) ([]*remote.FileMeta, error) { +func (_m *Remote) Dir(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, f string) ([]*remote.FileMeta, error) { ret := _m.Called(ctx, u, r, b, f) var r0 []*remote.FileMeta - if rf, ok := ret.Get(0).(func(context.Context, *model.User, *model.Repo, *model.Build, string) []*remote.FileMeta); ok { + if rf, ok := ret.Get(0).(func(context.Context, *model.User, *model.Repo, *model.Pipeline, string) []*remote.FileMeta); ok { r0 = rf(ctx, u, r, b, f) } else { if ret.Get(0) != nil { @@ -125,7 +125,7 @@ func (_m *Remote) Dir(ctx context.Context, u *model.User, r *model.Repo, b *mode } var r1 error - if rf, ok := ret.Get(1).(func(context.Context, *model.User, *model.Repo, *model.Build, string) error); ok { + if rf, ok := ret.Get(1).(func(context.Context, *model.User, *model.Repo, *model.Pipeline, string) error); ok { r1 = rf(ctx, u, r, b, f) } else { r1 = ret.Error(1) @@ -135,11 +135,11 @@ func (_m *Remote) Dir(ctx context.Context, u *model.User, r *model.Repo, b *mode } // File provides a mock function with given fields: ctx, u, r, b, f -func (_m *Remote) File(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, f string) ([]byte, error) { +func (_m *Remote) File(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, f string) ([]byte, error) { ret := _m.Called(ctx, u, r, b, f) var r0 []byte - if rf, ok := ret.Get(0).(func(context.Context, *model.User, *model.Repo, *model.Build, string) []byte); ok { + if rf, ok := ret.Get(0).(func(context.Context, *model.User, *model.Repo, *model.Pipeline, string) []byte); ok { r0 = rf(ctx, u, r, b, f) } else { if ret.Get(0) != nil { @@ -148,7 +148,7 @@ func (_m *Remote) File(ctx context.Context, u *model.User, r *model.Repo, b *mod } var r1 error - if rf, ok := ret.Get(1).(func(context.Context, *model.User, *model.Repo, *model.Build, string) error); ok { + if rf, ok := ret.Get(1).(func(context.Context, *model.User, *model.Repo, *model.Pipeline, string) error); ok { r1 = rf(ctx, u, r, b, f) } else { r1 = ret.Error(1) @@ -158,7 +158,7 @@ func (_m *Remote) File(ctx context.Context, u *model.User, r *model.Repo, b *mod } // Hook provides a mock function with given fields: ctx, r -func (_m *Remote) Hook(ctx context.Context, r *http.Request) (*model.Repo, *model.Build, error) { +func (_m *Remote) Hook(ctx context.Context, r *http.Request) (*model.Repo, *model.Pipeline, error) { ret := _m.Called(ctx, r) var r0 *model.Repo @@ -170,12 +170,12 @@ func (_m *Remote) Hook(ctx context.Context, r *http.Request) (*model.Repo, *mode } } - var r1 *model.Build - if rf, ok := ret.Get(1).(func(context.Context, *http.Request) *model.Build); ok { + var r1 *model.Pipeline + if rf, ok := ret.Get(1).(func(context.Context, *http.Request) *model.Pipeline); ok { r1 = rf(ctx, r) } else { if ret.Get(1) != nil { - r1 = ret.Get(1).(*model.Build) + r1 = ret.Get(1).(*model.Pipeline) } } @@ -342,11 +342,11 @@ func (_m *Remote) Repos(ctx context.Context, u *model.User) ([]*model.Repo, erro } // Status provides a mock function with given fields: ctx, u, r, b, p -func (_m *Remote) Status(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, p *model.Proc) error { +func (_m *Remote) Status(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, p *model.Proc) error { ret := _m.Called(ctx, u, r, b, p) var r0 error - if rf, ok := ret.Get(0).(func(context.Context, *model.User, *model.Repo, *model.Build, *model.Proc) error); ok { + if rf, ok := ret.Get(0).(func(context.Context, *model.User, *model.Repo, *model.Pipeline, *model.Proc) error); ok { r0 = rf(ctx, u, r, b, p) } else { r0 = ret.Error(0) diff --git a/server/remote/remote.go b/server/remote/remote.go index 35ea9d189..4a760d455 100644 --- a/server/remote/remote.go +++ b/server/remote/remote.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -54,14 +55,14 @@ type Remote interface { // File fetches a file from the remote repository and returns in string // format. - File(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, f string) ([]byte, error) + File(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, f string) ([]byte, error) // Dir fetches a folder from the remote repository - Dir(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, f string) ([]*FileMeta, error) + Dir(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, f string) ([]*FileMeta, error) // Status sends the commit status to the remote system. // An example would be the GitHub pull request status. - Status(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, p *model.Proc) error + Status(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, p *model.Proc) error // Netrc returns a .netrc file that can be used to clone // private repositories from a remote system. @@ -83,7 +84,7 @@ type Remote interface { // Hook parses the post-commit hook from the Request body and returns the // required data in a standard format. - Hook(ctx context.Context, r *http.Request) (*model.Repo, *model.Build, error) + Hook(ctx context.Context, r *http.Request) (*model.Repo, *model.Pipeline, error) // OrgMembership returns if user is member of organization and if user // is admin/owner in that organization. diff --git a/server/router/api.go b/server/router/api.go index 79d40dc04..9efd7165e 100644 --- a/server/router/api.go +++ b/server/router/api.go @@ -75,23 +75,35 @@ func apiRoutes(e *gin.Engine) { repo.GET("/branches", api.GetRepoBranches) - repo.GET("/builds", api.GetBuilds) - repo.POST("/builds", session.MustPush, api.CreateBuild) - repo.GET("/builds/:number", api.GetBuild) - repo.GET("/builds/:number/config", api.GetBuildConfig) + repo.GET("/pipelines", api.GetPipelines) + repo.POST("/pipelines", session.MustPush, api.CreatePipeline) + repo.GET("/pipelines/:number", api.GetPipeline) + repo.GET("/pipelines/:number/config", api.GetPipelineConfig) // requires push permissions - repo.POST("/builds/:number", session.MustPush, api.PostBuild) - repo.DELETE("/builds/:number", session.MustPush, api.DeleteBuild) + repo.POST("/pipelines/:number", session.MustPush, api.PostPipeline) + repo.DELETE("/pipelines/:number", session.MustPush, api.DeletePipeline) + repo.POST("/pipelines/:number/approve", session.MustPush, api.PostApproval) + repo.POST("/pipelines/:number/decline", session.MustPush, api.PostDecline) + repo.DELETE("/pipelines/:number/:job", session.MustPush, api.DeletePipeline) + + // DEPRECATED - use /pipelines/ + repo.GET("/builds", api.GetPipelines) + repo.POST("/builds", session.MustPush, api.CreatePipeline) + repo.GET("/builds/:number", api.GetPipeline) + repo.GET("/builds/:number/config", api.GetPipelineConfig) + // requires push permissions + repo.POST("/builds/:number", session.MustPush, api.PostPipeline) + repo.DELETE("/builds/:number", session.MustPush, api.DeletePipeline) repo.POST("/builds/:number/approve", session.MustPush, api.PostApproval) repo.POST("/builds/:number/decline", session.MustPush, api.PostDecline) - repo.DELETE("/builds/:number/:job", session.MustPush, api.DeleteBuild) + repo.DELETE("/builds/:number/:job", session.MustPush, api.DeletePipeline) repo.GET("/logs/:number/:pid", api.GetProcLogs) - repo.GET("/logs/:number/:pid/:proc", api.GetBuildLogs) + repo.GET("/logs/:number/:pid/:proc", api.GetPipelineLogs) // requires push permissions - repo.DELETE("/logs/:number", session.MustPush, api.DeleteBuildLogs) + repo.DELETE("/logs/:number", session.MustPush, api.DeletePipelineLogs) repo.GET("/files/:number", api.FileList) repo.GET("/files/:number/:proc/*file", api.FileGet) @@ -132,10 +144,17 @@ func apiRoutes(e *gin.Engine) { badges.GET("/cc.xml", api.GetCC) } + pipelines := e.Group("/api/pipelines") + { + pipelines.Use(session.MustAdmin()) + pipelines.GET("", api.GetPipelineQueue) + } + + // DEPRECATED - use /api/pipelines builds := e.Group("/api/builds") { builds.Use(session.MustAdmin()) - builds.GET("", api.GetBuildQueue) + builds.GET("", api.GetPipelineQueue) } queue := e.Group("/api/queue") @@ -144,6 +163,8 @@ func apiRoutes(e *gin.Engine) { queue.GET("/info", api.GetQueueInfo) queue.GET("/pause", api.PauseQueue) queue.GET("/resume", api.ResumeQueue) + queue.GET("/norunningpipelines", api.BlockTilQueueHasRunningItem) + // DEPRECATED - use /norunningpipelines queue.GET("/norunningbuilds", api.BlockTilQueueHasRunningItem) } @@ -191,7 +212,7 @@ func apiRoutes(e *gin.Engine) { sse := e.Group("/stream") { sse.GET("/events", api.EventStreamSSE) - sse.GET("/logs/:owner/:name/:build/:number", + sse.GET("/logs/:owner/:name/:pipeline/:number", session.SetRepo(), session.SetPerm(), session.MustPull, diff --git a/server/router/middleware/session/agent.go b/server/router/middleware/session/agent.go index d679676f8..d104c74c5 100644 --- a/server/router/middleware/session/agent.go +++ b/server/router/middleware/session/agent.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,7 +21,7 @@ import ( "github.com/woodpecker-ci/woodpecker/shared/token" ) -// AuthorizeAgent authorizes requests from build agents to access the queue. +// AuthorizeAgent authorizes requests from agent to access the queue. func AuthorizeAgent(c *gin.Context) { secret := c.MustGet("agent").(string) if secret == "" { diff --git a/server/shared/buildStatus.go b/server/shared/buildStatus.go deleted file mode 100644 index 361ec89bf..000000000 --- a/server/shared/buildStatus.go +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2019 mhmxs. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package shared - -import ( - "time" - - "github.com/woodpecker-ci/woodpecker/server/model" -) - -// TODO(974) move to server/pipeline/* - -func UpdateToStatusRunning(store model.UpdateBuildStore, build model.Build, started int64) (*model.Build, error) { - build.Status = model.StatusRunning - build.Started = started - return &build, store.UpdateBuild(&build) -} - -func UpdateToStatusPending(store model.UpdateBuildStore, build model.Build, reviewer string) (*model.Build, error) { - build.Reviewer = reviewer - build.Status = model.StatusPending - build.Reviewed = time.Now().Unix() - return &build, store.UpdateBuild(&build) -} - -func UpdateToStatusDeclined(store model.UpdateBuildStore, build model.Build, reviewer string) (*model.Build, error) { - build.Reviewer = reviewer - build.Status = model.StatusDeclined - build.Reviewed = time.Now().Unix() - return &build, store.UpdateBuild(&build) -} - -func UpdateStatusToDone(store model.UpdateBuildStore, build model.Build, status model.StatusValue, stopped int64) (*model.Build, error) { - build.Status = status - build.Finished = stopped - return &build, store.UpdateBuild(&build) -} - -func UpdateToStatusError(store model.UpdateBuildStore, build model.Build, err error) (*model.Build, error) { - build.Error = err.Error() - build.Status = model.StatusError - build.Started = time.Now().Unix() - build.Finished = build.Started - return &build, store.UpdateBuild(&build) -} - -func UpdateToStatusKilled(store model.UpdateBuildStore, build model.Build) (*model.Build, error) { - build.Status = model.StatusKilled - build.Finished = time.Now().Unix() - return &build, store.UpdateBuild(&build) -} diff --git a/server/shared/buildStatus_test.go b/server/shared/buildStatus_test.go deleted file mode 100644 index 1fc52694c..000000000 --- a/server/shared/buildStatus_test.go +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2019 mhmxs. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package shared - -import ( - "errors" - "testing" - "time" - - "github.com/woodpecker-ci/woodpecker/server/model" -) - -// TODO(974) move to server/pipeline/* - -type mockUpdateBuildStore struct{} - -func (m *mockUpdateBuildStore) UpdateBuild(build *model.Build) error { - return nil -} - -func TestUpdateToStatusRunning(t *testing.T) { - t.Parallel() - - build, _ := UpdateToStatusRunning(&mockUpdateBuildStore{}, model.Build{}, int64(1)) - - if model.StatusRunning != build.Status { - t.Errorf("Build status not equals '%s' != '%s'", model.StatusRunning, build.Status) - } else if int64(1) != build.Started { - t.Errorf("Build started not equals 1 != %d", build.Started) - } -} - -func TestUpdateToStatusPending(t *testing.T) { - t.Parallel() - - now := time.Now().Unix() - - build, _ := UpdateToStatusPending(&mockUpdateBuildStore{}, model.Build{}, "Reviewer") - - if model.StatusPending != build.Status { - t.Errorf("Build status not equals '%s' != '%s'", model.StatusPending, build.Status) - } else if build.Reviewer != "Reviewer" { - t.Errorf("Reviewer not equals 'Reviewer' != '%s'", build.Reviewer) - } else if now > build.Reviewed { - t.Errorf("Reviewed not updated %d !< %d", now, build.Reviewed) - } -} - -func TestUpdateToStatusDeclined(t *testing.T) { - t.Parallel() - - now := time.Now().Unix() - - build, _ := UpdateToStatusDeclined(&mockUpdateBuildStore{}, model.Build{}, "Reviewer") - - if model.StatusDeclined != build.Status { - t.Errorf("Build status not equals '%s' != '%s'", model.StatusDeclined, build.Status) - } else if build.Reviewer != "Reviewer" { - t.Errorf("Reviewer not equals 'Reviewer' != '%s'", build.Reviewer) - } else if now > build.Reviewed { - t.Errorf("Reviewed not updated %d !< %d", now, build.Reviewed) - } -} - -func TestUpdateToStatusToDone(t *testing.T) { - t.Parallel() - - build, _ := UpdateStatusToDone(&mockUpdateBuildStore{}, model.Build{}, "status", int64(1)) - - if build.Status != "status" { - t.Errorf("Build status not equals 'status' != '%s'", build.Status) - } else if int64(1) != build.Finished { - t.Errorf("Build finished not equals 1 != %d", build.Finished) - } -} - -func TestUpdateToStatusError(t *testing.T) { - t.Parallel() - - now := time.Now().Unix() - - build, _ := UpdateToStatusError(&mockUpdateBuildStore{}, model.Build{}, errors.New("error")) - - if build.Error != "error" { - t.Errorf("Build error not equals 'error' != '%s'", build.Error) - } else if model.StatusError != build.Status { - t.Errorf("Build status not equals '%s' != '%s'", model.StatusError, build.Status) - } else if now > build.Started { - t.Errorf("Started not updated %d !< %d", now, build.Started) - } else if build.Started != build.Finished { - t.Errorf("Build started and finished not equals %d != %d", build.Started, build.Finished) - } -} - -func TestUpdateToStatusKilled(t *testing.T) { - t.Parallel() - - now := time.Now().Unix() - - build, _ := UpdateToStatusKilled(&mockUpdateBuildStore{}, model.Build{}) - - if model.StatusKilled != build.Status { - t.Errorf("Build status not equals '%s' != '%s'", model.StatusKilled, build.Status) - } else if now > build.Finished { - t.Errorf("Finished not updated %d !< %d", now, build.Finished) - } -} diff --git a/server/shared/configFetcher.go b/server/shared/configFetcher.go index 6d504c617..8a6de974a 100644 --- a/server/shared/configFetcher.go +++ b/server/shared/configFetcher.go @@ -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 shared import ( @@ -24,16 +38,16 @@ type configFetcher struct { remote remote.Remote user *model.User repo *model.Repo - build *model.Build + pipeline *model.Pipeline configExtension config.Extension } -func NewConfigFetcher(remote remote.Remote, configExtension config.Extension, user *model.User, repo *model.Repo, build *model.Build) ConfigFetcher { +func NewConfigFetcher(remote remote.Remote, configExtension config.Extension, user *model.User, repo *model.Repo, pipeline *model.Pipeline) ConfigFetcher { return &configFetcher{ remote: remote, user: user, repo: repo, - build: build, + pipeline: pipeline, configExtension: configExtension, } } @@ -60,7 +74,7 @@ func (cf *configFetcher) Fetch(ctx context.Context) (files []*remote.FileMeta, e defer cancel() // ok here as we only try http fetching once, returning on fail and success log.Trace().Msgf("ConfigFetch[%s]: getting config from external http service", cf.repo.FullName) - newConfigs, useOld, err := cf.configExtension.FetchConfig(fetchCtx, cf.repo, cf.build, files) + newConfigs, useOld, err := cf.configExtension.FetchConfig(fetchCtx, cf.repo, cf.pipeline, files) if err != nil { log.Error().Msg("Got error " + err.Error()) return nil, fmt.Errorf("On Fetching config via http : %s", err) @@ -86,7 +100,7 @@ func (cf *configFetcher) fetch(c context.Context, timeout time.Duration, config log.Trace().Msgf("ConfigFetch[%s]: use user config '%s'", cf.repo.FullName, config) // either a file if !strings.HasSuffix(config, "/") { - file, err := cf.remote.File(ctx, cf.user, cf.repo, cf.build, config) + file, err := cf.remote.File(ctx, cf.user, cf.repo, cf.pipeline, config) if err == nil && len(file) != 0 { log.Trace().Msgf("ConfigFetch[%s]: found file '%s'", cf.repo.FullName, config) return []*remote.FileMeta{{ @@ -97,7 +111,7 @@ func (cf *configFetcher) fetch(c context.Context, timeout time.Duration, config } // or a folder - files, err := cf.remote.Dir(ctx, cf.user, cf.repo, cf.build, strings.TrimSuffix(config, "/")) + files, err := cf.remote.Dir(ctx, cf.user, cf.repo, cf.pipeline, strings.TrimSuffix(config, "/")) if err == nil && len(files) != 0 { log.Trace().Msgf("ConfigFetch[%s]: found %d files in '%s'", cf.repo.FullName, len(files), config) return filterPipelineFiles(files), nil @@ -112,7 +126,7 @@ func (cf *configFetcher) fetch(c context.Context, timeout time.Duration, config // test .woodpecker/ folder // if folder is not supported we will get a "Not implemented" error and continue config = ".woodpecker" - files, err := cf.remote.Dir(ctx, cf.user, cf.repo, cf.build, config) + files, err := cf.remote.Dir(ctx, cf.user, cf.repo, cf.pipeline, config) files = filterPipelineFiles(files) if err == nil && len(files) != 0 { log.Trace().Msgf("ConfigFetch[%s]: found %d files in '%s'", cf.repo.FullName, len(files), config) @@ -120,7 +134,7 @@ func (cf *configFetcher) fetch(c context.Context, timeout time.Duration, config } config = ".woodpecker.yml" - file, err := cf.remote.File(ctx, cf.user, cf.repo, cf.build, config) + file, err := cf.remote.File(ctx, cf.user, cf.repo, cf.pipeline, config) if err == nil && len(file) != 0 { log.Trace().Msgf("ConfigFetch[%s]: found file '%s'", cf.repo.FullName, config) return []*remote.FileMeta{{ @@ -130,7 +144,7 @@ func (cf *configFetcher) fetch(c context.Context, timeout time.Duration, config } config = ".drone.yml" - file, err = cf.remote.File(ctx, cf.user, cf.repo, cf.build, config) + file, err = cf.remote.File(ctx, cf.user, cf.repo, cf.pipeline, config) if err == nil && len(file) != 0 { log.Trace().Msgf("ConfigFetch[%s]: found file '%s'", cf.repo.FullName, config) return []*remote.FileMeta{{ diff --git a/server/shared/configFetcher_test.go b/server/shared/configFetcher_test.go index fe61abb33..ff69cf53b 100644 --- a/server/shared/configFetcher_test.go +++ b/server/shared/configFetcher_test.go @@ -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 shared_test import ( @@ -250,7 +264,7 @@ func TestFetch(t *testing.T) { config.NewHTTP("", ""), &model.User{Token: "xxx"}, repo, - &model.Build{Commit: "89ab7b2d6bfb347144ac7c557e638ab402848fee"}, + &model.Pipeline{Commit: "89ab7b2d6bfb347144ac7c557e638ab402848fee"}, ) files, err := configFetcher.Fetch(context.Background()) if tt.expectedError && err == nil { @@ -376,9 +390,9 @@ func TestFetchFromConfigService(t *testing.T) { } type incoming struct { - Repo *model.Repo `json:"repo"` - Build *model.Build `json:"build"` - Configuration []*config `json:"config"` + Repo *model.Repo `json:"repo"` + Build *model.Pipeline `json:"build"` + Configuration []*config `json:"config"` } var req incoming @@ -455,7 +469,7 @@ func TestFetchFromConfigService(t *testing.T) { configAPI, &model.User{Token: "xxx"}, repo, - &model.Build{Commit: "89ab7b2d6bfb347144ac7c557e638ab402848fee"}, + &model.Pipeline{Commit: "89ab7b2d6bfb347144ac7c557e638ab402848fee"}, ) files, err := configFetcher.Fetch(context.Background()) if tt.expectedError && err == nil { diff --git a/server/shared/pipelineStatus.go b/server/shared/pipelineStatus.go new file mode 100644 index 000000000..1f1be0811 --- /dev/null +++ b/server/shared/pipelineStatus.go @@ -0,0 +1,64 @@ +// Copyright 2022 Woodpecker Authors +// Copyright 2019 mhmxs. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package shared + +import ( + "time" + + "github.com/woodpecker-ci/woodpecker/server/model" +) + +// TODO(974) move to server/pipeline/* + +func UpdateToStatusRunning(store model.UpdatePipelineStore, pipeline model.Pipeline, started int64) (*model.Pipeline, error) { + pipeline.Status = model.StatusRunning + pipeline.Started = started + return &pipeline, store.UpdatePipeline(&pipeline) +} + +func UpdateToStatusPending(store model.UpdatePipelineStore, pipeline model.Pipeline, reviewer string) (*model.Pipeline, error) { + pipeline.Reviewer = reviewer + pipeline.Status = model.StatusPending + pipeline.Reviewed = time.Now().Unix() + return &pipeline, store.UpdatePipeline(&pipeline) +} + +func UpdateToStatusDeclined(store model.UpdatePipelineStore, pipeline model.Pipeline, reviewer string) (*model.Pipeline, error) { + pipeline.Reviewer = reviewer + pipeline.Status = model.StatusDeclined + pipeline.Reviewed = time.Now().Unix() + return &pipeline, store.UpdatePipeline(&pipeline) +} + +func UpdateStatusToDone(store model.UpdatePipelineStore, pipeline model.Pipeline, status model.StatusValue, stopped int64) (*model.Pipeline, error) { + pipeline.Status = status + pipeline.Finished = stopped + return &pipeline, store.UpdatePipeline(&pipeline) +} + +func UpdateToStatusError(store model.UpdatePipelineStore, pipeline model.Pipeline, err error) (*model.Pipeline, error) { + pipeline.Error = err.Error() + pipeline.Status = model.StatusError + pipeline.Started = time.Now().Unix() + pipeline.Finished = pipeline.Started + return &pipeline, store.UpdatePipeline(&pipeline) +} + +func UpdateToStatusKilled(store model.UpdatePipelineStore, pipeline model.Pipeline) (*model.Pipeline, error) { + pipeline.Status = model.StatusKilled + pipeline.Finished = time.Now().Unix() + return &pipeline, store.UpdatePipeline(&pipeline) +} diff --git a/server/shared/pipelineStatus_test.go b/server/shared/pipelineStatus_test.go new file mode 100644 index 000000000..69002183a --- /dev/null +++ b/server/shared/pipelineStatus_test.go @@ -0,0 +1,120 @@ +// Copyright 2022 Woodpecker Authors +// Copyright 2019 mhmxs. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package shared + +import ( + "errors" + "testing" + "time" + + "github.com/woodpecker-ci/woodpecker/server/model" +) + +// TODO(974) move to server/pipeline/* + +type mockUpdatePipelineStore struct{} + +func (m *mockUpdatePipelineStore) UpdatePipeline(pipeline *model.Pipeline) error { + return nil +} + +func TestUpdateToStatusRunning(t *testing.T) { + t.Parallel() + + pipeline, _ := UpdateToStatusRunning(&mockUpdatePipelineStore{}, model.Pipeline{}, int64(1)) + + if model.StatusRunning != pipeline.Status { + t.Errorf("Pipeline status not equals '%s' != '%s'", model.StatusRunning, pipeline.Status) + } else if int64(1) != pipeline.Started { + t.Errorf("Pipeline started not equals 1 != %d", pipeline.Started) + } +} + +func TestUpdateToStatusPending(t *testing.T) { + t.Parallel() + + now := time.Now().Unix() + + pipeline, _ := UpdateToStatusPending(&mockUpdatePipelineStore{}, model.Pipeline{}, "Reviewer") + + if model.StatusPending != pipeline.Status { + t.Errorf("Pipeline status not equals '%s' != '%s'", model.StatusPending, pipeline.Status) + } else if pipeline.Reviewer != "Reviewer" { + t.Errorf("Reviewer not equals 'Reviewer' != '%s'", pipeline.Reviewer) + } else if now > pipeline.Reviewed { + t.Errorf("Reviewed not updated %d !< %d", now, pipeline.Reviewed) + } +} + +func TestUpdateToStatusDeclined(t *testing.T) { + t.Parallel() + + now := time.Now().Unix() + + pipeline, _ := UpdateToStatusDeclined(&mockUpdatePipelineStore{}, model.Pipeline{}, "Reviewer") + + if model.StatusDeclined != pipeline.Status { + t.Errorf("Pipeline status not equals '%s' != '%s'", model.StatusDeclined, pipeline.Status) + } else if pipeline.Reviewer != "Reviewer" { + t.Errorf("Reviewer not equals 'Reviewer' != '%s'", pipeline.Reviewer) + } else if now > pipeline.Reviewed { + t.Errorf("Reviewed not updated %d !< %d", now, pipeline.Reviewed) + } +} + +func TestUpdateToStatusToDone(t *testing.T) { + t.Parallel() + + pipeline, _ := UpdateStatusToDone(&mockUpdatePipelineStore{}, model.Pipeline{}, "status", int64(1)) + + if pipeline.Status != "status" { + t.Errorf("Pipeline status not equals 'status' != '%s'", pipeline.Status) + } else if int64(1) != pipeline.Finished { + t.Errorf("Pipeline finished not equals 1 != %d", pipeline.Finished) + } +} + +func TestUpdateToStatusError(t *testing.T) { + t.Parallel() + + now := time.Now().Unix() + + pipeline, _ := UpdateToStatusError(&mockUpdatePipelineStore{}, model.Pipeline{}, errors.New("error")) + + if pipeline.Error != "error" { + t.Errorf("Pipeline error not equals 'error' != '%s'", pipeline.Error) + } else if model.StatusError != pipeline.Status { + t.Errorf("Pipeline status not equals '%s' != '%s'", model.StatusError, pipeline.Status) + } else if now > pipeline.Started { + t.Errorf("Started not updated %d !< %d", now, pipeline.Started) + } else if pipeline.Started != pipeline.Finished { + t.Errorf("Pipeline started and finished not equals %d != %d", pipeline.Started, pipeline.Finished) + } +} + +func TestUpdateToStatusKilled(t *testing.T) { + t.Parallel() + + now := time.Now().Unix() + + pipeline, _ := UpdateToStatusKilled(&mockUpdatePipelineStore{}, model.Pipeline{}) + + if model.StatusKilled != pipeline.Status { + t.Errorf("Pipeline status not equals '%s' != '%s'", model.StatusKilled, pipeline.Status) + } else if now > pipeline.Finished { + t.Errorf("Finished not updated %d !< %d", now, pipeline.Finished) + } +} diff --git a/server/shared/procBuilder.go b/server/shared/procBuilder.go index a855a2634..dcc49a0f1 100644 --- a/server/shared/procBuilder.go +++ b/server/shared/procBuilder.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -41,8 +42,8 @@ import ( // ProcBuilder Takes the hook data and the yaml and returns in internal data model type ProcBuilder struct { Repo *model.Repo - Curr *model.Build - Last *model.Build + Curr *model.Pipeline + Last *model.Pipeline Netrc *model.Netrc Secs []*model.Secret Regs []*model.Registry @@ -51,7 +52,7 @@ type ProcBuilder struct { Envs map[string]string } -type BuildItem struct { +type PipelineItem struct { Proc *model.Proc Platform string Labels map[string]string @@ -60,8 +61,8 @@ type BuildItem struct { Config *backend.Config } -func (b *ProcBuilder) Build() ([]*BuildItem, error) { - var items []*BuildItem +func (b *ProcBuilder) Build() ([]*PipelineItem, error) { + var items []*PipelineItem sort.Sort(remote.ByName(b.Yamls)) @@ -79,12 +80,12 @@ func (b *ProcBuilder) Build() ([]*BuildItem, error) { for _, axis := range axes { proc := &model.Proc{ - BuildID: b.Curr.ID, - PID: pidSequence, - PGID: pidSequence, - State: model.StatusPending, - Environ: axis, - Name: SanitizePath(y.Name), + PipelineID: b.Curr.ID, + PID: pidSequence, + PGID: pidSequence, + State: model.StatusPending, + Environ: axis, + Name: SanitizePath(y.Name), } metadata := metadataFromStruct(b.Repo, b.Curr, b.Last, proc, b.Link) @@ -148,7 +149,7 @@ func (b *ProcBuilder) Build() ([]*BuildItem, error) { continue } - item := &BuildItem{ + item := &PipelineItem{ Proc: proc, Config: ir, Labels: parsed.Labels, @@ -168,15 +169,14 @@ func (b *ProcBuilder) Build() ([]*BuildItem, error) { items = filterItemsWithMissingDependencies(items) // check if at least one proc can start, if list is not empty - procListContainsItemsToRun(items) if len(items) > 0 && !procListContainsItemsToRun(items) { - return nil, fmt.Errorf("build has no startpoint") + return nil, fmt.Errorf("pipeline has no startpoint") } return items, nil } -func procListContainsItemsToRun(items []*BuildItem) bool { +func procListContainsItemsToRun(items []*PipelineItem) bool { for i := range items { if items[i].Proc.State == model.StatusPending { return true @@ -185,8 +185,8 @@ func procListContainsItemsToRun(items []*BuildItem) bool { return false } -func filterItemsWithMissingDependencies(items []*BuildItem) []*BuildItem { - itemsToRemove := make([]*BuildItem, 0) +func filterItemsWithMissingDependencies(items []*PipelineItem) []*PipelineItem { + itemsToRemove := make([]*PipelineItem, 0) for _, item := range items { for _, dep := range item.DependsOn { @@ -197,7 +197,7 @@ func filterItemsWithMissingDependencies(items []*BuildItem) []*BuildItem { } if len(itemsToRemove) > 0 { - filtered := make([]*BuildItem, 0) + filtered := make([]*PipelineItem, 0) for _, item := range items { if !containsItemWithName(item.Proc.Name, itemsToRemove) { filtered = append(filtered, item) @@ -210,7 +210,7 @@ func filterItemsWithMissingDependencies(items []*BuildItem) []*BuildItem { return items } -func containsItemWithName(name string, items []*BuildItem) bool { +func containsItemWithName(name string, items []*PipelineItem) bool { for _, item := range items { if name == item.Proc.Name { return true @@ -292,16 +292,16 @@ func (b *ProcBuilder) toInternalRepresentation(parsed *yaml.Config, environ map[ ).Compile(parsed) } -func SetBuildStepsOnBuild(build *model.Build, buildItems []*BuildItem) *model.Build { +func SetPipelineStepsOnPipeline(pipeline *model.Pipeline, pipelineItems []*PipelineItem) *model.Pipeline { var pidSequence int - for _, item := range buildItems { - build.Procs = append(build.Procs, item.Proc) + for _, item := range pipelineItems { + pipeline.Procs = append(pipeline.Procs, item.Proc) if pidSequence < item.Proc.PID { pidSequence = item.Proc.PID } } - for _, item := range buildItems { + for _, item := range pipelineItems { for _, stage := range item.Config.Stages { var gid int for _, step := range stage.Steps { @@ -310,26 +310,26 @@ func SetBuildStepsOnBuild(build *model.Build, buildItems []*BuildItem) *model.Bu gid = pidSequence } proc := &model.Proc{ - BuildID: build.ID, - Name: step.Alias, - PID: pidSequence, - PPID: item.Proc.PID, - PGID: gid, - State: model.StatusPending, + PipelineID: pipeline.ID, + Name: step.Alias, + PID: pidSequence, + PPID: item.Proc.PID, + PGID: gid, + State: model.StatusPending, } if item.Proc.State == model.StatusSkipped { proc.State = model.StatusSkipped } - build.Procs = append(build.Procs, proc) + pipeline.Procs = append(pipeline.Procs, proc) } } } - return build + return pipeline } // return the metadata from the cli context. -func metadataFromStruct(repo *model.Repo, build, last *model.Build, proc *model.Proc, link string) frontend.Metadata { +func metadataFromStruct(repo *model.Repo, pipeline, last *model.Pipeline, proc *model.Proc, link string) frontend.Metadata { host := link uri, err := url.Parse(link) if err == nil { @@ -343,8 +343,8 @@ func metadataFromStruct(repo *model.Repo, build, last *model.Build, proc *model. Private: repo.IsSCMPrivate, Branch: repo.Branch, }, - Curr: metadataBuildFromModelBuild(build, true), - Prev: metadataBuildFromModelBuild(last, false), + Curr: metadataPipelineFromModelPipeline(pipeline, true), + Prev: metadataPipelineFromModelPipeline(last, false), Job: frontend.Job{ Number: proc.PID, Matrix: proc.Environ, @@ -358,39 +358,39 @@ func metadataFromStruct(repo *model.Repo, build, last *model.Build, proc *model. } } -func metadataBuildFromModelBuild(build *model.Build, includeParent bool) frontend.Build { +func metadataPipelineFromModelPipeline(pipeline *model.Pipeline, includeParent bool) frontend.Pipeline { cron := "" - if build.Event == model.EventCron { - cron = build.Sender + if pipeline.Event == model.EventCron { + cron = pipeline.Sender } parent := int64(0) if includeParent { - parent = build.Parent + parent = pipeline.Parent } - return frontend.Build{ - Number: build.Number, + return frontend.Pipeline{ + Number: pipeline.Number, Parent: parent, - Created: build.Created, - Started: build.Started, - Finished: build.Finished, - Status: string(build.Status), - Event: string(build.Event), - Link: build.Link, - Target: build.Deploy, + Created: pipeline.Created, + Started: pipeline.Started, + Finished: pipeline.Finished, + Status: string(pipeline.Status), + Event: string(pipeline.Event), + Link: pipeline.Link, + Target: pipeline.Deploy, Commit: frontend.Commit{ - Sha: build.Commit, - Ref: build.Ref, - Refspec: build.Refspec, - Branch: build.Branch, - Message: build.Message, + Sha: pipeline.Commit, + Ref: pipeline.Ref, + Refspec: pipeline.Refspec, + Branch: pipeline.Branch, + Message: pipeline.Message, Author: frontend.Author{ - Name: build.Author, - Email: build.Email, - Avatar: build.Avatar, + Name: pipeline.Author, + Email: pipeline.Email, + Avatar: pipeline.Avatar, }, - ChangedFiles: build.ChangedFiles, + ChangedFiles: pipeline.ChangedFiles, }, Cron: cron, } diff --git a/server/shared/procBuilder_test.go b/server/shared/procBuilder_test.go index 56c8c3872..3603d6e28 100644 --- a/server/shared/procBuilder_test.go +++ b/server/shared/procBuilder_test.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -33,10 +34,10 @@ func TestGlobalEnvsubst(t *testing.T) { "IMAGE": "scratch", }, Repo: &model.Repo{}, - Curr: &model.Build{ + Curr: &model.Pipeline{ Message: "aaa", }, - Last: &model.Build{}, + Last: &model.Pipeline{}, Netrc: &model.Netrc{}, Secs: []*model.Secret{}, Regs: []*model.Registry{}, @@ -51,10 +52,10 @@ pipeline: }, } - if buildItems, err := b.Build(); err != nil { + if pipelineItems, err := b.Build(); err != nil { t.Fatal(err) } else { - fmt.Println(buildItems) + fmt.Println(pipelineItems) } } @@ -67,10 +68,10 @@ func TestMissingGlobalEnvsubst(t *testing.T) { "NO_IMAGE": "scratch", }, Repo: &model.Repo{}, - Curr: &model.Build{ + Curr: &model.Pipeline{ Message: "aaa", }, - Last: &model.Build{}, + Last: &model.Pipeline{}, Netrc: &model.Netrc{}, Secs: []*model.Secret{}, Regs: []*model.Registry{}, @@ -97,11 +98,11 @@ func TestMultilineEnvsubst(t *testing.T) { b := ProcBuilder{ Repo: &model.Repo{}, - Curr: &model.Build{ + Curr: &model.Pipeline{ Message: `aaa bbb`, }, - Last: &model.Build{}, + Last: &model.Pipeline{}, Netrc: &model.Netrc{}, Secs: []*model.Secret{}, Regs: []*model.Registry{}, @@ -122,10 +123,10 @@ pipeline: }, } - if buildItems, err := b.Build(); err != nil { + if pipelineItems, err := b.Build(); err != nil { t.Fatal(err) } else { - fmt.Println(buildItems) + fmt.Println(pipelineItems) } } @@ -134,8 +135,8 @@ func TestMultiPipeline(t *testing.T) { b := ProcBuilder{ Repo: &model.Repo{}, - Curr: &model.Build{}, - Last: &model.Build{}, + Curr: &model.Pipeline{}, + Last: &model.Pipeline{}, Netrc: &model.Netrc{}, Secs: []*model.Secret{}, Regs: []*model.Registry{}, @@ -154,12 +155,12 @@ pipeline: }, } - buildItems, err := b.Build() + pipelineItems, err := b.Build() if err != nil { t.Fatal(err) } - if len(buildItems) != 2 { - t.Fatal("Should have generated 2 buildItems") + if len(pipelineItems) != 2 { + t.Fatal("Should have generated 2 pipelineItems") } } @@ -168,8 +169,8 @@ func TestDependsOn(t *testing.T) { b := ProcBuilder{ Repo: &model.Repo{}, - Curr: &model.Build{}, - Last: &model.Build{}, + Curr: &model.Pipeline{}, + Last: &model.Pipeline{}, Netrc: &model.Netrc{}, Secs: []*model.Secret{}, Regs: []*model.Registry{}, @@ -197,14 +198,14 @@ depends_on: }, } - buildItems, err := b.Build() + pipelineItems, err := b.Build() if err != nil { t.Fatal(err) } - if len(buildItems[0].DependsOn) != 2 { + if len(pipelineItems[0].DependsOn) != 2 { t.Fatal("Should have 3 dependencies") } - if buildItems[0].DependsOn[1] != "test" { + if pipelineItems[0].DependsOn[1] != "test" { t.Fatal("Should depend on test") } } @@ -214,8 +215,8 @@ func TestRunsOn(t *testing.T) { b := ProcBuilder{ Repo: &model.Repo{}, - Curr: &model.Build{}, - Last: &model.Build{}, + Curr: &model.Pipeline{}, + Last: &model.Pipeline{}, Netrc: &model.Netrc{}, Secs: []*model.Secret{}, Regs: []*model.Registry{}, @@ -233,14 +234,14 @@ runs_on: }, } - buildItems, err := b.Build() + pipelineItems, err := b.Build() if err != nil { t.Fatal(err) } - if len(buildItems[0].RunsOn) != 2 { + if len(pipelineItems[0].RunsOn) != 2 { t.Fatal("Should run on success and failure") } - if buildItems[0].RunsOn[1] != "failure" { + if pipelineItems[0].RunsOn[1] != "failure" { t.Fatal("Should run on failure") } } @@ -250,8 +251,8 @@ func TestPipelineName(t *testing.T) { b := ProcBuilder{ Repo: &model.Repo{Config: ".woodpecker"}, - Curr: &model.Build{}, - Last: &model.Build{}, + Curr: &model.Pipeline{}, + Last: &model.Pipeline{}, Netrc: &model.Netrc{}, Secs: []*model.Secret{}, Regs: []*model.Registry{}, @@ -270,12 +271,12 @@ pipeline: }, } - buildItems, err := b.Build() + pipelineItems, err := b.Build() if err != nil { t.Fatal(err) } - pipelineNames := []string{buildItems[0].Proc.Name, buildItems[1].Proc.Name} - if !containsItemWithName("lint", buildItems) || !containsItemWithName("test", buildItems) { + pipelineNames := []string{pipelineItems[0].Proc.Name, pipelineItems[1].Proc.Name} + if !containsItemWithName("lint", pipelineItems) || !containsItemWithName("test", pipelineItems) { t.Fatalf("Pipeline name should be 'lint' and 'test' but are '%v'", pipelineNames) } } @@ -285,8 +286,8 @@ func TestBranchFilter(t *testing.T) { b := ProcBuilder{ Repo: &model.Repo{}, - Curr: &model.Build{Branch: "dev"}, - Last: &model.Build{}, + Curr: &model.Pipeline{Branch: "dev"}, + Last: &model.Pipeline{}, Netrc: &model.Netrc{}, Secs: []*model.Secret{}, Regs: []*model.Registry{}, @@ -306,22 +307,22 @@ pipeline: }, } - buildItems, err := b.Build() + pipelineItems, err := b.Build() if err != nil { t.Fatal(err) } - if len(buildItems) != 2 { - t.Fatal("Should have generated 2 buildItems") + if len(pipelineItems) != 2 { + t.Fatal("Should have generated 2 pipeline") } - if buildItems[0].Proc.State != model.StatusSkipped { + if pipelineItems[0].Proc.State != model.StatusSkipped { t.Fatal("Should not run on dev branch") } - for _, child := range buildItems[0].Proc.Children { + for _, child := range pipelineItems[0].Proc.Children { if child.State != model.StatusSkipped { t.Fatal("Children should skipped status too") } } - if buildItems[1].Proc.State != model.StatusPending { + if pipelineItems[1].Proc.State != model.StatusPending { t.Fatal("Should run on dev branch") } } @@ -331,8 +332,8 @@ func TestRootWhenFilter(t *testing.T) { b := ProcBuilder{ Repo: &model.Repo{}, - Curr: &model.Build{Event: "tester"}, - Last: &model.Build{}, + Curr: &model.Pipeline{Event: "tester"}, + Last: &model.Pipeline{}, Netrc: &model.Netrc{}, Secs: []*model.Secret{}, Regs: []*model.Registry{}, @@ -362,25 +363,25 @@ pipeline: }, } - buildItems, err := b.Build() + pipelineItems, err := b.Build() if err != nil { t.Fatal(err) } - if len(buildItems) != 2 { - t.Fatal("Should have generated 2 buildItems") + if len(pipelineItems) != 2 { + t.Fatal("Should have generated 2 pipelineItems") } } func TestZeroSteps(t *testing.T) { t.Parallel() - build := &model.Build{Branch: "dev"} + pipeline := &model.Pipeline{Branch: "dev"} b := ProcBuilder{ Repo: &model.Repo{}, - Curr: build, - Last: &model.Build{}, + Curr: pipeline, + Last: &model.Pipeline{}, Netrc: &model.Netrc{}, Secs: []*model.Secret{}, Regs: []*model.Registry{}, @@ -397,24 +398,24 @@ pipeline: }, } - buildItems, err := b.Build() + pipelineItems, err := b.Build() if err != nil { t.Fatal(err) } - if len(buildItems) != 0 { - t.Fatal("Should not generate a build item if there are no steps") + if len(pipelineItems) != 0 { + t.Fatal("Should not generate a pipeline item if there are no steps") } } func TestZeroStepsAsMultiPipelineDeps(t *testing.T) { t.Parallel() - build := &model.Build{Branch: "dev"} + pipeline := &model.Pipeline{Branch: "dev"} b := ProcBuilder{ Repo: &model.Repo{}, - Curr: build, - Last: &model.Build{}, + Curr: pipeline, + Last: &model.Pipeline{}, Netrc: &model.Netrc{}, Secs: []*model.Secret{}, Regs: []*model.Registry{}, @@ -442,14 +443,14 @@ depends_on: [ zerostep ] }, } - buildItems, err := b.Build() + pipelineItems, err := b.Build() if err != nil { t.Fatal(err) } - if len(buildItems) != 1 { - t.Fatal("Zerostep and the step that depends on it should not generate a build item") + if len(pipelineItems) != 1 { + t.Fatal("Zerostep and the step that depends on it should not generate a pipeline item") } - if buildItems[0].Proc.Name != "justastep" { + if pipelineItems[0].Proc.Name != "justastep" { t.Fatal("justastep should have been generated") } } @@ -457,12 +458,12 @@ depends_on: [ zerostep ] func TestZeroStepsAsMultiPipelineTransitiveDeps(t *testing.T) { t.Parallel() - build := &model.Build{Branch: "dev"} + pipeline := &model.Pipeline{Branch: "dev"} b := ProcBuilder{ Repo: &model.Repo{}, - Curr: build, - Last: &model.Build{}, + Curr: pipeline, + Last: &model.Pipeline{}, Netrc: &model.Netrc{}, Secs: []*model.Secret{}, Regs: []*model.Registry{}, @@ -496,14 +497,14 @@ depends_on: [ shouldbefiltered ] }, } - buildItems, err := b.Build() + pipelineItems, err := b.Build() if err != nil { t.Fatal(err) } - if len(buildItems) != 1 { - t.Fatal("Zerostep and the step that depends on it, and the one depending on it should not generate a build item") + if len(pipelineItems) != 1 { + t.Fatal("Zerostep and the step that depends on it, and the one depending on it should not generate a pipeline item") } - if buildItems[0].Proc.Name != "justastep" { + if pipelineItems[0].Proc.Name != "justastep" { t.Fatal("justastep should have been generated") } } @@ -511,14 +512,14 @@ depends_on: [ shouldbefiltered ] func TestTree(t *testing.T) { t.Parallel() - build := &model.Build{ + pipeline := &model.Pipeline{ Event: model.EventPush, } b := ProcBuilder{ Repo: &model.Repo{}, - Curr: build, - Last: &model.Build{}, + Curr: pipeline, + Last: &model.Pipeline{}, Netrc: &model.Netrc{}, Secs: []*model.Secret{}, Regs: []*model.Registry{}, @@ -532,19 +533,19 @@ pipeline: }, } - buildItems, err := b.Build() - build = SetBuildStepsOnBuild(build, buildItems) + pipelineItems, err := b.Build() + pipeline = SetPipelineStepsOnPipeline(pipeline, pipelineItems) if err != nil { t.Fatal(err) } - if len(build.Procs) != 3 { + if len(pipeline.Procs) != 3 { t.Fatal("Should generate three in total") } - if build.Procs[1].PPID != 1 { + if pipeline.Procs[1].PPID != 1 { t.Fatal("Clone step should be a children of the stage") } - if build.Procs[2].PPID != 1 { - t.Fatal("Build step should be a children of the stage") + if pipeline.Procs[2].PPID != 1 { + t.Fatal("Pipeline step should be a children of the stage") } } diff --git a/server/shared/userSyncer.go b/server/shared/userSyncer.go index 1a0c20b05..bd5636a3f 100644 --- a/server/shared/userSyncer.go +++ b/server/shared/userSyncer.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/server/store/datastore/build.go b/server/store/datastore/build.go deleted file mode 100644 index 2664282dd..000000000 --- a/server/store/datastore/build.go +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright 2021 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 datastore - -import ( - "time" - - "xorm.io/xorm" - - "github.com/woodpecker-ci/woodpecker/server/model" -) - -func (s storage) GetBuild(id int64) (*model.Build, error) { - build := &model.Build{} - return build, wrapGet(s.engine.ID(id).Get(build)) -} - -func (s storage) GetBuildNumber(repo *model.Repo, num int64) (*model.Build, error) { - build := &model.Build{ - RepoID: repo.ID, - Number: num, - } - return build, wrapGet(s.engine.Get(build)) -} - -func (s storage) GetBuildRef(repo *model.Repo, ref string) (*model.Build, error) { - build := &model.Build{ - RepoID: repo.ID, - Ref: ref, - } - return build, wrapGet(s.engine.Get(build)) -} - -func (s storage) GetBuildCommit(repo *model.Repo, sha, branch string) (*model.Build, error) { - build := &model.Build{ - RepoID: repo.ID, - Branch: branch, - Commit: sha, - } - return build, wrapGet(s.engine.Get(build)) -} - -func (s storage) GetBuildLast(repo *model.Repo, branch string) (*model.Build, error) { - build := &model.Build{ - RepoID: repo.ID, - Branch: branch, - Event: model.EventPush, - } - return build, wrapGet(s.engine.Desc("build_number").Get(build)) -} - -func (s storage) GetBuildLastBefore(repo *model.Repo, branch string, num int64) (*model.Build, error) { - build := &model.Build{ - RepoID: repo.ID, - Branch: branch, - } - return build, wrapGet(s.engine. - Desc("build_number"). - Where("build_id < ?", num). - Get(build)) -} - -func (s storage) GetBuildList(repo *model.Repo, page int) ([]*model.Build, error) { - builds := make([]*model.Build, 0, perPage) - return builds, s.engine.Where("build_repo_id = ?", repo.ID). - Desc("build_number"). - Limit(perPage, perPage*(page-1)). - Find(&builds) -} - -// GetActiveBuildList get all builds that are pending, running or blocked -func (s storage) GetActiveBuildList(repo *model.Repo, page int) ([]*model.Build, error) { - builds := make([]*model.Build, 0, perPage) - query := s.engine. - Where("build_repo_id = ?", repo.ID). - In("build_status", model.StatusPending, model.StatusRunning, model.StatusBlocked). - Desc("build_number") - if page > 0 { - query = query.Limit(perPage, perPage*(page-1)) - } - return builds, query.Find(&builds) -} - -func (s storage) GetBuildCount() (int64, error) { - return s.engine.Count(new(model.Build)) -} - -func (s storage) CreateBuild(build *model.Build, procList ...*model.Proc) error { - sess := s.engine.NewSession() - defer sess.Close() - if err := sess.Begin(); err != nil { - return err - } - - // calc build number - var number int64 - if _, err := sess.SQL("SELECT MAX(build_number) FROM `builds` WHERE build_repo_id = ?", build.RepoID).Get(&number); err != nil { - return err - } - build.Number = number + 1 - - build.Created = time.Now().UTC().Unix() - build.Enqueued = build.Created - // only Insert set auto created ID back to object - if _, err := sess.Insert(build); err != nil { - return err - } - - for i := range procList { - procList[i].BuildID = build.ID - // only Insert set auto created ID back to object - if _, err := sess.Insert(procList[i]); err != nil { - return err - } - } - - return sess.Commit() -} - -func (s storage) UpdateBuild(build *model.Build) error { - _, err := s.engine.ID(build.ID).AllCols().Update(build) - return err -} - -func deleteBuild(sess *xorm.Session, buildID int64) error { - // delete related procs - for startProcs := 0; ; startProcs += perPage { - procIDs := make([]int64, 0, perPage) - if err := sess.Limit(perPage, startProcs).Table("procs").Cols("proc_id").Where("proc_build_id = ?", buildID).Find(&procIDs); err != nil { - return err - } - if len(procIDs) == 0 { - break - } - - for i := range procIDs { - if err := deleteProc(sess, procIDs[i]); err != nil { - return err - } - } - } - if _, err := sess.Where("build_id = ?", buildID).Delete(new(model.BuildConfig)); err != nil { - return err - } - _, err := sess.ID(buildID).Delete(new(model.Build)) - return err -} diff --git a/server/store/datastore/build_test.go b/server/store/datastore/build_test.go deleted file mode 100644 index 20d673b7d..000000000 --- a/server/store/datastore/build_test.go +++ /dev/null @@ -1,307 +0,0 @@ -// Copyright 2018 Drone.IO Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// 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 datastore - -import ( - "fmt" - "testing" - - "github.com/franela/goblin" - "github.com/stretchr/testify/assert" - - "github.com/woodpecker-ci/woodpecker/server/model" -) - -func TestBuilds(t *testing.T) { - repo := &model.Repo{ - UserID: 1, - FullName: "bradrydzewski/test", - Owner: "bradrydzewski", - Name: "test", - } - - store, closer := newTestStore(t, new(model.Repo), new(model.Proc), new(model.Build)) - defer closer() - - g := goblin.Goblin(t) - g.Describe("Builds", func() { - g.Before(func() { - _, err := store.engine.Exec("DELETE FROM repos") - g.Assert(err).IsNil() - g.Assert(store.CreateRepo(repo)).IsNil() - }) - g.After(func() { - _, err := store.engine.Exec("DELETE FROM repos") - g.Assert(err).IsNil() - }) - - // before each test be sure to purge the package - // table data from the database. - g.BeforeEach(func() { - _, err := store.engine.Exec("DELETE FROM builds") - g.Assert(err).IsNil() - _, err = store.engine.Exec("DELETE FROM procs") - g.Assert(err).IsNil() - }) - - g.It("Should Post a Build", func() { - build := model.Build{ - RepoID: repo.ID, - Status: model.StatusSuccess, - Commit: "85f8c029b902ed9400bc600bac301a0aadb144ac", - } - err := store.CreateBuild(&build) - g.Assert(err).IsNil() - g.Assert(build.ID != 0).IsTrue() - g.Assert(build.Number).Equal(int64(1)) - g.Assert(build.Commit).Equal("85f8c029b902ed9400bc600bac301a0aadb144ac") - - count, err := store.GetBuildCount() - g.Assert(err).IsNil() - g.Assert(count > 0).IsTrue() - fmt.Println("GOT COUNT", count) - }) - - g.It("Should Put a Build", func() { - build := model.Build{ - RepoID: repo.ID, - Number: 5, - Status: model.StatusSuccess, - Commit: "85f8c029b902ed9400bc600bac301a0aadb144ac", - } - err := store.CreateBuild(&build) - g.Assert(err).IsNil() - build.Status = model.StatusRunning - err1 := store.UpdateBuild(&build) - getbuild, err2 := store.GetBuild(build.ID) - g.Assert(err1).IsNil() - g.Assert(err2).IsNil() - g.Assert(build.ID).Equal(getbuild.ID) - g.Assert(build.RepoID).Equal(getbuild.RepoID) - g.Assert(build.Status).Equal(getbuild.Status) - g.Assert(build.Number).Equal(getbuild.Number) - }) - - g.It("Should Get a Build", func() { - build := model.Build{ - RepoID: repo.ID, - Status: model.StatusSuccess, - } - err := store.CreateBuild(&build, []*model.Proc{}...) - g.Assert(err).IsNil() - getbuild, err := store.GetBuild(build.ID) - g.Assert(err).IsNil() - g.Assert(build.ID).Equal(getbuild.ID) - g.Assert(build.RepoID).Equal(getbuild.RepoID) - g.Assert(build.Status).Equal(getbuild.Status) - }) - - g.It("Should Get a Build by Number", func() { - build1 := &model.Build{ - RepoID: repo.ID, - Status: model.StatusPending, - } - build2 := &model.Build{ - RepoID: repo.ID, - Status: model.StatusPending, - } - err1 := store.CreateBuild(build1, []*model.Proc{}...) - g.Assert(err1).IsNil() - err2 := store.CreateBuild(build2, []*model.Proc{}...) - g.Assert(err2).IsNil() - getbuild, err3 := store.GetBuildNumber(&model.Repo{ID: 1}, build2.Number) - g.Assert(err3).IsNil() - g.Assert(build2.ID).Equal(getbuild.ID) - g.Assert(build2.RepoID).Equal(getbuild.RepoID) - g.Assert(build2.Number).Equal(getbuild.Number) - }) - - g.It("Should Get a Build by Ref", func() { - build1 := &model.Build{ - RepoID: repo.ID, - Status: model.StatusPending, - Ref: "refs/pull/5", - } - build2 := &model.Build{ - RepoID: repo.ID, - Status: model.StatusPending, - Ref: "refs/pull/6", - } - err1 := store.CreateBuild(build1, []*model.Proc{}...) - g.Assert(err1).IsNil() - err2 := store.CreateBuild(build2, []*model.Proc{}...) - g.Assert(err2).IsNil() - getbuild, err3 := store.GetBuildRef(&model.Repo{ID: 1}, "refs/pull/6") - g.Assert(err3).IsNil() - g.Assert(build2.ID).Equal(getbuild.ID) - g.Assert(build2.RepoID).Equal(getbuild.RepoID) - g.Assert(build2.Number).Equal(getbuild.Number) - g.Assert(build2.Ref).Equal(getbuild.Ref) - }) - - g.It("Should Get a Build by Ref", func() { - build1 := &model.Build{ - RepoID: repo.ID, - Status: model.StatusPending, - Ref: "refs/pull/5", - } - build2 := &model.Build{ - RepoID: repo.ID, - Status: model.StatusPending, - Ref: "refs/pull/6", - } - err1 := store.CreateBuild(build1, []*model.Proc{}...) - g.Assert(err1).IsNil() - err2 := store.CreateBuild(build2, []*model.Proc{}...) - g.Assert(err2).IsNil() - getbuild, err3 := store.GetBuildRef(&model.Repo{ID: 1}, "refs/pull/6") - g.Assert(err3).IsNil() - g.Assert(build2.ID).Equal(getbuild.ID) - g.Assert(build2.RepoID).Equal(getbuild.RepoID) - g.Assert(build2.Number).Equal(getbuild.Number) - g.Assert(build2.Ref).Equal(getbuild.Ref) - }) - - g.It("Should Get a Build by Commit", func() { - build1 := &model.Build{ - RepoID: repo.ID, - Status: model.StatusPending, - Branch: "master", - Commit: "85f8c029b902ed9400bc600bac301a0aadb144ac", - } - build2 := &model.Build{ - RepoID: repo.ID, - Status: model.StatusPending, - Branch: "dev", - Commit: "85f8c029b902ed9400bc600bac301a0aadb144aa", - } - err1 := store.CreateBuild(build1, []*model.Proc{}...) - g.Assert(err1).IsNil() - err2 := store.CreateBuild(build2, []*model.Proc{}...) - g.Assert(err2).IsNil() - getbuild, err3 := store.GetBuildCommit(&model.Repo{ID: 1}, build2.Commit, build2.Branch) - g.Assert(err3).IsNil() - g.Assert(build2.ID).Equal(getbuild.ID) - g.Assert(build2.RepoID).Equal(getbuild.RepoID) - g.Assert(build2.Number).Equal(getbuild.Number) - g.Assert(build2.Commit).Equal(getbuild.Commit) - g.Assert(build2.Branch).Equal(getbuild.Branch) - }) - - g.It("Should Get the last Build", func() { - build1 := &model.Build{ - RepoID: repo.ID, - Status: model.StatusFailure, - Branch: "master", - Commit: "85f8c029b902ed9400bc600bac301a0aadb144ac", - Event: model.EventPush, - } - build2 := &model.Build{ - RepoID: repo.ID, - Status: model.StatusSuccess, - Branch: "master", - Commit: "85f8c029b902ed9400bc600bac301a0aadb144aa", - Event: model.EventPush, - } - err1 := store.CreateBuild(build1, []*model.Proc{}...) - err2 := store.CreateBuild(build2, []*model.Proc{}...) - getbuild, err3 := store.GetBuildLast(&model.Repo{ID: 1}, build2.Branch) - g.Assert(err1).IsNil() - g.Assert(err2).IsNil() - g.Assert(err3).IsNil() - g.Assert(build2.ID).Equal(getbuild.ID) - g.Assert(build2.RepoID).Equal(getbuild.RepoID) - g.Assert(build2.Number).Equal(getbuild.Number) - g.Assert(build2.Status).Equal(getbuild.Status) - g.Assert(build2.Branch).Equal(getbuild.Branch) - g.Assert(build2.Commit).Equal(getbuild.Commit) - }) - - g.It("Should Get the last Build Before Build N", func() { - build1 := &model.Build{ - RepoID: repo.ID, - Status: model.StatusFailure, - Branch: "master", - Commit: "85f8c029b902ed9400bc600bac301a0aadb144ac", - } - build2 := &model.Build{ - RepoID: repo.ID, - Status: model.StatusSuccess, - Branch: "master", - Commit: "85f8c029b902ed9400bc600bac301a0aadb144aa", - } - build3 := &model.Build{ - RepoID: repo.ID, - Status: model.StatusRunning, - Branch: "master", - Commit: "85f8c029b902ed9400bc600bac301a0aadb144aa", - } - err1 := store.CreateBuild(build1, []*model.Proc{}...) - g.Assert(err1).IsNil() - err2 := store.CreateBuild(build2, []*model.Proc{}...) - g.Assert(err2).IsNil() - err3 := store.CreateBuild(build3, []*model.Proc{}...) - g.Assert(err3).IsNil() - getbuild, err4 := store.GetBuildLastBefore(&model.Repo{ID: 1}, build3.Branch, build3.ID) - g.Assert(err4).IsNil() - g.Assert(build2.ID).Equal(getbuild.ID) - g.Assert(build2.RepoID).Equal(getbuild.RepoID) - g.Assert(build2.Number).Equal(getbuild.Number) - g.Assert(build2.Status).Equal(getbuild.Status) - g.Assert(build2.Branch).Equal(getbuild.Branch) - g.Assert(build2.Commit).Equal(getbuild.Commit) - }) - - g.It("Should get recent Builds", func() { - build1 := &model.Build{ - RepoID: repo.ID, - Status: model.StatusFailure, - } - build2 := &model.Build{ - RepoID: repo.ID, - Status: model.StatusSuccess, - } - err1 := store.CreateBuild(build1, []*model.Proc{}...) - g.Assert(err1).IsNil() - err2 := store.CreateBuild(build2, []*model.Proc{}...) - g.Assert(err2).IsNil() - builds, err3 := store.GetBuildList(&model.Repo{ID: 1}, 1) - g.Assert(err3).IsNil() - g.Assert(len(builds)).Equal(2) - g.Assert(builds[0].ID).Equal(build2.ID) - g.Assert(builds[0].RepoID).Equal(build2.RepoID) - g.Assert(builds[0].Status).Equal(build2.Status) - }) - }) -} - -func TestBuildIncrement(t *testing.T) { - store, closer := newTestStore(t, new(model.Build)) - defer closer() - - buildA := &model.Build{RepoID: 1} - if !assert.NoError(t, store.CreateBuild(buildA)) { - return - } - assert.EqualValues(t, 1, buildA.Number) - - buildB := &model.Build{RepoID: 1} - assert.NoError(t, store.CreateBuild(buildB)) - assert.EqualValues(t, 2, buildB.Number) - - buildC := &model.Build{RepoID: 2} - assert.NoError(t, store.CreateBuild(buildC)) - assert.EqualValues(t, 1, buildC.Number) -} diff --git a/server/store/datastore/config.go b/server/store/datastore/config.go index 6de2dc24a..505a63e69 100644 --- a/server/store/datastore/config.go +++ b/server/store/datastore/config.go @@ -18,12 +18,12 @@ import ( "github.com/woodpecker-ci/woodpecker/server/model" ) -func (s storage) ConfigsForBuild(buildID int64) ([]*model.Config, error) { +func (s storage) ConfigsForPipeline(pipelineID int64) ([]*model.Config, error) { configs := make([]*model.Config, 0, perPage) return configs, s.engine. Table("config"). - Join("LEFT", "build_config", "config.config_id = build_config.config_id"). - Where("build_config.build_id = ?", buildID). + Join("LEFT", "pipeline_config", "config.config_id = pipeline_config.config_id"). + Where("pipeline_config.build_id = ?", pipelineID). Find(&configs) } @@ -40,21 +40,21 @@ func (s storage) ConfigFindIdentical(repoID int64, hash string) (*model.Config, func (s storage) ConfigFindApproved(config *model.Config) (bool, error) { /* TODO: use builder (do not behave same as pure sql, fix that) - return s.engine.Table(new(model.Build)). - Join("INNER", "build_config", "builds.build_id = build_config.build_id" ). - Where(builder.Eq{"builds.build_repo_id": config.RepoID}). - And(builder.Eq{"build_config.config_id": config.ID}). - And(builder.In("builds.build_status", "blocked", "pending")). - Exist(new(model.Build)) + return s.engine.Table(new(model.Pipeline)). + Join("INNER", "pipeline_config", "pipelines.build_id = pipeline_config.build_id" ). + Where(builder.Eq{"pipelines.build_repo_id": config.RepoID}). + And(builder.Eq{"pipeline_config.config_id": config.ID}). + And(builder.In("pipelines.build_status", "blocked", "pending")). + Exist(new(model.Pipeline)) */ c, err := s.engine.SQL(` -SELECT build_id FROM builds +SELECT build_id FROM pipelines WHERE build_repo_id = ? AND build_id in ( SELECT build_id -FROM build_config -WHERE build_config.config_id = ? +FROM pipeline_config +WHERE pipeline_config.config_id = ? ) AND build_status NOT IN ('blocked', 'pending') LIMIT 1 @@ -68,7 +68,7 @@ func (s storage) ConfigCreate(config *model.Config) error { return err } -func (s storage) BuildConfigCreate(config *model.BuildConfig) error { +func (s storage) PipelineConfigCreate(config *model.PipelineConfig) error { // only Insert set auto created ID back to object _, err := s.engine.Insert(config) return err diff --git a/server/store/datastore/config_test.go b/server/store/datastore/config_test.go index 638f3d566..b7830495b 100644 --- a/server/store/datastore/config_test.go +++ b/server/store/datastore/config_test.go @@ -23,7 +23,7 @@ import ( ) func TestConfig(t *testing.T) { - store, closer := newTestStore(t, new(model.Config), new(model.BuildConfig), new(model.Build), new(model.Repo)) + store, closer := newTestStore(t, new(model.Config), new(model.PipelineConfig), new(model.Pipeline), new(model.Repo)) defer closer() var ( @@ -53,23 +53,23 @@ func TestConfig(t *testing.T) { return } - build := &model.Build{ + pipeline := &model.Pipeline{ RepoID: repo.ID, Status: model.StatusRunning, Commit: "85f8c029b902ed9400bc600bac301a0aadb144ac", } - if err := store.CreateBuild(build); err != nil { - t.Errorf("Unexpected error: insert build: %s", err) + if err := store.CreatePipeline(pipeline); err != nil { + t.Errorf("Unexpected error: insert pipeline: %s", err) return } - if err := store.BuildConfigCreate( - &model.BuildConfig{ - ConfigID: config.ID, - BuildID: build.ID, + if err := store.PipelineConfigCreate( + &model.PipelineConfig{ + ConfigID: config.ID, + PipelineID: pipeline.ID, }, ); err != nil { - t.Errorf("Unexpected error: insert build config: %s", err) + t.Errorf("Unexpected error: insert pipeline config: %s", err) return } @@ -94,7 +94,7 @@ func TestConfig(t *testing.T) { t.Errorf("Want config name %s, got %s", want, got) } - loaded, err := store.ConfigsForBuild(build.ID) + loaded, err := store.ConfigsForPipeline(pipeline.ID) if err != nil { t.Errorf("Want config by id, got error %q", err) return @@ -105,7 +105,7 @@ func TestConfig(t *testing.T) { } func TestConfigApproved(t *testing.T) { - store, closer := newTestStore(t, new(model.Config), new(model.BuildConfig), new(model.Build), new(model.Repo)) + store, closer := newTestStore(t, new(model.Config), new(model.PipelineConfig), new(model.Pipeline), new(model.Repo)) defer closer() repo := &model.Repo{ @@ -120,31 +120,31 @@ func TestConfigApproved(t *testing.T) { } var ( - data = "pipeline: [ { image: golang, commands: [ go build, go test ] } ]" - hash = "8d8647c9aa90d893bfb79dddbe901f03e258588121e5202632f8ae5738590b26" - buildBlocked = &model.Build{ + data = "pipeline: [ { image: golang, commands: [ go build, go test ] } ]" + hash = "8d8647c9aa90d893bfb79dddbe901f03e258588121e5202632f8ae5738590b26" + pipelineBlocked = &model.Pipeline{ RepoID: repo.ID, Status: model.StatusBlocked, Commit: "85f8c029b902ed9400bc600bac301a0aadb144ac", } - buildPending = &model.Build{ + pipelinePending = &model.Pipeline{ RepoID: repo.ID, Status: model.StatusPending, Commit: "85f8c029b902ed9400bc600bac301a0aadb144ac", } - buildRunning = &model.Build{ + pipelineRunning = &model.Pipeline{ RepoID: repo.ID, Status: model.StatusRunning, Commit: "85f8c029b902ed9400bc600bac301a0aadb144ac", } ) - if err := store.CreateBuild(buildBlocked); err != nil { - t.Errorf("Unexpected error: insert build: %s", err) + if err := store.CreatePipeline(pipelineBlocked); err != nil { + t.Errorf("Unexpected error: insert pipeline: %s", err) return } - if err := store.CreateBuild(buildPending); err != nil { - t.Errorf("Unexpected error: insert build: %s", err) + if err := store.CreatePipeline(pipelinePending); err != nil { + t.Errorf("Unexpected error: insert pipeline: %s", err) return } conf := &model.Config{ @@ -156,12 +156,12 @@ func TestConfigApproved(t *testing.T) { t.Errorf("Unexpected error: insert config: %s", err) return } - buildConfig := &model.BuildConfig{ - ConfigID: conf.ID, - BuildID: buildBlocked.ID, + pipelineConfig := &model.PipelineConfig{ + ConfigID: conf.ID, + PipelineID: pipelineBlocked.ID, } - if err := store.BuildConfigCreate(buildConfig); err != nil { - t.Errorf("Unexpected error: insert build_config: %s", err) + if err := store.PipelineConfigCreate(pipelineConfig); err != nil { + t.Errorf("Unexpected error: insert pipeline_config: %s", err) return } @@ -174,7 +174,7 @@ func TestConfigApproved(t *testing.T) { return } - assert.NoError(t, store.CreateBuild(buildRunning)) + assert.NoError(t, store.CreatePipeline(pipelineRunning)) conf2 := &model.Config{ RepoID: repo.ID, Data: []byte(data), @@ -184,11 +184,11 @@ func TestConfigApproved(t *testing.T) { t.Errorf("Unexpected error: insert config: %s", err) return } - buildConfig2 := &model.BuildConfig{ - ConfigID: conf2.ID, - BuildID: buildRunning.ID, + pipelineConfig2 := &model.PipelineConfig{ + ConfigID: conf2.ID, + PipelineID: pipelineRunning.ID, } - if err := store.BuildConfigCreate(buildConfig2); err != nil { + if err := store.PipelineConfigCreate(pipelineConfig2); err != nil { t.Errorf("Unexpected error: insert config: %s", err) return } @@ -200,7 +200,7 @@ func TestConfigApproved(t *testing.T) { } func TestConfigIndexes(t *testing.T) { - store, closer := newTestStore(t, new(model.Config), new(model.Proc), new(model.Build), new(model.Repo)) + store, closer := newTestStore(t, new(model.Config), new(model.Proc), new(model.Pipeline), new(model.Repo)) defer closer() var ( diff --git a/server/store/datastore/feed.go b/server/store/datastore/feed.go index ecc1990a2..27ecaca81 100644 --- a/server/store/datastore/feed.go +++ b/server/store/datastore/feed.go @@ -19,7 +19,7 @@ import ( ) // TODO: need tests before converting to builder statement -func (s storage) GetBuildQueue() ([]*model.Feed, error) { +func (s storage) GetPipelineQueue() ([]*model.Feed, error) { feed := make([]*model.Feed, 0, perPage) // TODO: use builder (do not behave same as pure sql, fix that) err := s.engine.SQL(` @@ -44,10 +44,10 @@ SELECT ,build_email ,build_avatar FROM - builds b + pipelines p ,repos r -WHERE b.build_repo_id = r.repo_id - AND b.build_status IN ('pending','running') +WHERE p.build_repo_id = r.repo_id + AND p.build_status IN ('pending','running') `).Find(&feed) return feed, err } @@ -78,7 +78,7 @@ SELECT ,build_avatar FROM repos INNER JOIN perms ON perms.perm_repo_id = repos.repo_id -INNER JOIN builds ON builds.build_repo_id = repos.repo_id +INNER JOIN pipelines ON pipelines.build_repo_id = repos.repo_id WHERE perms.perm_user_id = ? AND (perms.perm_push = ? OR perms.perm_admin = ?) ORDER BY build_id DESC @@ -110,9 +110,9 @@ SELECT ,build_author ,build_email ,build_avatar -FROM repos LEFT OUTER JOIN builds ON build_id = ( - SELECT build_id FROM builds - WHERE builds.build_repo_id = repos.repo_id +FROM repos LEFT OUTER JOIN pipelines ON build_id = ( + SELECT build_id FROM pipelines + WHERE pipelines.build_repo_id = repos.repo_id ORDER BY build_id DESC LIMIT 1 ) diff --git a/server/store/datastore/feed_test.go b/server/store/datastore/feed_test.go index 878a566b1..1669786cf 100644 --- a/server/store/datastore/feed_test.go +++ b/server/store/datastore/feed_test.go @@ -23,7 +23,7 @@ import ( ) func TestRepoListLatest(t *testing.T) { - store, closer := newTestStore(t, new(model.Repo), new(model.User), new(model.Perm), new(model.Build)) + store, closer := newTestStore(t, new(model.Repo), new(model.User), new(model.Perm), new(model.Pipeline)) defer closer() user := &model.User{ @@ -65,45 +65,45 @@ func TestRepoListLatest(t *testing.T) { assert.NoError(t, store.PermUpsert(perm)) } - build1 := &model.Build{ + pipeline1 := &model.Pipeline{ RepoID: repo1.ID, Status: model.StatusFailure, } - build2 := &model.Build{ + pipeline2 := &model.Pipeline{ RepoID: repo1.ID, Status: model.StatusRunning, } - build3 := &model.Build{ + pipeline3 := &model.Pipeline{ RepoID: repo2.ID, Status: model.StatusKilled, } - build4 := &model.Build{ + pipeline4 := &model.Pipeline{ RepoID: repo3.ID, Status: model.StatusError, } - assert.NoError(t, store.CreateBuild(build1)) - assert.NoError(t, store.CreateBuild(build2)) - assert.NoError(t, store.CreateBuild(build3)) - assert.NoError(t, store.CreateBuild(build4)) + assert.NoError(t, store.CreatePipeline(pipeline1)) + assert.NoError(t, store.CreatePipeline(pipeline2)) + assert.NoError(t, store.CreatePipeline(pipeline3)) + assert.NoError(t, store.CreatePipeline(pipeline4)) - builds, err := store.RepoListLatest(user) + pipelines, err := store.RepoListLatest(user) if err != nil { - t.Errorf("Unexpected error: repository list with latest build: %s", err) + t.Errorf("Unexpected error: repository list with latest pipeline: %s", err) return } - if got, want := len(builds), 2; got != want { + if got, want := len(pipelines), 2; got != want { t.Errorf("Want %d repositories, got %d", want, got) } - if got, want := builds[0].Status, string(model.StatusRunning); want != got { + if got, want := pipelines[0].Status, string(model.StatusRunning); want != got { t.Errorf("Want repository status %s, got %s", want, got) } - if got, want := builds[0].FullName, repo1.FullName; want != got { + if got, want := pipelines[0].FullName, repo1.FullName; want != got { t.Errorf("Want repository name %s, got %s", want, got) } - if got, want := builds[1].Status, string(model.StatusKilled); want != got { + if got, want := pipelines[1].Status, string(model.StatusKilled); want != got { t.Errorf("Want repository status %s, got %s", want, got) } - if got, want := builds[1].FullName, repo2.FullName; want != got { + if got, want := pipelines[1].FullName, repo2.FullName; want != got { t.Errorf("Want repository name %s, got %s", want, got) } } diff --git a/server/store/datastore/file.go b/server/store/datastore/file.go index 5e99cb571..d31bad9c6 100644 --- a/server/store/datastore/file.go +++ b/server/store/datastore/file.go @@ -21,9 +21,9 @@ import ( "github.com/woodpecker-ci/woodpecker/server/model" ) -func (s storage) FileList(build *model.Build) ([]*model.File, error) { +func (s storage) FileList(pipeline *model.Pipeline) ([]*model.File, error) { files := make([]*model.File, 0, perPage) - return files, s.engine.Where("file_build_id = ?", build.ID).Find(&files) + return files, s.engine.Where("file_build_id = ?", pipeline.ID).Find(&files) } func (s storage) FileFind(proc *model.Proc, name string) (*model.File, error) { diff --git a/server/store/datastore/file_test.go b/server/store/datastore/file_test.go index 0a8025af1..02540cf24 100644 --- a/server/store/datastore/file_test.go +++ b/server/store/datastore/file_test.go @@ -30,11 +30,11 @@ func TestFileFind(t *testing.T) { if err := store.FileCreate( &model.File{ - BuildID: 2, - ProcID: 1, - Name: "hello.txt", - Mime: "text/plain", - Size: 11, + PipelineID: 2, + ProcID: 1, + Name: "hello.txt", + Mime: "text/plain", + Size: 11, }, bytes.NewBufferString("hello world"), ); err != nil { @@ -50,8 +50,8 @@ func TestFileFind(t *testing.T) { if got, want := file.ID, int64(1); got != want { t.Errorf("Want file id %d, got %d", want, got) } - if got, want := file.BuildID, int64(2); got != want { - t.Errorf("Want file build id %d, got %d", want, got) + if got, want := file.PipelineID, int64(2); got != want { + t.Errorf("Want file pipeline id %d, got %d", want, got) } if got, want := file.ProcID, int64(1); got != want { t.Errorf("Want file proc id %d, got %d", want, got) @@ -78,31 +78,31 @@ func TestFileFind(t *testing.T) { } func TestFileList(t *testing.T) { - store, closer := newTestStore(t, new(model.File), new(model.Build)) + store, closer := newTestStore(t, new(model.File), new(model.Pipeline)) defer closer() assert.NoError(t, store.FileCreate( &model.File{ - BuildID: 1, - ProcID: 1, - Name: "hello.txt", - Mime: "text/plain", - Size: 11, + PipelineID: 1, + ProcID: 1, + Name: "hello.txt", + Mime: "text/plain", + Size: 11, }, bytes.NewBufferString("hello world"), )) assert.NoError(t, store.FileCreate( &model.File{ - BuildID: 1, - ProcID: 1, - Name: "hola.txt", - Mime: "text/plain", - Size: 11, + PipelineID: 1, + ProcID: 1, + Name: "hola.txt", + Mime: "text/plain", + Size: 11, }, bytes.NewBufferString("hola mundo"), )) - files, err := store.FileList(&model.Build{ID: 1}) + files, err := store.FileList(&model.Pipeline{ID: 1}) if err != nil { t.Errorf("Unexpected error: select files: %s", err) return @@ -114,16 +114,16 @@ func TestFileList(t *testing.T) { } func TestFileIndexes(t *testing.T) { - store, closer := newTestStore(t, new(model.File), new(model.Build)) + store, closer := newTestStore(t, new(model.File), new(model.Pipeline)) defer closer() if err := store.FileCreate( &model.File{ - BuildID: 1, - ProcID: 1, - Name: "hello.txt", - Size: 11, - Mime: "text/plain", + PipelineID: 1, + ProcID: 1, + Name: "hello.txt", + Size: 11, + Mime: "text/plain", }, bytes.NewBufferString("hello world"), ); err != nil { @@ -134,11 +134,11 @@ func TestFileIndexes(t *testing.T) { // fail due to duplicate file name if err := store.FileCreate( &model.File{ - BuildID: 1, - ProcID: 1, - Name: "hello.txt", - Mime: "text/plain", - Size: 11, + PipelineID: 1, + ProcID: 1, + Name: "hello.txt", + Mime: "text/plain", + Size: 11, }, bytes.NewBufferString("hello world"), ); err == nil { @@ -147,26 +147,26 @@ func TestFileIndexes(t *testing.T) { } func TestFileCascade(t *testing.T) { - store, closer := newTestStore(t, new(model.File), new(model.Proc), new(model.Build)) + store, closer := newTestStore(t, new(model.File), new(model.Proc), new(model.Pipeline)) defer closer() procOne := &model.Proc{ - BuildID: 1, - PID: 1, - PGID: 1, - Name: "build", - State: "success", + PipelineID: 1, + PID: 1, + PGID: 1, + Name: "build", + State: "success", } err1 := store.ProcCreate([]*model.Proc{procOne}) assert.EqualValues(t, int64(1), procOne.ID) err2 := store.FileCreate( &model.File{ - BuildID: 1, - ProcID: 1, - Name: "hello.txt", - Mime: "text/plain", - Size: 11, + PipelineID: 1, + ProcID: 1, + Name: "hello.txt", + Mime: "text/plain", + Size: 11, }, bytes.NewBufferString("hello world"), ) @@ -177,11 +177,11 @@ func TestFileCascade(t *testing.T) { t.Errorf("Unexpected error: cannot insert file: %s", err2) } - if _, err3 := store.ProcFind(&model.Build{ID: 1}, 1); err3 != nil { + if _, err3 := store.ProcFind(&model.Pipeline{ID: 1}, 1); err3 != nil { t.Errorf("Unexpected error: cannot get inserted proc: %s", err3) } - err := store.ProcClear(&model.Build{ID: 1, Procs: []*model.Proc{procOne}}) + err := store.ProcClear(&model.Pipeline{ID: 1, Procs: []*model.Proc{procOne}}) assert.NoError(t, err) file, err4 := store.FileFind(&model.Proc{ID: 1}, "hello.txt") diff --git a/server/store/datastore/migration/008_secrets_update_secret_name.go b/server/store/datastore/migration/008_lowercase_secret_names.go similarity index 100% rename from server/store/datastore/migration/008_secrets_update_secret_name.go rename to server/store/datastore/migration/008_lowercase_secret_names.go diff --git a/server/store/datastore/migration/009_rename_builds_to_pipeline.go b/server/store/datastore/migration/009_rename_builds_to_pipeline.go new file mode 100644 index 000000000..9f263c6ed --- /dev/null +++ b/server/store/datastore/migration/009_rename_builds_to_pipeline.go @@ -0,0 +1,35 @@ +// Copyright 2022 Woodpecker Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package migration + +import ( + "xorm.io/xorm" +) + +var renameBuildsToPipeline = task{ + name: "rename-builds-to-pipeline", + required: true, + fn: func(sess *xorm.Session) error { + err := renameTable(sess, "builds", "pipelines") + if err != nil { + return err + } + err = renameTable(sess, "build_config", "pipeline_config") + if err != nil { + return err + } + return nil + }, +} diff --git a/server/store/datastore/migration/migration.go b/server/store/datastore/migration/migration.go index 5a616a69f..8a1185e45 100644 --- a/server/store/datastore/migration/migration.go +++ b/server/store/datastore/migration/migration.go @@ -36,12 +36,13 @@ var migrationTasks = []*task{ &alterTableLogUpdateColumnLogDataType, &alterTableSecretsAddUserCol, &lowercaseSecretNames, + &renameBuildsToPipeline, } var allBeans = []interface{}{ new(model.Agent), - new(model.Build), - new(model.BuildConfig), + new(model.Pipeline), + new(model.PipelineConfig), new(model.Config), new(model.File), new(model.Logs), diff --git a/server/store/datastore/pipeline.go b/server/store/datastore/pipeline.go new file mode 100644 index 000000000..d0c738424 --- /dev/null +++ b/server/store/datastore/pipeline.go @@ -0,0 +1,159 @@ +// Copyright 2021 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 datastore + +import ( + "time" + + "xorm.io/xorm" + + "github.com/woodpecker-ci/woodpecker/server/model" +) + +func (s storage) GetPipeline(id int64) (*model.Pipeline, error) { + pipeline := &model.Pipeline{} + return pipeline, wrapGet(s.engine.ID(id).Get(pipeline)) +} + +func (s storage) GetPipelineNumber(repo *model.Repo, num int64) (*model.Pipeline, error) { + pipeline := &model.Pipeline{ + RepoID: repo.ID, + Number: num, + } + return pipeline, wrapGet(s.engine.Get(pipeline)) +} + +func (s storage) GetPipelineRef(repo *model.Repo, ref string) (*model.Pipeline, error) { + pipeline := &model.Pipeline{ + RepoID: repo.ID, + Ref: ref, + } + return pipeline, wrapGet(s.engine.Get(pipeline)) +} + +func (s storage) GetPipelineCommit(repo *model.Repo, sha, branch string) (*model.Pipeline, error) { + pipeline := &model.Pipeline{ + RepoID: repo.ID, + Branch: branch, + Commit: sha, + } + return pipeline, wrapGet(s.engine.Get(pipeline)) +} + +func (s storage) GetPipelineLast(repo *model.Repo, branch string) (*model.Pipeline, error) { + pipeline := &model.Pipeline{ + RepoID: repo.ID, + Branch: branch, + Event: model.EventPush, + } + return pipeline, wrapGet(s.engine.Desc("build_number").Get(pipeline)) +} + +func (s storage) GetPipelineLastBefore(repo *model.Repo, branch string, num int64) (*model.Pipeline, error) { + pipeline := &model.Pipeline{ + RepoID: repo.ID, + Branch: branch, + } + return pipeline, wrapGet(s.engine. + Desc("build_number"). + Where("build_id < ?", num). + Get(pipeline)) +} + +func (s storage) GetPipelineList(repo *model.Repo, page int) ([]*model.Pipeline, error) { + pipelines := make([]*model.Pipeline, 0, perPage) + return pipelines, s.engine.Where("build_repo_id = ?", repo.ID). + Desc("build_number"). + Limit(perPage, perPage*(page-1)). + Find(&pipelines) +} + +// GetActivePipelineList get all pipelines that are pending, running or blocked +func (s storage) GetActivePipelineList(repo *model.Repo, page int) ([]*model.Pipeline, error) { + pipelines := make([]*model.Pipeline, 0, perPage) + query := s.engine. + Where("build_repo_id = ?", repo.ID). + In("build_status", model.StatusPending, model.StatusRunning, model.StatusBlocked). + Desc("build_number") + if page > 0 { + query = query.Limit(perPage, perPage*(page-1)) + } + return pipelines, query.Find(&pipelines) +} + +func (s storage) GetPipelineCount() (int64, error) { + return s.engine.Count(new(model.Pipeline)) +} + +func (s storage) CreatePipeline(pipeline *model.Pipeline, procList ...*model.Proc) error { + sess := s.engine.NewSession() + defer sess.Close() + if err := sess.Begin(); err != nil { + return err + } + + // calc pipeline number + var number int64 + if _, err := sess.SQL("SELECT MAX(build_number) FROM `pipelines` WHERE build_repo_id = ?", pipeline.RepoID).Get(&number); err != nil { + return err + } + pipeline.Number = number + 1 + + pipeline.Created = time.Now().UTC().Unix() + pipeline.Enqueued = pipeline.Created + // only Insert set auto created ID back to object + if _, err := sess.Insert(pipeline); err != nil { + return err + } + + for i := range procList { + procList[i].PipelineID = pipeline.ID + // only Insert set auto created ID back to object + if _, err := sess.Insert(procList[i]); err != nil { + return err + } + } + + return sess.Commit() +} + +func (s storage) UpdatePipeline(pipeline *model.Pipeline) error { + _, err := s.engine.ID(pipeline.ID).AllCols().Update(pipeline) + return err +} + +func deletePipeline(sess *xorm.Session, pipelineID int64) error { + // delete related procs + for startProcs := 0; ; startProcs += perPage { + procIDs := make([]int64, 0, perPage) + if err := sess.Limit(perPage, startProcs).Table("procs").Cols("proc_id").Where("proc_build_id = ?", pipelineID).Find(&procIDs); err != nil { + return err + } + if len(procIDs) == 0 { + break + } + + for i := range procIDs { + if err := deleteProc(sess, procIDs[i]); err != nil { + return err + } + } + } + if _, err := sess.Where("build_id = ?", pipelineID).Delete(new(model.PipelineConfig)); err != nil { + return err + } + _, err := sess.ID(pipelineID).Delete(new(model.Pipeline)) + return err +} diff --git a/server/store/datastore/pipeline_test.go b/server/store/datastore/pipeline_test.go new file mode 100644 index 000000000..7fa23370d --- /dev/null +++ b/server/store/datastore/pipeline_test.go @@ -0,0 +1,308 @@ +// Copyright 2022 Woodpecker Authors +// Copyright 2018 Drone.IO Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// 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 datastore + +import ( + "fmt" + "testing" + + "github.com/franela/goblin" + "github.com/stretchr/testify/assert" + + "github.com/woodpecker-ci/woodpecker/server/model" +) + +func TestPipelines(t *testing.T) { + repo := &model.Repo{ + UserID: 1, + FullName: "bradrydzewski/test", + Owner: "bradrydzewski", + Name: "test", + } + + store, closer := newTestStore(t, new(model.Repo), new(model.Proc), new(model.Pipeline)) + defer closer() + + g := goblin.Goblin(t) + g.Describe("Pipelines", func() { + g.Before(func() { + _, err := store.engine.Exec("DELETE FROM repos") + g.Assert(err).IsNil() + g.Assert(store.CreateRepo(repo)).IsNil() + }) + g.After(func() { + _, err := store.engine.Exec("DELETE FROM repos") + g.Assert(err).IsNil() + }) + + // before each test be sure to purge the package + // table data from the database. + g.BeforeEach(func() { + _, err := store.engine.Exec("DELETE FROM pipelines") + g.Assert(err).IsNil() + _, err = store.engine.Exec("DELETE FROM procs") + g.Assert(err).IsNil() + }) + + g.It("Should Post a Pipeline", func() { + pipeline := model.Pipeline{ + RepoID: repo.ID, + Status: model.StatusSuccess, + Commit: "85f8c029b902ed9400bc600bac301a0aadb144ac", + } + err := store.CreatePipeline(&pipeline) + g.Assert(err).IsNil() + g.Assert(pipeline.ID != 0).IsTrue() + g.Assert(pipeline.Number).Equal(int64(1)) + g.Assert(pipeline.Commit).Equal("85f8c029b902ed9400bc600bac301a0aadb144ac") + + count, err := store.GetPipelineCount() + g.Assert(err).IsNil() + g.Assert(count > 0).IsTrue() + fmt.Println("GOT COUNT", count) + }) + + g.It("Should Put a Pipeline", func() { + pipeline := model.Pipeline{ + RepoID: repo.ID, + Number: 5, + Status: model.StatusSuccess, + Commit: "85f8c029b902ed9400bc600bac301a0aadb144ac", + } + err := store.CreatePipeline(&pipeline) + g.Assert(err).IsNil() + pipeline.Status = model.StatusRunning + err1 := store.UpdatePipeline(&pipeline) + GetPipeline, err2 := store.GetPipeline(pipeline.ID) + g.Assert(err1).IsNil() + g.Assert(err2).IsNil() + g.Assert(pipeline.ID).Equal(GetPipeline.ID) + g.Assert(pipeline.RepoID).Equal(GetPipeline.RepoID) + g.Assert(pipeline.Status).Equal(GetPipeline.Status) + g.Assert(pipeline.Number).Equal(GetPipeline.Number) + }) + + g.It("Should Get a Pipeline", func() { + pipeline := model.Pipeline{ + RepoID: repo.ID, + Status: model.StatusSuccess, + } + err := store.CreatePipeline(&pipeline, []*model.Proc{}...) + g.Assert(err).IsNil() + GetPipeline, err := store.GetPipeline(pipeline.ID) + g.Assert(err).IsNil() + g.Assert(pipeline.ID).Equal(GetPipeline.ID) + g.Assert(pipeline.RepoID).Equal(GetPipeline.RepoID) + g.Assert(pipeline.Status).Equal(GetPipeline.Status) + }) + + g.It("Should Get a Pipeline by Number", func() { + pipeline1 := &model.Pipeline{ + RepoID: repo.ID, + Status: model.StatusPending, + } + pipeline2 := &model.Pipeline{ + RepoID: repo.ID, + Status: model.StatusPending, + } + err1 := store.CreatePipeline(pipeline1, []*model.Proc{}...) + g.Assert(err1).IsNil() + err2 := store.CreatePipeline(pipeline2, []*model.Proc{}...) + g.Assert(err2).IsNil() + GetPipeline, err3 := store.GetPipelineNumber(&model.Repo{ID: 1}, pipeline2.Number) + g.Assert(err3).IsNil() + g.Assert(pipeline2.ID).Equal(GetPipeline.ID) + g.Assert(pipeline2.RepoID).Equal(GetPipeline.RepoID) + g.Assert(pipeline2.Number).Equal(GetPipeline.Number) + }) + + g.It("Should Get a Pipeline by Ref", func() { + pipeline1 := &model.Pipeline{ + RepoID: repo.ID, + Status: model.StatusPending, + Ref: "refs/pull/5", + } + pipeline2 := &model.Pipeline{ + RepoID: repo.ID, + Status: model.StatusPending, + Ref: "refs/pull/6", + } + err1 := store.CreatePipeline(pipeline1, []*model.Proc{}...) + g.Assert(err1).IsNil() + err2 := store.CreatePipeline(pipeline2, []*model.Proc{}...) + g.Assert(err2).IsNil() + GetPipeline, err3 := store.GetPipelineRef(&model.Repo{ID: 1}, "refs/pull/6") + g.Assert(err3).IsNil() + g.Assert(pipeline2.ID).Equal(GetPipeline.ID) + g.Assert(pipeline2.RepoID).Equal(GetPipeline.RepoID) + g.Assert(pipeline2.Number).Equal(GetPipeline.Number) + g.Assert(pipeline2.Ref).Equal(GetPipeline.Ref) + }) + + g.It("Should Get a Pipeline by Ref", func() { + pipeline1 := &model.Pipeline{ + RepoID: repo.ID, + Status: model.StatusPending, + Ref: "refs/pull/5", + } + pipeline2 := &model.Pipeline{ + RepoID: repo.ID, + Status: model.StatusPending, + Ref: "refs/pull/6", + } + err1 := store.CreatePipeline(pipeline1, []*model.Proc{}...) + g.Assert(err1).IsNil() + err2 := store.CreatePipeline(pipeline2, []*model.Proc{}...) + g.Assert(err2).IsNil() + GetPipeline, err3 := store.GetPipelineRef(&model.Repo{ID: 1}, "refs/pull/6") + g.Assert(err3).IsNil() + g.Assert(pipeline2.ID).Equal(GetPipeline.ID) + g.Assert(pipeline2.RepoID).Equal(GetPipeline.RepoID) + g.Assert(pipeline2.Number).Equal(GetPipeline.Number) + g.Assert(pipeline2.Ref).Equal(GetPipeline.Ref) + }) + + g.It("Should Get a Pipeline by Commit", func() { + pipeline1 := &model.Pipeline{ + RepoID: repo.ID, + Status: model.StatusPending, + Branch: "master", + Commit: "85f8c029b902ed9400bc600bac301a0aadb144ac", + } + pipeline2 := &model.Pipeline{ + RepoID: repo.ID, + Status: model.StatusPending, + Branch: "dev", + Commit: "85f8c029b902ed9400bc600bac301a0aadb144aa", + } + err1 := store.CreatePipeline(pipeline1, []*model.Proc{}...) + g.Assert(err1).IsNil() + err2 := store.CreatePipeline(pipeline2, []*model.Proc{}...) + g.Assert(err2).IsNil() + GetPipeline, err3 := store.GetPipelineCommit(&model.Repo{ID: 1}, pipeline2.Commit, pipeline2.Branch) + g.Assert(err3).IsNil() + g.Assert(pipeline2.ID).Equal(GetPipeline.ID) + g.Assert(pipeline2.RepoID).Equal(GetPipeline.RepoID) + g.Assert(pipeline2.Number).Equal(GetPipeline.Number) + g.Assert(pipeline2.Commit).Equal(GetPipeline.Commit) + g.Assert(pipeline2.Branch).Equal(GetPipeline.Branch) + }) + + g.It("Should Get the last Pipeline", func() { + pipeline1 := &model.Pipeline{ + RepoID: repo.ID, + Status: model.StatusFailure, + Branch: "master", + Commit: "85f8c029b902ed9400bc600bac301a0aadb144ac", + Event: model.EventPush, + } + pipeline2 := &model.Pipeline{ + RepoID: repo.ID, + Status: model.StatusSuccess, + Branch: "master", + Commit: "85f8c029b902ed9400bc600bac301a0aadb144aa", + Event: model.EventPush, + } + err1 := store.CreatePipeline(pipeline1, []*model.Proc{}...) + err2 := store.CreatePipeline(pipeline2, []*model.Proc{}...) + GetPipeline, err3 := store.GetPipelineLast(&model.Repo{ID: 1}, pipeline2.Branch) + g.Assert(err1).IsNil() + g.Assert(err2).IsNil() + g.Assert(err3).IsNil() + g.Assert(pipeline2.ID).Equal(GetPipeline.ID) + g.Assert(pipeline2.RepoID).Equal(GetPipeline.RepoID) + g.Assert(pipeline2.Number).Equal(GetPipeline.Number) + g.Assert(pipeline2.Status).Equal(GetPipeline.Status) + g.Assert(pipeline2.Branch).Equal(GetPipeline.Branch) + g.Assert(pipeline2.Commit).Equal(GetPipeline.Commit) + }) + + g.It("Should Get the last Pipeline Before Pipeline N", func() { + pipeline1 := &model.Pipeline{ + RepoID: repo.ID, + Status: model.StatusFailure, + Branch: "master", + Commit: "85f8c029b902ed9400bc600bac301a0aadb144ac", + } + pipeline2 := &model.Pipeline{ + RepoID: repo.ID, + Status: model.StatusSuccess, + Branch: "master", + Commit: "85f8c029b902ed9400bc600bac301a0aadb144aa", + } + pipeline3 := &model.Pipeline{ + RepoID: repo.ID, + Status: model.StatusRunning, + Branch: "master", + Commit: "85f8c029b902ed9400bc600bac301a0aadb144aa", + } + err1 := store.CreatePipeline(pipeline1, []*model.Proc{}...) + g.Assert(err1).IsNil() + err2 := store.CreatePipeline(pipeline2, []*model.Proc{}...) + g.Assert(err2).IsNil() + err3 := store.CreatePipeline(pipeline3, []*model.Proc{}...) + g.Assert(err3).IsNil() + GetPipeline, err4 := store.GetPipelineLastBefore(&model.Repo{ID: 1}, pipeline3.Branch, pipeline3.ID) + g.Assert(err4).IsNil() + g.Assert(pipeline2.ID).Equal(GetPipeline.ID) + g.Assert(pipeline2.RepoID).Equal(GetPipeline.RepoID) + g.Assert(pipeline2.Number).Equal(GetPipeline.Number) + g.Assert(pipeline2.Status).Equal(GetPipeline.Status) + g.Assert(pipeline2.Branch).Equal(GetPipeline.Branch) + g.Assert(pipeline2.Commit).Equal(GetPipeline.Commit) + }) + + g.It("Should get recent pipelines", func() { + pipeline1 := &model.Pipeline{ + RepoID: repo.ID, + Status: model.StatusFailure, + } + pipeline2 := &model.Pipeline{ + RepoID: repo.ID, + Status: model.StatusSuccess, + } + err1 := store.CreatePipeline(pipeline1, []*model.Proc{}...) + g.Assert(err1).IsNil() + err2 := store.CreatePipeline(pipeline2, []*model.Proc{}...) + g.Assert(err2).IsNil() + pipelines, err3 := store.GetPipelineList(&model.Repo{ID: 1}, 1) + g.Assert(err3).IsNil() + g.Assert(len(pipelines)).Equal(2) + g.Assert(pipelines[0].ID).Equal(pipeline2.ID) + g.Assert(pipelines[0].RepoID).Equal(pipeline2.RepoID) + g.Assert(pipelines[0].Status).Equal(pipeline2.Status) + }) + }) +} + +func TestPipelineIncrement(t *testing.T) { + store, closer := newTestStore(t, new(model.Pipeline)) + defer closer() + + pipelineA := &model.Pipeline{RepoID: 1} + if !assert.NoError(t, store.CreatePipeline(pipelineA)) { + return + } + assert.EqualValues(t, 1, pipelineA.Number) + + pipelineB := &model.Pipeline{RepoID: 1} + assert.NoError(t, store.CreatePipeline(pipelineB)) + assert.EqualValues(t, 2, pipelineB.Number) + + pipelineC := &model.Pipeline{RepoID: 2} + assert.NoError(t, store.CreatePipeline(pipelineC)) + assert.EqualValues(t, 1, pipelineC.Number) +} diff --git a/server/store/datastore/proc.go b/server/store/datastore/proc.go index 1a3a11e40..ab7eca864 100644 --- a/server/store/datastore/proc.go +++ b/server/store/datastore/proc.go @@ -25,27 +25,27 @@ func (s storage) ProcLoad(id int64) (*model.Proc, error) { return proc, wrapGet(s.engine.ID(id).Get(proc)) } -func (s storage) ProcFind(build *model.Build, pid int) (*model.Proc, error) { +func (s storage) ProcFind(pipeline *model.Pipeline, pid int) (*model.Proc, error) { proc := &model.Proc{ - BuildID: build.ID, - PID: pid, + PipelineID: pipeline.ID, + PID: pid, } return proc, wrapGet(s.engine.Get(proc)) } -func (s storage) ProcChild(build *model.Build, ppid int, child string) (*model.Proc, error) { +func (s storage) ProcChild(pipeline *model.Pipeline, ppid int, child string) (*model.Proc, error) { proc := &model.Proc{ - BuildID: build.ID, - PPID: ppid, - Name: child, + PipelineID: pipeline.ID, + PPID: ppid, + Name: child, } return proc, wrapGet(s.engine.Get(proc)) } -func (s storage) ProcList(build *model.Build) ([]*model.Proc, error) { +func (s storage) ProcList(pipeline *model.Pipeline) ([]*model.Proc, error) { procList := make([]*model.Proc, 0, perPage) return procList, s.engine. - Where("proc_build_id = ?", build.ID). + Where("proc_build_id = ?", pipeline.ID). OrderBy("proc_pid"). Find(&procList) } @@ -72,18 +72,18 @@ func (s storage) ProcUpdate(proc *model.Proc) error { return err } -func (s storage) ProcClear(build *model.Build) error { +func (s storage) ProcClear(pipeline *model.Pipeline) error { sess := s.engine.NewSession() defer sess.Close() if err := sess.Begin(); err != nil { return err } - if _, err := sess.Where("file_build_id = ?", build.ID).Delete(new(model.File)); err != nil { + if _, err := sess.Where("file_build_id = ?", pipeline.ID).Delete(new(model.File)); err != nil { return err } - if _, err := sess.Where("proc_build_id = ?", build.ID).Delete(new(model.Proc)); err != nil { + if _, err := sess.Where("proc_build_id = ?", pipeline.ID).Delete(new(model.Proc)); err != nil { return err } diff --git a/server/store/datastore/proc_test.go b/server/store/datastore/proc_test.go index de65ee272..fd1a074f7 100644 --- a/server/store/datastore/proc_test.go +++ b/server/store/datastore/proc_test.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,29 +24,29 @@ import ( ) func TestProcFind(t *testing.T) { - store, closer := newTestStore(t, new(model.Proc), new(model.Build)) + store, closer := newTestStore(t, new(model.Proc), new(model.Pipeline)) defer closer() procs := []*model.Proc{ { - BuildID: 1000, - PID: 1, - PPID: 2, - PGID: 3, - Name: "build", - State: model.StatusSuccess, - Error: "pc load letter", - ExitCode: 255, - Machine: "localhost", - Platform: "linux/amd64", - Environ: map[string]string{"GOLANG": "tip"}, + PipelineID: 1000, + PID: 1, + PPID: 2, + PGID: 3, + Name: "build", + State: model.StatusSuccess, + Error: "pc load letter", + ExitCode: 255, + Machine: "localhost", + Platform: "linux/amd64", + Environ: map[string]string{"GOLANG": "tip"}, }, } assert.NoError(t, store.ProcCreate(procs)) assert.EqualValues(t, 1, procs[0].ID) assert.Error(t, store.ProcCreate(procs)) - proc, err := store.ProcFind(&model.Build{ID: 1000}, 1) + proc, err := store.ProcFind(&model.Pipeline{ID: 1000}, 1) if !assert.NoError(t, err) { return } @@ -53,31 +54,31 @@ func TestProcFind(t *testing.T) { } func TestProcChild(t *testing.T) { - store, closer := newTestStore(t, new(model.Proc), new(model.Build)) + store, closer := newTestStore(t, new(model.Proc), new(model.Pipeline)) defer closer() err := store.ProcCreate([]*model.Proc{ { - BuildID: 1, - PID: 1, - PPID: 1, - PGID: 1, - State: "success", + PipelineID: 1, + PID: 1, + PPID: 1, + PGID: 1, + State: "success", }, { - BuildID: 1, - PID: 2, - PGID: 2, - PPID: 1, - Name: "build", - State: "success", + PipelineID: 1, + PID: 2, + PGID: 2, + PPID: 1, + Name: "build", + State: "success", }, }) if err != nil { t.Errorf("Unexpected error: insert procs: %s", err) return } - proc, err := store.ProcChild(&model.Build{ID: 1}, 1, "build") + proc, err := store.ProcChild(&model.Pipeline{ID: 1}, 1, "build") if err != nil { t.Error(err) return @@ -92,38 +93,38 @@ func TestProcChild(t *testing.T) { } func TestProcList(t *testing.T) { - store, closer := newTestStore(t, new(model.Proc), new(model.Build)) + store, closer := newTestStore(t, new(model.Proc), new(model.Pipeline)) defer closer() err := store.ProcCreate([]*model.Proc{ { - BuildID: 2, - PID: 1, - PPID: 1, - PGID: 1, - State: "success", + PipelineID: 2, + PID: 1, + PPID: 1, + PGID: 1, + State: "success", }, { - BuildID: 1, - PID: 1, - PPID: 1, - PGID: 1, - State: "success", + PipelineID: 1, + PID: 1, + PPID: 1, + PGID: 1, + State: "success", }, { - BuildID: 1, - PID: 2, - PGID: 2, - PPID: 1, - Name: "build", - State: "success", + PipelineID: 1, + PID: 2, + PGID: 2, + PPID: 1, + Name: "build", + State: "success", }, }) if err != nil { t.Errorf("Unexpected error: insert procs: %s", err) return } - procs, err := store.ProcList(&model.Build{ID: 1}) + procs, err := store.ProcList(&model.Pipeline{ID: 1}) if err != nil { t.Error(err) return @@ -134,21 +135,21 @@ func TestProcList(t *testing.T) { } func TestProcUpdate(t *testing.T) { - store, closer := newTestStore(t, new(model.Proc), new(model.Build)) + store, closer := newTestStore(t, new(model.Proc), new(model.Pipeline)) defer closer() proc := &model.Proc{ - BuildID: 1, - PID: 1, - PPID: 2, - PGID: 3, - Name: "build", - State: "pending", - Error: "pc load letter", - ExitCode: 255, - Machine: "localhost", - Platform: "linux/amd64", - Environ: map[string]string{"GOLANG": "tip"}, + PipelineID: 1, + PID: 1, + PPID: 2, + PGID: 3, + Name: "build", + State: "pending", + Error: "pc load letter", + ExitCode: 255, + Machine: "localhost", + Platform: "linux/amd64", + Environ: map[string]string{"GOLANG": "tip"}, } if err := store.ProcCreate([]*model.Proc{proc}); err != nil { t.Errorf("Unexpected error: insert proc: %s", err) @@ -159,7 +160,7 @@ func TestProcUpdate(t *testing.T) { t.Errorf("Unexpected error: update proc: %s", err) return } - updated, err := store.ProcFind(&model.Build{ID: 1}, 1) + updated, err := store.ProcFind(&model.Pipeline{ID: 1}, 1) if err != nil { t.Error(err) return @@ -170,17 +171,17 @@ func TestProcUpdate(t *testing.T) { } func TestProcIndexes(t *testing.T) { - store, closer := newTestStore(t, new(model.Proc), new(model.Build)) + store, closer := newTestStore(t, new(model.Proc), new(model.Pipeline)) defer closer() if err := store.ProcCreate([]*model.Proc{ { - BuildID: 1, - PID: 1, - PPID: 1, - PGID: 1, - State: "running", - Name: "build", + PipelineID: 1, + PID: 1, + PPID: 1, + PGID: 1, + State: "running", + Name: "build", }, }); err != nil { t.Errorf("Unexpected error: insert procs: %s", err) @@ -190,12 +191,12 @@ func TestProcIndexes(t *testing.T) { // fail due to duplicate pid if err := store.ProcCreate([]*model.Proc{ { - BuildID: 1, - PID: 1, - PPID: 1, - PGID: 1, - State: "success", - Name: "clone", + PipelineID: 1, + PID: 1, + PPID: 1, + PGID: 1, + State: "success", + Name: "clone", }, }); err == nil { t.Errorf("Unexpected error: duplicate pid") diff --git a/server/store/datastore/repo.go b/server/store/datastore/repo.go index 1f15ed0f0..593da8b8a 100644 --- a/server/store/datastore/repo.go +++ b/server/store/datastore/repo.go @@ -114,18 +114,18 @@ func (s storage) DeleteRepo(repo *model.Repo) error { return err } - // delete related builds - for startBuilds := 0; ; startBuilds += batchSize { - buildIDs := make([]int64, 0, batchSize) - if err := sess.Limit(batchSize, startBuilds).Table("builds").Cols("build_id").Where("build_repo_id = ?", repo.ID).Find(&buildIDs); err != nil { + // delete related pipelines + for startPipelines := 0; ; startPipelines += batchSize { + pipelineIDs := make([]int64, 0, batchSize) + if err := sess.Limit(batchSize, startPipelines).Table("pipelines").Cols("build_id").Where("build_repo_id = ?", repo.ID).Find(&pipelineIDs); err != nil { return err } - if len(buildIDs) == 0 { + if len(pipelineIDs) == 0 { break } - for i := range buildIDs { - if err := deleteBuild(sess, buildIDs[i]); err != nil { + for i := range pipelineIDs { + if err := deletePipeline(sess, pipelineIDs[i]); err != nil { return err } } diff --git a/server/store/datastore/repo_test.go b/server/store/datastore/repo_test.go index ff3ec1986..26f856820 100644 --- a/server/store/datastore/repo_test.go +++ b/server/store/datastore/repo_test.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,7 +26,7 @@ import ( ) func TestRepos(t *testing.T) { - store, closer := newTestStore(t, new(model.Repo), new(model.User), new(model.Build)) + store, closer := newTestStore(t, new(model.Repo), new(model.User), new(model.Pipeline)) defer closer() g := goblin.Goblin(t) @@ -33,7 +34,7 @@ func TestRepos(t *testing.T) { // before each test be sure to purge the package // table data from the database. g.BeforeEach(func() { - _, err := store.engine.Exec("DELETE FROM builds") + _, err := store.engine.Exec("DELETE FROM pipelines") g.Assert(err).IsNil() _, err = store.engine.Exec("DELETE FROM repos") g.Assert(err).IsNil() @@ -379,8 +380,8 @@ func TestRepoCrud(t *testing.T) { new(model.Repo), new(model.User), new(model.Perm), - new(model.Build), - new(model.BuildConfig), + new(model.Pipeline), + new(model.PipelineConfig), new(model.Logs), new(model.Proc), new(model.File), @@ -397,13 +398,13 @@ func TestRepoCrud(t *testing.T) { Name: "test", } assert.NoError(t, store.CreateRepo(&repo)) - build := model.Build{ + pipeline := model.Pipeline{ RepoID: repo.ID, } proc := model.Proc{ Name: "a proc", } - assert.NoError(t, store.CreateBuild(&build, &proc)) + assert.NoError(t, store.CreatePipeline(&pipeline, &proc)) // create unrelated repoUnrelated := model.Repo{ @@ -413,13 +414,13 @@ func TestRepoCrud(t *testing.T) { Name: "x", } assert.NoError(t, store.CreateRepo(&repoUnrelated)) - buildUnrelated := model.Build{ + pipelineUnrelated := model.Pipeline{ RepoID: repoUnrelated.ID, } procUnrelated := model.Proc{ Name: "a unrelated proc", } - assert.NoError(t, store.CreateBuild(&buildUnrelated, &procUnrelated)) + assert.NoError(t, store.CreatePipeline(&pipelineUnrelated, &procUnrelated)) _, err := store.GetRepo(repo.ID) assert.NoError(t, err) @@ -430,9 +431,9 @@ func TestRepoCrud(t *testing.T) { procCount, err := store.engine.Count(new(model.Proc)) assert.NoError(t, err) assert.EqualValues(t, 1, procCount) - buildCount, err := store.engine.Count(new(model.Build)) + pipelineCount, err := store.engine.Count(new(model.Pipeline)) assert.NoError(t, err) - assert.EqualValues(t, 1, buildCount) + assert.EqualValues(t, 1, pipelineCount) } func TestRepoRedirection(t *testing.T) { diff --git a/server/store/datastore/secret_test.go b/server/store/datastore/secret_test.go index 66278569d..85c932c32 100644 --- a/server/store/datastore/secret_test.go +++ b/server/store/datastore/secret_test.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -77,7 +78,7 @@ func TestSecretList(t *testing.T) { assert.Len(t, list, 2) } -func TestSecretBuildList(t *testing.T) { +func TestSecretPipelineList(t *testing.T) { store, closer := newTestStore(t, new(model.Secret)) defer closer() diff --git a/server/store/datastore/users_test.go b/server/store/datastore/users_test.go index 93443f673..de3a7ab8b 100644 --- a/server/store/datastore/users_test.go +++ b/server/store/datastore/users_test.go @@ -1,3 +1,4 @@ +// Copyright 2022 Woodpecker Authors // Copyright 2018 Drone.IO Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,7 +24,7 @@ import ( ) func TestUsers(t *testing.T) { - store, closer := newTestStore(t, new(model.User), new(model.Repo), new(model.Build), new(model.Proc), new(model.Perm)) + store, closer := newTestStore(t, new(model.User), new(model.Repo), new(model.Pipeline), new(model.Proc), new(model.Perm)) defer closer() g := goblin.Goblin(t) @@ -35,7 +36,7 @@ func TestUsers(t *testing.T) { g.Assert(err).IsNil() _, err = store.engine.Exec("DELETE FROM repos") g.Assert(err).IsNil() - _, err = store.engine.Exec("DELETE FROM builds") + _, err = store.engine.Exec("DELETE FROM pipelines") g.Assert(err).IsNil() _, err = store.engine.Exec("DELETE FROM procs") g.Assert(err).IsNil() @@ -182,7 +183,7 @@ func TestUsers(t *testing.T) { g.Assert(err3).IsNotNil() }) - g.It("Should get the Build feed for a User", func() { + g.It("Should get the Pipeline feed for a User", func() { user := &model.User{ Login: "joe", Email: "foo@bar.com", @@ -222,33 +223,33 @@ func TestUsers(t *testing.T) { g.Assert(store.PermUpsert(perm)).IsNil() } - build1 := &model.Build{ + pipeline1 := &model.Pipeline{ RepoID: repo1.ID, Status: model.StatusFailure, } - build2 := &model.Build{ + pipeline2 := &model.Pipeline{ RepoID: repo1.ID, Status: model.StatusSuccess, } - build3 := &model.Build{ + pipeline3 := &model.Pipeline{ RepoID: repo2.ID, Status: model.StatusSuccess, } - build4 := &model.Build{ + pipeline4 := &model.Pipeline{ RepoID: repo3.ID, Status: model.StatusSuccess, } - g.Assert(store.CreateBuild(build1)).IsNil() - g.Assert(store.CreateBuild(build2)).IsNil() - g.Assert(store.CreateBuild(build3)).IsNil() - g.Assert(store.CreateBuild(build4)).IsNil() + g.Assert(store.CreatePipeline(pipeline1)).IsNil() + g.Assert(store.CreatePipeline(pipeline2)).IsNil() + g.Assert(store.CreatePipeline(pipeline3)).IsNil() + g.Assert(store.CreatePipeline(pipeline4)).IsNil() - builds, err := store.UserFeed(user) + pipelines, err := store.UserFeed(user) g.Assert(err).IsNil() - g.Assert(len(builds)).Equal(3) - g.Assert(builds[0].FullName).Equal(repo2.FullName) - g.Assert(builds[1].FullName).Equal(repo1.FullName) - g.Assert(builds[2].FullName).Equal(repo1.FullName) + g.Assert(len(pipelines)).Equal(3) + g.Assert(pipelines[0].FullName).Equal(repo2.FullName) + g.Assert(pipelines[1].FullName).Equal(repo1.FullName) + g.Assert(pipelines[2].FullName).Equal(repo1.FullName) }) }) } diff --git a/server/store/mocks/store.go b/server/store/mocks/store.go index d9aa4bfc2..337b62f02 100644 --- a/server/store/mocks/store.go +++ b/server/store/mocks/store.go @@ -14,20 +14,6 @@ type Store struct { mock.Mock } -// BuildConfigCreate provides a mock function with given fields: _a0 -func (_m *Store) BuildConfigCreate(_a0 *model.BuildConfig) error { - ret := _m.Called(_a0) - - var r0 error - if rf, ok := ret.Get(0).(func(*model.BuildConfig) error); ok { - r0 = rf(_a0) - } else { - r0 = ret.Error(0) - } - - return r0 -} - // Close provides a mock function with given fields: func (_m *Store) Close() error { ret := _m.Called() @@ -100,13 +86,13 @@ func (_m *Store) ConfigFindIdentical(repoID int64, hash string) (*model.Config, return r0, r1 } -// ConfigsForBuild provides a mock function with given fields: buildID -func (_m *Store) ConfigsForBuild(buildID int64) ([]*model.Config, error) { - ret := _m.Called(buildID) +// ConfigsForPipeline provides a mock function with given fields: pipelineID +func (_m *Store) ConfigsForPipeline(pipelineID int64) ([]*model.Config, error) { + ret := _m.Called(pipelineID) var r0 []*model.Config if rf, ok := ret.Get(0).(func(int64) []*model.Config); ok { - r0 = rf(buildID) + r0 = rf(pipelineID) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]*model.Config) @@ -115,7 +101,7 @@ func (_m *Store) ConfigsForBuild(buildID int64) ([]*model.Config, error) { var r1 error if rf, ok := ret.Get(1).(func(int64) error); ok { - r1 = rf(buildID) + r1 = rf(pipelineID) } else { r1 = ret.Error(1) } @@ -123,8 +109,8 @@ func (_m *Store) ConfigsForBuild(buildID int64) ([]*model.Config, error) { return r0, r1 } -// CreateBuild provides a mock function with given fields: _a0, _a1 -func (_m *Store) CreateBuild(_a0 *model.Build, _a1 ...*model.Proc) error { +// CreatePipeline provides a mock function with given fields: _a0, _a1 +func (_m *Store) CreatePipeline(_a0 *model.Pipeline, _a1 ...*model.Proc) error { _va := make([]interface{}, len(_a1)) for _i := range _a1 { _va[_i] = _a1[_i] @@ -135,7 +121,7 @@ func (_m *Store) CreateBuild(_a0 *model.Build, _a1 ...*model.Proc) error { ret := _m.Called(_ca...) var r0 error - if rf, ok := ret.Get(0).(func(*model.Build, ...*model.Proc) error); ok { + if rf, ok := ret.Get(0).(func(*model.Pipeline, ...*model.Proc) error); ok { r0 = rf(_a0, _a1...) } else { r0 = ret.Error(0) @@ -384,11 +370,11 @@ func (_m *Store) FileFind(_a0 *model.Proc, _a1 string) (*model.File, error) { } // FileList provides a mock function with given fields: _a0 -func (_m *Store) FileList(_a0 *model.Build) ([]*model.File, error) { +func (_m *Store) FileList(_a0 *model.Pipeline) ([]*model.File, error) { ret := _m.Called(_a0) var r0 []*model.File - if rf, ok := ret.Get(0).(func(*model.Build) []*model.File); ok { + if rf, ok := ret.Get(0).(func(*model.Pipeline) []*model.File); ok { r0 = rf(_a0) } else { if ret.Get(0) != nil { @@ -397,7 +383,7 @@ func (_m *Store) FileList(_a0 *model.Build) ([]*model.File, error) { } var r1 error - if rf, ok := ret.Get(1).(func(*model.Build) error); ok { + if rf, ok := ret.Get(1).(func(*model.Pipeline) error); ok { r1 = rf(_a0) } else { r1 = ret.Error(1) @@ -429,16 +415,16 @@ func (_m *Store) FileRead(_a0 *model.Proc, _a1 string) (io.ReadCloser, error) { return r0, r1 } -// GetActiveBuildList provides a mock function with given fields: repo, page -func (_m *Store) GetActiveBuildList(repo *model.Repo, page int) ([]*model.Build, error) { +// GetActivePipelineList provides a mock function with given fields: repo, page +func (_m *Store) GetActivePipelineList(repo *model.Repo, page int) ([]*model.Pipeline, error) { ret := _m.Called(repo, page) - var r0 []*model.Build - if rf, ok := ret.Get(0).(func(*model.Repo, int) []*model.Build); ok { + var r0 []*model.Pipeline + if rf, ok := ret.Get(0).(func(*model.Repo, int) []*model.Pipeline); ok { r0 = rf(repo, page) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).([]*model.Build) + r0 = ret.Get(0).([]*model.Pipeline) } } @@ -452,16 +438,16 @@ func (_m *Store) GetActiveBuildList(repo *model.Repo, page int) ([]*model.Build, return r0, r1 } -// GetBuild provides a mock function with given fields: _a0 -func (_m *Store) GetBuild(_a0 int64) (*model.Build, error) { +// GetPipeline provides a mock function with given fields: _a0 +func (_m *Store) GetPipeline(_a0 int64) (*model.Pipeline, error) { ret := _m.Called(_a0) - var r0 *model.Build - if rf, ok := ret.Get(0).(func(int64) *model.Build); ok { + var r0 *model.Pipeline + if rf, ok := ret.Get(0).(func(int64) *model.Pipeline); ok { r0 = rf(_a0) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(*model.Build) + r0 = ret.Get(0).(*model.Pipeline) } } @@ -475,16 +461,16 @@ func (_m *Store) GetBuild(_a0 int64) (*model.Build, error) { return r0, r1 } -// GetBuildCommit provides a mock function with given fields: _a0, _a1, _a2 -func (_m *Store) GetBuildCommit(_a0 *model.Repo, _a1 string, _a2 string) (*model.Build, error) { +// GetPipelineCommit provides a mock function with given fields: _a0, _a1, _a2 +func (_m *Store) GetPipelineCommit(_a0 *model.Repo, _a1 string, _a2 string) (*model.Pipeline, error) { ret := _m.Called(_a0, _a1, _a2) - var r0 *model.Build - if rf, ok := ret.Get(0).(func(*model.Repo, string, string) *model.Build); ok { + var r0 *model.Pipeline + if rf, ok := ret.Get(0).(func(*model.Repo, string, string) *model.Pipeline); ok { r0 = rf(_a0, _a1, _a2) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(*model.Build) + r0 = ret.Get(0).(*model.Pipeline) } } @@ -498,8 +484,8 @@ func (_m *Store) GetBuildCommit(_a0 *model.Repo, _a1 string, _a2 string) (*model return r0, r1 } -// GetBuildCount provides a mock function with given fields: -func (_m *Store) GetBuildCount() (int64, error) { +// GetPipelineCount provides a mock function with given fields: +func (_m *Store) GetPipelineCount() (int64, error) { ret := _m.Called() var r0 int64 @@ -519,16 +505,16 @@ func (_m *Store) GetBuildCount() (int64, error) { return r0, r1 } -// GetBuildLast provides a mock function with given fields: _a0, _a1 -func (_m *Store) GetBuildLast(_a0 *model.Repo, _a1 string) (*model.Build, error) { +// GetPipelineLast provides a mock function with given fields: _a0, _a1 +func (_m *Store) GetPipelineLast(_a0 *model.Repo, _a1 string) (*model.Pipeline, error) { ret := _m.Called(_a0, _a1) - var r0 *model.Build - if rf, ok := ret.Get(0).(func(*model.Repo, string) *model.Build); ok { + var r0 *model.Pipeline + if rf, ok := ret.Get(0).(func(*model.Repo, string) *model.Pipeline); ok { r0 = rf(_a0, _a1) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(*model.Build) + r0 = ret.Get(0).(*model.Pipeline) } } @@ -542,16 +528,16 @@ func (_m *Store) GetBuildLast(_a0 *model.Repo, _a1 string) (*model.Build, error) return r0, r1 } -// GetBuildLastBefore provides a mock function with given fields: _a0, _a1, _a2 -func (_m *Store) GetBuildLastBefore(_a0 *model.Repo, _a1 string, _a2 int64) (*model.Build, error) { +// GetPipelineLastBefore provides a mock function with given fields: _a0, _a1, _a2 +func (_m *Store) GetPipelineLastBefore(_a0 *model.Repo, _a1 string, _a2 int64) (*model.Pipeline, error) { ret := _m.Called(_a0, _a1, _a2) - var r0 *model.Build - if rf, ok := ret.Get(0).(func(*model.Repo, string, int64) *model.Build); ok { + var r0 *model.Pipeline + if rf, ok := ret.Get(0).(func(*model.Repo, string, int64) *model.Pipeline); ok { r0 = rf(_a0, _a1, _a2) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(*model.Build) + r0 = ret.Get(0).(*model.Pipeline) } } @@ -565,16 +551,16 @@ func (_m *Store) GetBuildLastBefore(_a0 *model.Repo, _a1 string, _a2 int64) (*mo return r0, r1 } -// GetBuildList provides a mock function with given fields: _a0, _a1 -func (_m *Store) GetBuildList(_a0 *model.Repo, _a1 int) ([]*model.Build, error) { +// GetPipelineList provides a mock function with given fields: _a0, _a1 +func (_m *Store) GetPipelineList(_a0 *model.Repo, _a1 int) ([]*model.Pipeline, error) { ret := _m.Called(_a0, _a1) - var r0 []*model.Build - if rf, ok := ret.Get(0).(func(*model.Repo, int) []*model.Build); ok { + var r0 []*model.Pipeline + if rf, ok := ret.Get(0).(func(*model.Repo, int) []*model.Pipeline); ok { r0 = rf(_a0, _a1) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).([]*model.Build) + r0 = ret.Get(0).([]*model.Pipeline) } } @@ -588,16 +574,16 @@ func (_m *Store) GetBuildList(_a0 *model.Repo, _a1 int) ([]*model.Build, error) return r0, r1 } -// GetBuildNumber provides a mock function with given fields: _a0, _a1 -func (_m *Store) GetBuildNumber(_a0 *model.Repo, _a1 int64) (*model.Build, error) { +// GetPipelineNumber provides a mock function with given fields: _a0, _a1 +func (_m *Store) GetPipelineNumber(_a0 *model.Repo, _a1 int64) (*model.Pipeline, error) { ret := _m.Called(_a0, _a1) - var r0 *model.Build - if rf, ok := ret.Get(0).(func(*model.Repo, int64) *model.Build); ok { + var r0 *model.Pipeline + if rf, ok := ret.Get(0).(func(*model.Repo, int64) *model.Pipeline); ok { r0 = rf(_a0, _a1) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(*model.Build) + r0 = ret.Get(0).(*model.Pipeline) } } @@ -611,8 +597,8 @@ func (_m *Store) GetBuildNumber(_a0 *model.Repo, _a1 int64) (*model.Build, error return r0, r1 } -// GetBuildQueue provides a mock function with given fields: -func (_m *Store) GetBuildQueue() ([]*model.Feed, error) { +// GetPipelineQueue provides a mock function with given fields: +func (_m *Store) GetPipelineQueue() ([]*model.Feed, error) { ret := _m.Called() var r0 []*model.Feed @@ -634,16 +620,16 @@ func (_m *Store) GetBuildQueue() ([]*model.Feed, error) { return r0, r1 } -// GetBuildRef provides a mock function with given fields: _a0, _a1 -func (_m *Store) GetBuildRef(_a0 *model.Repo, _a1 string) (*model.Build, error) { +// GetPipelineRef provides a mock function with given fields: _a0, _a1 +func (_m *Store) GetPipelineRef(_a0 *model.Repo, _a1 string) (*model.Pipeline, error) { ret := _m.Called(_a0, _a1) - var r0 *model.Build - if rf, ok := ret.Get(0).(func(*model.Repo, string) *model.Build); ok { + var r0 *model.Pipeline + if rf, ok := ret.Get(0).(func(*model.Repo, string) *model.Pipeline); ok { r0 = rf(_a0, _a1) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(*model.Build) + r0 = ret.Get(0).(*model.Pipeline) } } @@ -1126,12 +1112,26 @@ func (_m *Store) Ping() error { return r0 } +// PipelineConfigCreate provides a mock function with given fields: _a0 +func (_m *Store) PipelineConfigCreate(_a0 *model.PipelineConfig) error { + ret := _m.Called(_a0) + + var r0 error + if rf, ok := ret.Get(0).(func(*model.PipelineConfig) error); ok { + r0 = rf(_a0) + } else { + r0 = ret.Error(0) + } + + return r0 +} + // ProcChild provides a mock function with given fields: _a0, _a1, _a2 -func (_m *Store) ProcChild(_a0 *model.Build, _a1 int, _a2 string) (*model.Proc, error) { +func (_m *Store) ProcChild(_a0 *model.Pipeline, _a1 int, _a2 string) (*model.Proc, error) { ret := _m.Called(_a0, _a1, _a2) var r0 *model.Proc - if rf, ok := ret.Get(0).(func(*model.Build, int, string) *model.Proc); ok { + if rf, ok := ret.Get(0).(func(*model.Pipeline, int, string) *model.Proc); ok { r0 = rf(_a0, _a1, _a2) } else { if ret.Get(0) != nil { @@ -1140,7 +1140,7 @@ func (_m *Store) ProcChild(_a0 *model.Build, _a1 int, _a2 string) (*model.Proc, } var r1 error - if rf, ok := ret.Get(1).(func(*model.Build, int, string) error); ok { + if rf, ok := ret.Get(1).(func(*model.Pipeline, int, string) error); ok { r1 = rf(_a0, _a1, _a2) } else { r1 = ret.Error(1) @@ -1150,11 +1150,11 @@ func (_m *Store) ProcChild(_a0 *model.Build, _a1 int, _a2 string) (*model.Proc, } // ProcClear provides a mock function with given fields: _a0 -func (_m *Store) ProcClear(_a0 *model.Build) error { +func (_m *Store) ProcClear(_a0 *model.Pipeline) error { ret := _m.Called(_a0) var r0 error - if rf, ok := ret.Get(0).(func(*model.Build) error); ok { + if rf, ok := ret.Get(0).(func(*model.Pipeline) error); ok { r0 = rf(_a0) } else { r0 = ret.Error(0) @@ -1178,11 +1178,11 @@ func (_m *Store) ProcCreate(_a0 []*model.Proc) error { } // ProcFind provides a mock function with given fields: _a0, _a1 -func (_m *Store) ProcFind(_a0 *model.Build, _a1 int) (*model.Proc, error) { +func (_m *Store) ProcFind(_a0 *model.Pipeline, _a1 int) (*model.Proc, error) { ret := _m.Called(_a0, _a1) var r0 *model.Proc - if rf, ok := ret.Get(0).(func(*model.Build, int) *model.Proc); ok { + if rf, ok := ret.Get(0).(func(*model.Pipeline, int) *model.Proc); ok { r0 = rf(_a0, _a1) } else { if ret.Get(0) != nil { @@ -1191,7 +1191,7 @@ func (_m *Store) ProcFind(_a0 *model.Build, _a1 int) (*model.Proc, error) { } var r1 error - if rf, ok := ret.Get(1).(func(*model.Build, int) error); ok { + if rf, ok := ret.Get(1).(func(*model.Pipeline, int) error); ok { r1 = rf(_a0, _a1) } else { r1 = ret.Error(1) @@ -1201,11 +1201,11 @@ func (_m *Store) ProcFind(_a0 *model.Build, _a1 int) (*model.Proc, error) { } // ProcList provides a mock function with given fields: _a0 -func (_m *Store) ProcList(_a0 *model.Build) ([]*model.Proc, error) { +func (_m *Store) ProcList(_a0 *model.Pipeline) ([]*model.Proc, error) { ret := _m.Called(_a0) var r0 []*model.Proc - if rf, ok := ret.Get(0).(func(*model.Build) []*model.Proc); ok { + if rf, ok := ret.Get(0).(func(*model.Pipeline) []*model.Proc); ok { r0 = rf(_a0) } else { if ret.Get(0) != nil { @@ -1214,7 +1214,7 @@ func (_m *Store) ProcList(_a0 *model.Build) ([]*model.Proc, error) { } var r1 error - if rf, ok := ret.Get(1).(func(*model.Build) error); ok { + if rf, ok := ret.Get(1).(func(*model.Pipeline) error); ok { r1 = rf(_a0) } else { r1 = ret.Error(1) @@ -1582,12 +1582,12 @@ func (_m *Store) TaskList() ([]*model.Task, error) { return r0, r1 } -// UpdateBuild provides a mock function with given fields: _a0 -func (_m *Store) UpdateBuild(_a0 *model.Build) error { +// UpdatePipeline provides a mock function with given fields: _a0 +func (_m *Store) UpdatePipeline(_a0 *model.Pipeline) error { ret := _m.Called(_a0) var r0 error - if rf, ok := ret.Get(0).(func(*model.Build) error); ok { + if rf, ok := ret.Get(0).(func(*model.Pipeline) error); ok { r0 = rf(_a0) } else { r0 = ret.Error(0) diff --git a/server/store/store.go b/server/store/store.go index 1d6adf9be..8d91a5a88 100644 --- a/server/store/store.go +++ b/server/store/store.go @@ -69,32 +69,32 @@ type Store interface { // HasRedirectionForRepo checks if there's a redirection for the given repo and full name HasRedirectionForRepo(int64, string) (bool, error) - // Builds - // GetBuild gets a build by unique ID. - GetBuild(int64) (*model.Build, error) - // GetBuildNumber gets a build by number. - GetBuildNumber(*model.Repo, int64) (*model.Build, error) - // GetBuildRef gets a build by its ref. - GetBuildRef(*model.Repo, string) (*model.Build, error) - // GetBuildCommit gets a build by its commit sha. - GetBuildCommit(*model.Repo, string, string) (*model.Build, error) - // GetBuildLast gets the last build for the branch. - GetBuildLast(*model.Repo, string) (*model.Build, error) - // GetBuildLastBefore gets the last build before build number N. - GetBuildLastBefore(*model.Repo, string, int64) (*model.Build, error) - // GetBuildList gets a list of builds for the repository + // Pipelines + // GetPipeline gets a pipeline by unique ID. + GetPipeline(int64) (*model.Pipeline, error) + // GetPipelineNumber gets a pipeline by number. + GetPipelineNumber(*model.Repo, int64) (*model.Pipeline, error) + // GetPipelineRef gets a pipeline by its ref. + GetPipelineRef(*model.Repo, string) (*model.Pipeline, error) + // GetPipelineCommit gets a pipeline by its commit sha. + GetPipelineCommit(*model.Repo, string, string) (*model.Pipeline, error) + // GetPipelineLast gets the last pipeline for the branch. + GetPipelineLast(*model.Repo, string) (*model.Pipeline, error) + // GetPipelineLastBefore gets the last pipeline before pipeline number N. + GetPipelineLastBefore(*model.Repo, string, int64) (*model.Pipeline, error) + // GetPipelineList gets a list of pipelines for the repository // TODO: paginate - GetBuildList(*model.Repo, int) ([]*model.Build, error) - // GetBuildList gets a list of the active builds for the repository - GetActiveBuildList(repo *model.Repo, page int) ([]*model.Build, error) - // GetBuildQueue gets a list of build in queue. - GetBuildQueue() ([]*model.Feed, error) - // GetBuildCount gets a count of all builds in the system. - GetBuildCount() (int64, error) - // CreateBuild creates a new build and jobs. - CreateBuild(*model.Build, ...*model.Proc) error - // UpdateBuild updates a build. - UpdateBuild(*model.Build) error + GetPipelineList(*model.Repo, int) ([]*model.Pipeline, error) + // GetPipelineList gets a list of the active pipelines for the repository + GetActivePipelineList(repo *model.Repo, page int) ([]*model.Pipeline, error) + // GetPipelineQueue gets a list of pipelines in queue. + GetPipelineQueue() ([]*model.Feed, error) + // GetPipelineCount gets a count of all pipelines in the system. + GetPipelineCount() (int64, error) + // CreatePipeline creates a new pipeline and jobs. + CreatePipeline(*model.Pipeline, ...*model.Proc) error + // UpdatePipeline updates a pipeline. + UpdatePipeline(*model.Pipeline) error // Feeds UserFeed(*model.User) ([]*model.Feed, error) @@ -113,11 +113,11 @@ type Store interface { PermFlush(user *model.User, before int64) error // Configs - ConfigsForBuild(buildID int64) ([]*model.Config, error) + ConfigsForPipeline(pipelineID int64) ([]*model.Config, error) ConfigFindIdentical(repoID int64, hash string) (*model.Config, error) ConfigFindApproved(*model.Config) (bool, error) ConfigCreate(*model.Config) error - BuildConfigCreate(*model.BuildConfig) error + PipelineConfigCreate(*model.PipelineConfig) error // Secrets SecretFind(*model.Repo, string) (*model.Secret, error) @@ -139,12 +139,12 @@ type Store interface { // Procs ProcLoad(int64) (*model.Proc, error) - ProcFind(*model.Build, int) (*model.Proc, error) - ProcChild(*model.Build, int, string) (*model.Proc, error) - ProcList(*model.Build) ([]*model.Proc, error) + ProcFind(*model.Pipeline, int) (*model.Proc, error) + ProcChild(*model.Pipeline, int, string) (*model.Proc, error) + ProcList(*model.Pipeline) ([]*model.Proc, error) ProcCreate([]*model.Proc) error ProcUpdate(*model.Proc) error - ProcClear(*model.Build) error + ProcClear(*model.Pipeline) error // Logs LogFind(*model.Proc) (io.ReadCloser, error) @@ -153,7 +153,7 @@ type Store interface { LogSave(*model.Proc, io.Reader) error // Files - FileList(*model.Build) ([]*model.File, error) + FileList(*model.Pipeline) ([]*model.File, error) FileFind(*model.Proc, string) (*model.File, error) FileRead(*model.Proc, string) (io.ReadCloser, error) FileCreate(*model.File, io.Reader) error diff --git a/server/swagger/files/swagger.yml b/server/swagger/files/swagger.yml index 389414b78..d1d24960d 100644 --- a/server/swagger/files/swagger.yml +++ b/server/swagger/files/swagger.yml @@ -302,7 +302,7 @@ paths: - accessToken: [] responses: 200: - description: Successfully restarted the Build. + description: Successfully restarted the Pipeline. schema: $ref: "#/definitions/Build" 404: diff --git a/server/swagger/swagger.go b/server/swagger/swagger.go index 68efbf7af..7925a0413 100644 --- a/server/swagger/swagger.go +++ b/server/swagger/swagger.go @@ -46,7 +46,7 @@ func userList(w http.ResponseWriter, r *http.Request) {} // swagger:route GET /user/feed user getUserFeed // -// Get the currently authenticated user's build feed. +// Get the currently authenticated user's pipeline feed. // // Responses: // 200: feed diff --git a/web/components.d.ts b/web/components.d.ts index 638ee8ebe..4d68e8c43 100644 --- a/web/components.d.ts +++ b/web/components.d.ts @@ -8,18 +8,9 @@ export {} declare module '@vue/runtime-core' { export interface GlobalComponents { ActionsTab: typeof import('./src/components/repo/settings/ActionsTab.vue')['default'] - ActiveBuilds: typeof import('./src/components/layout/header/ActiveBuilds.vue')['default'] + ActivePipelines: typeof import('./src/components/layout/header/ActivePipelines.vue')['default'] AdminSecretsTab: typeof import('./src/components/admin/settings/AdminSecretsTab.vue')['default'] BadgeTab: typeof import('./src/components/repo/settings/BadgeTab.vue')['default'] - BuildFeedItem: typeof import('./src/components/build-feed/BuildFeedItem.vue')['default'] - BuildFeedSidebar: typeof import('./src/components/build-feed/BuildFeedSidebar.vue')['default'] - BuildItem: typeof import('./src/components/repo/build/BuildItem.vue')['default'] - BuildList: typeof import('./src/components/repo/build/BuildList.vue')['default'] - BuildLog: typeof import('./src/components/repo/build/BuildLog.vue')['default'] - BuildProcDuration: typeof import('./src/components/repo/build/BuildProcDuration.vue')['default'] - BuildProcList: typeof import('./src/components/repo/build/BuildProcList.vue')['default'] - BuildRunningIcon: typeof import('./src/components/repo/build/BuildRunningIcon.vue')['default'] - BuildStatusIcon: typeof import('./src/components/repo/build/BuildStatusIcon.vue')['default'] Button: typeof import('./src/components/atomic/Button.vue')['default'] Checkbox: typeof import('./src/components/form/Checkbox.vue')['default'] CheckboxesField: typeof import('./src/components/form/CheckboxesField.vue')['default'] @@ -77,6 +68,15 @@ declare module '@vue/runtime-core' { NumberField: typeof import('./src/components/form/NumberField.vue')['default'] OrgSecretsTab: typeof import('./src/components/org/settings/OrgSecretsTab.vue')['default'] Panel: typeof import('./src/components/layout/Panel.vue')['default'] + PipelineFeedItem: typeof import('./src/components/pipeline-feed/PipelineFeedItem.vue')['default'] + PipelineFeedSidebar: typeof import('./src/components/pipeline-feed/PipelineFeedSidebar.vue')['default'] + PipelineItem: typeof import('./src/components/repo/pipeline/PipelineItem.vue')['default'] + PipelineList: typeof import('./src/components/repo/pipeline/PipelineList.vue')['default'] + PipelineLog: typeof import('./src/components/repo/pipeline/PipelineLog.vue')['default'] + PipelineProcDuration: typeof import('./src/components/repo/pipeline/PipelineProcDuration.vue')['default'] + PipelineProcList: typeof import('./src/components/repo/pipeline/PipelineProcList.vue')['default'] + PipelineRunningIcon: typeof import('./src/components/repo/pipeline/PipelineRunningIcon.vue')['default'] + PipelineStatusIcon: typeof import('./src/components/repo/pipeline/PipelineStatusIcon.vue')['default'] Popup: typeof import('./src/components/layout/Popup.vue')['default'] RadioField: typeof import('./src/components/form/RadioField.vue')['default'] RegistriesTab: typeof import('./src/components/repo/settings/RegistriesTab.vue')['default'] diff --git a/web/src/App.vue b/web/src/App.vue index 4c1a875ae..078b0c4de 100644 --- a/web/src/App.vue +++ b/web/src/App.vue @@ -8,7 +8,7 @@ - + @@ -21,8 +21,8 @@ import { computed, defineComponent } from 'vue'; import { useI18n } from 'vue-i18n'; import { useRoute } from 'vue-router'; -import BuildFeedSidebar from '~/components/build-feed/BuildFeedSidebar.vue'; import Navbar from '~/components/layout/header/Navbar.vue'; +import PipelineFeedSidebar from '~/components/pipeline-feed/PipelineFeedSidebar.vue'; import useApiClient from '~/compositions/useApiClient'; import useNotifications from '~/compositions/useNotifications'; @@ -31,7 +31,7 @@ export default defineComponent({ components: { Navbar, - BuildFeedSidebar, + PipelineFeedSidebar, }, setup() { diff --git a/web/src/assets/locales/en.json b/web/src/assets/locales/en.json index 4870f0a05..2817504b0 100644 --- a/web/src/assets/locales/en.json +++ b/web/src/assets/locales/en.json @@ -193,7 +193,7 @@ } } }, - "build": { + "pipeline": { "created": "Created", "tasks": "Tasks", "config": "Config", @@ -206,7 +206,7 @@ "pipelines_for": "Pipelines for branch \"{branch}\"", "exit_code": "exit code {exitCode}", "loading": "Loading…", - "pipeline": "Pipeline #{buildId}", + "pipeline": "Pipeline #{pipelineId}", "log_download_error": "There was an error while downloading the log file", "actions": { "cancel": "Cancel", diff --git a/web/src/components/build-feed/BuildFeedSidebar.vue b/web/src/components/build-feed/BuildFeedSidebar.vue deleted file mode 100644 index b11d93cd6..000000000 --- a/web/src/components/build-feed/BuildFeedSidebar.vue +++ /dev/null @@ -1,39 +0,0 @@ - - - diff --git a/web/src/components/layout/header/ActiveBuilds.vue b/web/src/components/layout/header/ActivePipelines.vue similarity index 79% rename from web/src/components/layout/header/ActiveBuilds.vue rename to web/src/components/layout/header/ActivePipelines.vue index ce2049853..69e31ebd4 100644 --- a/web/src/components/layout/header/ActiveBuilds.vue +++ b/web/src/components/layout/header/ActivePipelines.vue @@ -2,7 +2,7 @@ diff --git a/web/src/components/layout/header/Navbar.vue b/web/src/components/layout/header/Navbar.vue index 99ce50fb3..a61848735 100644 --- a/web/src/components/layout/header/Navbar.vue +++ b/web/src/components/layout/header/Navbar.vue @@ -34,7 +34,7 @@ :to="{ name: 'admin-settings' }" /> - + @@ -55,12 +55,12 @@ import useAuthentication from '~/compositions/useAuthentication'; import useConfig from '~/compositions/useConfig'; import { useDarkMode } from '~/compositions/useDarkMode'; -import ActiveBuilds from './ActiveBuilds.vue'; +import ActivePipelines from './ActivePipelines.vue'; export default defineComponent({ name: 'Navbar', - components: { Button, ActiveBuilds, IconButton }, + components: { Button, ActivePipelines, IconButton }, setup() { const config = useConfig(); diff --git a/web/src/components/layout/popups/ManualPipelinePopup.vue b/web/src/components/layout/popups/ManualPipelinePopup.vue index dbf500b92..8ec9296a9 100644 --- a/web/src/components/layout/popups/ManualPipelinePopup.vue +++ b/web/src/components/layout/popups/ManualPipelinePopup.vue @@ -104,14 +104,14 @@ function deleteVar(key: string) { async function triggerManualPipeline() { loading.value = true; - const build = await apiClient.createBuild(repo.value.owner, repo.value.name, payload.value); + const pipeline = await apiClient.createPipeline(repo.value.owner, repo.value.name, payload.value); emit('close'); await router.push({ - name: 'repo-build', + name: 'repo-pipeline', params: { - buildId: build.number, + pipelineId: pipeline.number, }, }); diff --git a/web/src/components/build-feed/BuildFeedItem.vue b/web/src/components/pipeline-feed/PipelineFeedItem.vue similarity index 60% rename from web/src/components/build-feed/BuildFeedItem.vue rename to web/src/components/pipeline-feed/PipelineFeedItem.vue index eee99538f..90fcf4d4a 100644 --- a/web/src/components/build-feed/BuildFeedItem.vue +++ b/web/src/components/pipeline-feed/PipelineFeedItem.vue @@ -1,8 +1,8 @@