Add "plugin" support to local backend (#2239)

and a nit to improve the clone


---
*Sponsored by Kithara Software GmbH*
This commit is contained in:
6543 2023-08-22 22:00:32 +02:00 committed by GitHub
parent 7adfa6c2ba
commit 3954d85a5b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 45 additions and 17 deletions

View file

@ -6,11 +6,7 @@ The local backend will execute the pipelines on the local system without any iso
:::note
This backend is still pretty new and can not be treated as stable. Its
implementation and configuration can change at any time. Binary releases of the
agent will be available with the release of the [1.0.0
milestone](https://github.com/woodpecker-ci/woodpecker/milestone/4), so for now
you must compile the agent by yourself, to get the local backend functionality.
<!-- TODO: remove the self-compile note after the release of the agent -->
implementation and configuration can change at any time.
:::
Since the code runs directly in the same context as the agent (same user, same
@ -92,6 +88,17 @@ steps:
[...]
```
### Plugins as Executable Binaries
```yaml
steps:
build:
image: /usr/bin/tree
```
If no commands are provided, we treat them as plugins in the usual manner.
In the context of the local backend, plugins are simply executable binaries, which can be located using their name if they are listed in `$PATH`, or through an absolute path.
### Using labels to filter tasks
You can use the [agent configuration

View file

@ -6,11 +6,7 @@ The local backend will execute the pipelines on the local system without any iso
:::note
This backend is still pretty new and can not be treated as stable. Its
implementation and configuration can change at any time. Binary releases of the
agent will be available with the release of the [1.0.0
milestone](https://github.com/woodpecker-ci/woodpecker/milestone/4), so for now
you must compile the agent by yourself, to get the local backend functionality.
<!-- TODO: remove the self-compile note after the release of the agent -->
implementation and configuration can change at any time.
:::
Since the code runs directly in the same context as the agent (same user, same

View file

@ -28,7 +28,6 @@ import (
"github.com/rs/zerolog/log"
"github.com/woodpecker-ci/woodpecker/pipeline/backend/types"
"github.com/woodpecker-ci/woodpecker/shared/constant"
)
// checkGitCloneCap check if we have the git binary on hand
@ -64,17 +63,20 @@ func (e *local) setupClone(state *workflowState) error {
// execClone executes a clone-step locally
func (e *local) execClone(ctx context.Context, step *types.Step, state *workflowState, env []string) error {
if err := e.setupClone(state); err != nil {
return fmt.Errorf("setup clone step failed: %w", err)
if scm := step.Environment["CI_REPO_SCM"]; scm != "git" {
return fmt.Errorf("local backend can only clone from git repos, but this repo use '%s'", scm)
}
if err := checkGitCloneCap(); err != nil {
return fmt.Errorf("check for git clone capabilities failed: %w", err)
}
if step.Image != constant.DefaultCloneImage {
// TODO: write message into log
log.Warn().Msgf("clone step image '%s' does not match default git clone image. We ignore it assume git.", step.Image)
if err := e.setupClone(state); err != nil {
return fmt.Errorf("setup clone step failed: %w", err)
}
if !strings.Contains(step.Image, "plugin-git") {
log.Warn().Msgf("clone step image '%s' does not match default git clone image. We ignore it and use our plugin-git anyway.", step.Image)
}
rmCmd, err := writeNetRC(step, state)

View file

@ -120,13 +120,16 @@ func (e *local) StartStep(ctx context.Context, step *types.Step, taskUUID string
return e.execClone(ctx, step, state, env)
case types.StepTypeCommands:
return e.execCommands(ctx, step, state, env)
case types.StepTypePlugin:
return e.execPlugin(ctx, step, state, env)
default:
return ErrUnsupportedStepType
}
}
// execCommands use step.Image as shell and run the commands in it
func (e *local) execCommands(ctx context.Context, step *types.Step, state *workflowState, env []string) error {
// TODO: use commands directly
// TODO: find a way to simulate commands to be exec as stdin user commands instead of generating a script and hope the shell understands
script := ""
for _, cmd := range step.Commands {
script += fmt.Sprintf("echo + %s\n%s\n", strings.TrimSpace(shellescape.Quote(cmd)), cmd)
@ -148,6 +151,26 @@ func (e *local) execCommands(ctx context.Context, step *types.Step, state *workf
return cmd.Start()
}
// execPlugin use step.Image as exec binary
func (e *local) execPlugin(ctx context.Context, step *types.Step, state *workflowState, env []string) error {
binary, err := exec.LookPath(step.Image)
if err != nil {
return fmt.Errorf("lookup plugin binary: %w", err)
}
cmd := exec.CommandContext(ctx, binary)
cmd.Env = env
cmd.Dir = state.workspaceDir
// Get output and redirect Stderr to Stdout
e.output, _ = cmd.StdoutPipe()
cmd.Stderr = cmd.Stdout
state.stepCMDs[step.Name] = cmd
return cmd.Start()
}
// WaitStep for the pipeline step to complete and returns
// the completion results.
func (e *local) WaitStep(_ context.Context, step *types.Step, taskUUID string) (*types.State, error) {