mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2024-11-29 13:21:10 +00:00
Pull in cncd/* for simpler workflow
This commit is contained in:
parent
f9f0998cd2
commit
a4541ac901
141 changed files with 6341 additions and 217 deletions
|
@ -29,11 +29,11 @@ import (
|
||||||
"google.golang.org/grpc/keepalive"
|
"google.golang.org/grpc/keepalive"
|
||||||
"google.golang.org/grpc/metadata"
|
"google.golang.org/grpc/metadata"
|
||||||
|
|
||||||
"github.com/cncd/pipeline/pipeline"
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline"
|
||||||
"github.com/cncd/pipeline/pipeline/backend"
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/backend"
|
||||||
"github.com/cncd/pipeline/pipeline/backend/docker"
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/backend/docker"
|
||||||
"github.com/cncd/pipeline/pipeline/multipart"
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/multipart"
|
||||||
"github.com/cncd/pipeline/pipeline/rpc"
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/rpc"
|
||||||
|
|
||||||
"github.com/drone/signal"
|
"github.com/drone/signal"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
|
|
|
@ -33,9 +33,9 @@ import (
|
||||||
"golang.org/x/crypto/acme/autocert"
|
"golang.org/x/crypto/acme/autocert"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
|
|
||||||
"github.com/cncd/logging"
|
"github.com/laszlocph/drone-oss-08/cncd/logging"
|
||||||
"github.com/cncd/pipeline/pipeline/rpc/proto"
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/rpc/proto"
|
||||||
"github.com/cncd/pubsub"
|
"github.com/laszlocph/drone-oss-08/cncd/pubsub"
|
||||||
"github.com/laszlocph/drone-oss-08/plugins/sender"
|
"github.com/laszlocph/drone-oss-08/plugins/sender"
|
||||||
"github.com/laszlocph/drone-oss-08/remote"
|
"github.com/laszlocph/drone-oss-08/remote"
|
||||||
"github.com/laszlocph/drone-oss-08/router"
|
"github.com/laszlocph/drone-oss-08/router"
|
||||||
|
|
|
@ -18,7 +18,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/cncd/queue"
|
"github.com/laszlocph/drone-oss-08/cncd/queue"
|
||||||
"github.com/dimfeld/httptreemux"
|
"github.com/dimfeld/httptreemux"
|
||||||
"github.com/laszlocph/drone-oss-08/model"
|
"github.com/laszlocph/drone-oss-08/model"
|
||||||
"github.com/laszlocph/drone-oss-08/plugins/registry"
|
"github.com/laszlocph/drone-oss-08/plugins/registry"
|
||||||
|
|
6
cncd/logging/README
Normal file
6
cncd/logging/README
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
Go package provides a common interface for storing and streaming logs.
|
||||||
|
|
||||||
|
Documentation:
|
||||||
|
|
||||||
|
http://godoc.org/github.com/laszlocph/drone-oss-08/cncd/logging
|
||||||
|
http://godoc.org/github.com/laszlocph/drone-oss-08/cncd/logging/gcp
|
52
cncd/logging/log_test.go
Normal file
52
cncd/logging/log_test.go
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
package logging
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLogging(t *testing.T) {
|
||||||
|
var (
|
||||||
|
wg sync.WaitGroup
|
||||||
|
|
||||||
|
testPath = "test"
|
||||||
|
testEntry = &Entry{
|
||||||
|
Data: []byte("test"),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(
|
||||||
|
context.Background(),
|
||||||
|
)
|
||||||
|
|
||||||
|
logger := New()
|
||||||
|
logger.Open(ctx, testPath)
|
||||||
|
go func() {
|
||||||
|
logger.Tail(ctx, testPath, func(entry ...*Entry) { wg.Done() })
|
||||||
|
}()
|
||||||
|
go func() {
|
||||||
|
logger.Tail(ctx, testPath, func(entry ...*Entry) { wg.Done() })
|
||||||
|
}()
|
||||||
|
|
||||||
|
<-time.After(time.Millisecond)
|
||||||
|
|
||||||
|
wg.Add(4)
|
||||||
|
go func() {
|
||||||
|
logger.Write(ctx, testPath, testEntry)
|
||||||
|
logger.Write(ctx, testPath, testEntry)
|
||||||
|
}()
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
logger.Tail(ctx, testPath, func(entry ...*Entry) { wg.Done() })
|
||||||
|
}()
|
||||||
|
|
||||||
|
<-time.After(time.Millisecond)
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
cancel()
|
||||||
|
}
|
15
cncd/pipeline/.drone.yml
Normal file
15
cncd/pipeline/.drone.yml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
workspace:
|
||||||
|
base: /go
|
||||||
|
path: src/github.com/laszlocph/drone-oss-08/cncd/pipeline
|
||||||
|
|
||||||
|
pipeline:
|
||||||
|
install:
|
||||||
|
image: golang:1.8
|
||||||
|
commands:
|
||||||
|
- go install github.com/laszlocph/drone-oss-08/cncd/pipeline/pipec
|
||||||
|
- go install github.com/laszlocph/drone-oss-08/cncd/pipeline/piped
|
||||||
|
|
||||||
|
test:
|
||||||
|
image: golang:1.8
|
||||||
|
commands:
|
||||||
|
- go test -cover github.com/laszlocph/drone-oss-08/cncd/pipeline/...
|
2
cncd/pipeline/.gitignore
vendored
Normal file
2
cncd/pipeline/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
*.txt
|
||||||
|
*.out
|
1
cncd/pipeline/doc.go
Normal file
1
cncd/pipeline/doc.go
Normal file
|
@ -0,0 +1 @@
|
||||||
|
package pipeline
|
507
cncd/pipeline/pipec/compile.go
Normal file
507
cncd/pipeline/pipec/compile.go
Normal file
|
@ -0,0 +1,507 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/frontend"
|
||||||
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/frontend/yaml"
|
||||||
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/frontend/yaml/compiler"
|
||||||
|
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
var compileCommand = cli.Command{
|
||||||
|
Name: "compile",
|
||||||
|
Usage: "compile the yaml file",
|
||||||
|
Action: compileAction,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "in",
|
||||||
|
Value: "pipeline.yml",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "out",
|
||||||
|
Value: "pipeline.json",
|
||||||
|
},
|
||||||
|
cli.StringSliceFlag{
|
||||||
|
Name: "volumes",
|
||||||
|
},
|
||||||
|
cli.StringSliceFlag{
|
||||||
|
Name: "privileged",
|
||||||
|
Value: &cli.StringSlice{
|
||||||
|
"plugins/docker",
|
||||||
|
"plugins/gcr",
|
||||||
|
"plugins/ecr",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "prefix",
|
||||||
|
Value: "pipeline",
|
||||||
|
},
|
||||||
|
cli.BoolFlag{
|
||||||
|
Name: "local",
|
||||||
|
},
|
||||||
|
//
|
||||||
|
// volume caching
|
||||||
|
//
|
||||||
|
cli.BoolFlag{
|
||||||
|
Name: "volume-cache",
|
||||||
|
EnvVar: "CI_VOLUME_CACHE",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "volume-cache-base",
|
||||||
|
Value: "/var/lib/drone",
|
||||||
|
EnvVar: "CI_VOLUME_CACHE_BASE",
|
||||||
|
},
|
||||||
|
//
|
||||||
|
// s3 caching
|
||||||
|
//
|
||||||
|
cli.BoolFlag{
|
||||||
|
Name: "aws-cache",
|
||||||
|
EnvVar: "CI_AWS_CACHE",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "aws-region",
|
||||||
|
EnvVar: "AWS_REGION",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "aws-bucket",
|
||||||
|
EnvVar: "AWS_BUCKET",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "aws-access-key-id",
|
||||||
|
EnvVar: "AWS_ACCESS_KEY_ID",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "aws-secret-access-key",
|
||||||
|
EnvVar: "AWS_SECRET_ACCESS_KEY",
|
||||||
|
},
|
||||||
|
//
|
||||||
|
// registry credentials
|
||||||
|
//
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "registry-hostname",
|
||||||
|
EnvVar: "CI_REGISTRY_HOSTNAME",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "registry-username",
|
||||||
|
EnvVar: "CI_REGISTRY_USERNAME",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "registry-password",
|
||||||
|
EnvVar: "CI_REGISTRY_PASSWORD",
|
||||||
|
},
|
||||||
|
//
|
||||||
|
// workspace default
|
||||||
|
//
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "workspace-base",
|
||||||
|
Value: "/pipeline",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "workspace-path",
|
||||||
|
Value: "src",
|
||||||
|
},
|
||||||
|
//
|
||||||
|
// netrc parameters
|
||||||
|
//
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "netrc-username",
|
||||||
|
EnvVar: "CI_NETRC_USERNAME",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "netrc-password",
|
||||||
|
EnvVar: "CI_NETRC_PASSWORD",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "netrc-machine",
|
||||||
|
EnvVar: "CI_NETRC_MACHINE",
|
||||||
|
},
|
||||||
|
//
|
||||||
|
// resource limit parameters
|
||||||
|
//
|
||||||
|
cli.Int64Flag{
|
||||||
|
Name: "limit-mem-swap",
|
||||||
|
EnvVar: "CI_LIMIT_MEM_SWAP",
|
||||||
|
},
|
||||||
|
cli.Int64Flag{
|
||||||
|
Name: "limit-mem",
|
||||||
|
EnvVar: "CI_LIMIT_MEM",
|
||||||
|
},
|
||||||
|
cli.Int64Flag{
|
||||||
|
Name: "limit-shm-size",
|
||||||
|
EnvVar: "CI_LIMIT_SHM_SIZE",
|
||||||
|
},
|
||||||
|
cli.Int64Flag{
|
||||||
|
Name: "limit-cpu-quota",
|
||||||
|
EnvVar: "CI_LIMIT_CPU_QUOTA",
|
||||||
|
},
|
||||||
|
cli.Int64Flag{
|
||||||
|
Name: "limit-cpu-shares",
|
||||||
|
EnvVar: "CI_LIMIT_CPU_SHARES",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "limit-cpu-set",
|
||||||
|
EnvVar: "CI_LIMIT_CPU_SET",
|
||||||
|
},
|
||||||
|
//
|
||||||
|
// metadata parameters
|
||||||
|
//
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "system-arch",
|
||||||
|
Value: "linux/amd64",
|
||||||
|
EnvVar: "CI_SYSTEM_ARCH",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "system-name",
|
||||||
|
Value: "pipec",
|
||||||
|
EnvVar: "CI_SYSTEM_NAME",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "system-link",
|
||||||
|
Value: "https://github.com/cncd/pipec",
|
||||||
|
EnvVar: "CI_SYSTEM_LINK",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "repo-name",
|
||||||
|
EnvVar: "CI_REPO_NAME",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "repo-link",
|
||||||
|
EnvVar: "CI_REPO_LINK",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "repo-remote-url",
|
||||||
|
EnvVar: "CI_REPO_REMOTE",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "repo-private",
|
||||||
|
EnvVar: "CI_REPO_PRIVATE",
|
||||||
|
},
|
||||||
|
cli.IntFlag{
|
||||||
|
Name: "build-number",
|
||||||
|
EnvVar: "CI_BUILD_NUMBER",
|
||||||
|
},
|
||||||
|
cli.Int64Flag{
|
||||||
|
Name: "build-created",
|
||||||
|
EnvVar: "CI_BUILD_CREATED",
|
||||||
|
},
|
||||||
|
cli.Int64Flag{
|
||||||
|
Name: "build-started",
|
||||||
|
EnvVar: "CI_BUILD_STARTED",
|
||||||
|
},
|
||||||
|
cli.Int64Flag{
|
||||||
|
Name: "build-finished",
|
||||||
|
EnvVar: "CI_BUILD_FINISHED",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "build-status",
|
||||||
|
EnvVar: "CI_BUILD_STATUS",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "build-event",
|
||||||
|
EnvVar: "CI_BUILD_EVENT",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "build-link",
|
||||||
|
EnvVar: "CI_BUILD_LINK",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "build-target",
|
||||||
|
EnvVar: "CI_BUILD_TARGET",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "commit-sha",
|
||||||
|
EnvVar: "CI_COMMIT_SHA",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "commit-ref",
|
||||||
|
EnvVar: "CI_COMMIT_REF",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "commit-refspec",
|
||||||
|
EnvVar: "CI_COMMIT_REFSPEC",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "commit-branch",
|
||||||
|
EnvVar: "CI_COMMIT_BRANCH",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "commit-message",
|
||||||
|
EnvVar: "CI_COMMIT_MESSAGE",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "commit-author-name",
|
||||||
|
EnvVar: "CI_COMMIT_AUTHOR_NAME",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "commit-author-avatar",
|
||||||
|
EnvVar: "CI_COMMIT_AUTHOR_AVATAR",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "commit-author-email",
|
||||||
|
EnvVar: "CI_COMMIT_AUTHOR_EMAIL",
|
||||||
|
},
|
||||||
|
cli.IntFlag{
|
||||||
|
Name: "prev-build-number",
|
||||||
|
EnvVar: "CI_PREV_BUILD_NUMBER",
|
||||||
|
},
|
||||||
|
cli.Int64Flag{
|
||||||
|
Name: "prev-build-created",
|
||||||
|
EnvVar: "CI_PREV_BUILD_CREATED",
|
||||||
|
},
|
||||||
|
cli.Int64Flag{
|
||||||
|
Name: "prev-build-started",
|
||||||
|
EnvVar: "CI_PREV_BUILD_STARTED",
|
||||||
|
},
|
||||||
|
cli.Int64Flag{
|
||||||
|
Name: "prev-build-finished",
|
||||||
|
EnvVar: "CI_PREV_BUILD_FINISHED",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "prev-build-status",
|
||||||
|
EnvVar: "CI_PREV_BUILD_STATUS",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "prev-build-event",
|
||||||
|
EnvVar: "CI_PREV_BUILD_EVENT",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "prev-build-link",
|
||||||
|
EnvVar: "CI_PREV_BUILD_LINK",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "prev-commit-sha",
|
||||||
|
EnvVar: "CI_PREV_COMMIT_SHA",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "prev-commit-ref",
|
||||||
|
EnvVar: "CI_PREV_COMMIT_REF",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "prev-commit-refspec",
|
||||||
|
EnvVar: "CI_PREV_COMMIT_REFSPEC",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "prev-commit-branch",
|
||||||
|
EnvVar: "CI_PREV_COMMIT_BRANCH",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "prev-commit-message",
|
||||||
|
EnvVar: "CI_PREV_COMMIT_MESSAGE",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "prev-commit-author-name",
|
||||||
|
EnvVar: "CI_PREV_COMMIT_AUTHOR_NAME",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "prev-commit-author-avatar",
|
||||||
|
EnvVar: "CI_PREV_COMMIT_AUTHOR_AVATAR",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "prev-commit-author-email",
|
||||||
|
EnvVar: "CI_PREV_COMMIT_AUTHOR_EMAIL",
|
||||||
|
},
|
||||||
|
cli.IntFlag{
|
||||||
|
Name: "job-number",
|
||||||
|
EnvVar: "CI_JOB_NUMBER",
|
||||||
|
},
|
||||||
|
// cli.StringFlag{
|
||||||
|
// Name: "job-matrix",
|
||||||
|
// EnvVar: "CI_JOB_MATRIX",
|
||||||
|
// },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func compileAction(c *cli.Context) (err error) {
|
||||||
|
file := c.Args().First()
|
||||||
|
if file == "" {
|
||||||
|
file = c.String("in")
|
||||||
|
}
|
||||||
|
|
||||||
|
conf, err := yaml.ParseFile(file)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// configure volumes for local execution
|
||||||
|
volumes := c.StringSlice("volumes")
|
||||||
|
if c.Bool("local") {
|
||||||
|
var (
|
||||||
|
workspaceBase = conf.Workspace.Base
|
||||||
|
workspacePath = conf.Workspace.Path
|
||||||
|
)
|
||||||
|
if workspaceBase == "" {
|
||||||
|
workspaceBase = c.String("workspace-base")
|
||||||
|
}
|
||||||
|
if workspacePath == "" {
|
||||||
|
workspacePath = c.String("workspace-path")
|
||||||
|
}
|
||||||
|
dir, _ := filepath.Abs(filepath.Dir(file))
|
||||||
|
volumes = append(volumes, dir+":"+path.Join(workspaceBase, workspacePath))
|
||||||
|
}
|
||||||
|
|
||||||
|
// secrets from environment variable
|
||||||
|
var secrets []compiler.Secret
|
||||||
|
for _, env := range os.Environ() {
|
||||||
|
parts := strings.Split(env, "=")
|
||||||
|
secrets = append(secrets, compiler.Secret{
|
||||||
|
Name: parts[0],
|
||||||
|
Value: parts[1],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// compiles the yaml file
|
||||||
|
compiled := compiler.New(
|
||||||
|
compiler.WithResourceLimit(
|
||||||
|
c.Int64("limit-mem-swap"),
|
||||||
|
c.Int64("limit-mem"),
|
||||||
|
c.Int64("limit-shm-size"),
|
||||||
|
c.Int64("limit-cpu-quota"),
|
||||||
|
c.Int64("limit-cpu-shares"),
|
||||||
|
c.String("limit-cpu-set"),
|
||||||
|
),
|
||||||
|
compiler.WithRegistry(
|
||||||
|
compiler.Registry{
|
||||||
|
Hostname: c.String("registry-hostname"),
|
||||||
|
Username: c.String("registry-username"),
|
||||||
|
Password: c.String("registry-password"),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
compiler.WithEscalated(
|
||||||
|
c.StringSlice("privileged")...,
|
||||||
|
),
|
||||||
|
compiler.WithSecret(secrets...),
|
||||||
|
compiler.WithVolumes(volumes...),
|
||||||
|
compiler.WithWorkspace(
|
||||||
|
c.String("workspace-base"),
|
||||||
|
c.String("workspace-path"),
|
||||||
|
),
|
||||||
|
compiler.WithPrefix(
|
||||||
|
c.String("prefix"),
|
||||||
|
),
|
||||||
|
compiler.WithProxy(),
|
||||||
|
compiler.WithLocal(
|
||||||
|
c.Bool("local"),
|
||||||
|
),
|
||||||
|
compiler.WithNetrc(
|
||||||
|
c.String("netrc-username"),
|
||||||
|
c.String("netrc-password"),
|
||||||
|
c.String("netrc-machine"),
|
||||||
|
),
|
||||||
|
compiler.WithMetadata(
|
||||||
|
metadataFromContext(c),
|
||||||
|
),
|
||||||
|
compiler.WithOption(
|
||||||
|
compiler.WithVolumeCacher(
|
||||||
|
c.String("volume-cache-base"),
|
||||||
|
),
|
||||||
|
c.Bool("volume-cache"),
|
||||||
|
),
|
||||||
|
compiler.WithOption(
|
||||||
|
compiler.WithS3Cacher(
|
||||||
|
c.String("aws-access-key-id"),
|
||||||
|
c.String("aws-secret-access-key"),
|
||||||
|
c.String("aws-region"),
|
||||||
|
c.String("aws-bucket"),
|
||||||
|
),
|
||||||
|
c.Bool("aws-cache"),
|
||||||
|
),
|
||||||
|
).Compile(conf)
|
||||||
|
|
||||||
|
// marshal the compiled spec to formatted yaml
|
||||||
|
out, err := json.MarshalIndent(compiled, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// create output file with option to dump to stdout
|
||||||
|
var writer = os.Stdout
|
||||||
|
output := c.String("out")
|
||||||
|
if output != "-" {
|
||||||
|
writer, err = os.Create(output)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defer writer.Close()
|
||||||
|
|
||||||
|
_, err = writer.Write(out)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if writer != os.Stdout {
|
||||||
|
fmt.Fprintf(os.Stdout, "Successfully compiled %s to %s\n", file, output)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the metadata from the cli context.
|
||||||
|
func metadataFromContext(c *cli.Context) frontend.Metadata {
|
||||||
|
return frontend.Metadata{
|
||||||
|
Repo: frontend.Repo{
|
||||||
|
Name: c.String("repo-name"),
|
||||||
|
Link: c.String("repo-link"),
|
||||||
|
Remote: c.String("repo-remote-url"),
|
||||||
|
Private: c.Bool("repo-private"),
|
||||||
|
},
|
||||||
|
Curr: frontend.Build{
|
||||||
|
Number: c.Int("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"),
|
||||||
|
Commit: frontend.Commit{
|
||||||
|
Sha: c.String("commit-sha"),
|
||||||
|
Ref: c.String("commit-ref"),
|
||||||
|
Refspec: c.String("commit-refspec"),
|
||||||
|
Branch: c.String("commit-branch"),
|
||||||
|
Message: c.String("commit-message"),
|
||||||
|
Author: frontend.Author{
|
||||||
|
Name: c.String("commit-author-name"),
|
||||||
|
Email: c.String("commit-author-email"),
|
||||||
|
Avatar: c.String("commit-author-avatar"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Prev: frontend.Build{
|
||||||
|
Number: c.Int("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"),
|
||||||
|
Commit: frontend.Commit{
|
||||||
|
Sha: c.String("prev-commit-sha"),
|
||||||
|
Ref: c.String("prev-commit-ref"),
|
||||||
|
Refspec: c.String("prev-commit-refspec"),
|
||||||
|
Branch: c.String("prev-commit-branch"),
|
||||||
|
Message: c.String("prev-commit-message"),
|
||||||
|
Author: frontend.Author{
|
||||||
|
Name: c.String("prev-commit-author-name"),
|
||||||
|
Email: c.String("prev-commit-author-email"),
|
||||||
|
Avatar: c.String("prev-commit-author-avatar"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Job: frontend.Job{
|
||||||
|
Number: c.Int("job-number"),
|
||||||
|
// Matrix: ,
|
||||||
|
},
|
||||||
|
Sys: frontend.System{
|
||||||
|
Name: c.String("system-name"),
|
||||||
|
Link: c.String("system-link"),
|
||||||
|
Arch: c.String("system-arch"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
123
cncd/pipeline/pipec/exec.go
Normal file
123
cncd/pipeline/pipec/exec.go
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline"
|
||||||
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/backend"
|
||||||
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/backend/docker"
|
||||||
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/backend/kubernetes"
|
||||||
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/interrupt"
|
||||||
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/multipart"
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
var executeCommand = cli.Command{
|
||||||
|
Name: "exec",
|
||||||
|
Usage: "execute the compiled file",
|
||||||
|
Action: executeAction,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "in",
|
||||||
|
Value: "pipeline.json",
|
||||||
|
},
|
||||||
|
cli.DurationFlag{
|
||||||
|
Name: "timeout",
|
||||||
|
EnvVar: "CI_TIMEOUT",
|
||||||
|
Value: time.Hour,
|
||||||
|
},
|
||||||
|
cli.BoolFlag{
|
||||||
|
Name: "kubernetes",
|
||||||
|
EnvVar: "CI_KUBERNETES",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "kubernetes-namepsace",
|
||||||
|
EnvVar: "CI_KUBERNETES_NAMESPACE",
|
||||||
|
Value: "default",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "kubernetes-endpoint",
|
||||||
|
EnvVar: "CI_KUBERNETES_ENDPOINT",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "kubernetes-token",
|
||||||
|
EnvVar: "CI_KUBERNETES_TOKEN",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func executeAction(c *cli.Context) (err error) {
|
||||||
|
path := c.Args().First()
|
||||||
|
if path == "" {
|
||||||
|
path = c.String("in")
|
||||||
|
}
|
||||||
|
|
||||||
|
var reader io.ReadCloser
|
||||||
|
if path == "-" {
|
||||||
|
reader = os.Stdin
|
||||||
|
} else {
|
||||||
|
reader, err = os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defer reader.Close()
|
||||||
|
|
||||||
|
config, err := pipeline.Parse(reader)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var engine backend.Engine
|
||||||
|
if c.Bool("kubernetes") {
|
||||||
|
engine = kubernetes.New(
|
||||||
|
c.String("kubernetes-namepsace"),
|
||||||
|
c.String("kubernetes-endpoint"),
|
||||||
|
c.String("kubernetes-token"),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
engine, err = docker.NewEnv()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), c.Duration("timeout"))
|
||||||
|
defer cancel()
|
||||||
|
ctx = interrupt.WithContext(ctx)
|
||||||
|
|
||||||
|
return pipeline.New(config,
|
||||||
|
pipeline.WithContext(ctx),
|
||||||
|
pipeline.WithLogger(defaultLogger),
|
||||||
|
pipeline.WithTracer(defaultTracer),
|
||||||
|
pipeline.WithEngine(engine),
|
||||||
|
).Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
var defaultLogger = pipeline.LogFunc(func(proc *backend.Step, rc multipart.Reader) error {
|
||||||
|
part, err := rc.NextPart()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
io.Copy(os.Stderr, part)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
var defaultTracer = pipeline.TraceFunc(func(state *pipeline.State) error {
|
||||||
|
if state.Process.Exited {
|
||||||
|
fmt.Printf("proc %q exited with status %d\n", state.Pipeline.Step.Name, state.Process.ExitCode)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("proc %q started\n", state.Pipeline.Step.Name)
|
||||||
|
state.Pipeline.Step.Environment["CI_BUILD_STATUS"] = "success"
|
||||||
|
state.Pipeline.Step.Environment["CI_BUILD_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
|
||||||
|
if state.Pipeline.Error != nil {
|
||||||
|
state.Pipeline.Step.Environment["CI_BUILD_STATUS"] = "failure"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
54
cncd/pipeline/pipec/lint.go
Normal file
54
cncd/pipeline/pipec/lint.go
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/frontend/yaml"
|
||||||
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/frontend/yaml/linter"
|
||||||
|
|
||||||
|
"github.com/kr/pretty"
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
var lintCommand = cli.Command{
|
||||||
|
Name: "lint",
|
||||||
|
Usage: "lints the yaml file",
|
||||||
|
Action: lintAction,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
cli.BoolFlag{
|
||||||
|
Name: "trusted",
|
||||||
|
},
|
||||||
|
cli.BoolFlag{
|
||||||
|
Name: "pretty",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func lintAction(c *cli.Context) error {
|
||||||
|
file := c.Args().First()
|
||||||
|
if file == "" {
|
||||||
|
return fmt.Errorf("Error: please provide a path the configuration file")
|
||||||
|
}
|
||||||
|
|
||||||
|
conf, err := yaml.ParseFile(file)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = linter.New(
|
||||||
|
linter.WithTrusted(
|
||||||
|
c.Bool("trusted"),
|
||||||
|
),
|
||||||
|
).Lint(conf)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Bool("pretty") {
|
||||||
|
pretty.Println(conf)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Lint complete. Yaml file is valid")
|
||||||
|
return nil
|
||||||
|
}
|
26
cncd/pipeline/pipec/main.go
Normal file
26
cncd/pipeline/pipec/main.go
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
|
||||||
|
_ "github.com/joho/godotenv/autoload"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := cli.NewApp()
|
||||||
|
app.Name = "pipec"
|
||||||
|
app.Usage = "pipec provides command line tools for the cncd runtime"
|
||||||
|
app.Commands = []cli.Command{
|
||||||
|
compileCommand,
|
||||||
|
executeCommand,
|
||||||
|
lintCommand,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := app.Run(os.Args); err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
314
cncd/pipeline/piped/main.go
Normal file
314
cncd/pipeline/piped/main.go
Normal file
|
@ -0,0 +1,314 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"math"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline"
|
||||||
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/backend"
|
||||||
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/backend/docker"
|
||||||
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/interrupt"
|
||||||
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/multipart"
|
||||||
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/rpc"
|
||||||
|
|
||||||
|
_ "github.com/joho/godotenv/autoload"
|
||||||
|
"github.com/tevino/abool"
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
maxFileUpload = 5000000
|
||||||
|
maxLogsUpload = 5000000
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := cli.NewApp()
|
||||||
|
app.Name = "piped"
|
||||||
|
app.Usage = "piped stars a pipeline execution daemon"
|
||||||
|
app.Action = start
|
||||||
|
app.Flags = []cli.Flag{
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "endpoint",
|
||||||
|
EnvVar: "PIPED_ENDPOINT,PIPED_SERVER",
|
||||||
|
Value: "ws://localhost:9999",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "token",
|
||||||
|
EnvVar: "PIPED_TOKEN,PIPED_SECRET",
|
||||||
|
},
|
||||||
|
cli.DurationFlag{
|
||||||
|
Name: "backoff",
|
||||||
|
EnvVar: "PIPED_BACKOFF",
|
||||||
|
Value: time.Second * 15,
|
||||||
|
},
|
||||||
|
cli.IntFlag{
|
||||||
|
Name: "retry-limit",
|
||||||
|
EnvVar: "PIPED_RETRY_LIMIT",
|
||||||
|
Value: math.MaxInt32,
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "platform",
|
||||||
|
EnvVar: "PIPED_PLATFORM",
|
||||||
|
Value: "linux/amd64",
|
||||||
|
},
|
||||||
|
cli.Int64Flag{
|
||||||
|
Name: "upload-limit",
|
||||||
|
EnvVar: "PIPED_UPLOAD_LIMIT",
|
||||||
|
Value: math.MaxInt32,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
app.Commands = []cli.Command{
|
||||||
|
onceCommand,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := app.Run(os.Args); err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func start(c *cli.Context) error {
|
||||||
|
endpoint, err := url.Parse(
|
||||||
|
c.String("endpoint"),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
filter := rpc.Filter{
|
||||||
|
Labels: map[string]string{
|
||||||
|
"platform": c.String("platform"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err := rpc.NewClient(
|
||||||
|
endpoint.String(),
|
||||||
|
rpc.WithRetryLimit(
|
||||||
|
c.Int("retry-limit"),
|
||||||
|
),
|
||||||
|
rpc.WithBackoff(
|
||||||
|
c.Duration("backoff"),
|
||||||
|
),
|
||||||
|
rpc.WithToken(
|
||||||
|
c.String("token"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer client.Close()
|
||||||
|
|
||||||
|
sigterm := abool.New()
|
||||||
|
ctx := context.Background()
|
||||||
|
ctx = interrupt.WithContextFunc(ctx, func() {
|
||||||
|
println("ctrl+c received, terminating process")
|
||||||
|
sigterm.Set()
|
||||||
|
})
|
||||||
|
|
||||||
|
for {
|
||||||
|
if sigterm.IsSet() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if err := run(ctx, client, filter); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func run(ctx context.Context, client rpc.Peer, filter rpc.Filter) error {
|
||||||
|
log.Println("pipeline: request next execution")
|
||||||
|
|
||||||
|
// get the next job from the queue
|
||||||
|
work, err := client.Next(ctx, filter)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if work == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
log.Printf("pipeline: received next execution: %s", work.ID)
|
||||||
|
if os.Getenv("SUICIDE_MODE") != "" {
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
// new docker engine
|
||||||
|
engine, err := docker.NewEnv()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
timeout := time.Hour
|
||||||
|
if minutes := work.Timeout; minutes != 0 {
|
||||||
|
timeout = time.Duration(minutes) * time.Minute
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
cancelled := abool.New()
|
||||||
|
go func() {
|
||||||
|
werr := client.Wait(ctx, work.ID)
|
||||||
|
if werr != nil {
|
||||||
|
cancelled.SetTo(true) // TODO verify error is really an error
|
||||||
|
log.Printf("pipeline: cancel signal received: %s: %s", work.ID, werr)
|
||||||
|
cancel()
|
||||||
|
} else {
|
||||||
|
log.Printf("pipeline: cancel channel closed: %s", work.ID)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
log.Printf("pipeline: cancel ping loop: %s", work.ID)
|
||||||
|
return
|
||||||
|
case <-time.After(time.Minute):
|
||||||
|
log.Printf("pipeline: ping queue: %s", work.ID)
|
||||||
|
client.Extend(ctx, work.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
state := rpc.State{}
|
||||||
|
state.Started = time.Now().Unix()
|
||||||
|
err = client.Init(context.Background(), work.ID, state)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("pipeline: error signaling pipeline init: %s: %s", work.ID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var uploads sync.WaitGroup
|
||||||
|
defaultLogger := pipeline.LogFunc(func(proc *backend.Step, rc multipart.Reader) error {
|
||||||
|
part, rerr := rc.NextPart()
|
||||||
|
if rerr != nil {
|
||||||
|
return rerr
|
||||||
|
}
|
||||||
|
uploads.Add(1)
|
||||||
|
|
||||||
|
var secrets []string
|
||||||
|
for _, secret := range work.Config.Secrets {
|
||||||
|
if secret.Mask {
|
||||||
|
secrets = append(secrets, secret.Value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
limitedPart := io.LimitReader(part, maxLogsUpload)
|
||||||
|
logstream := rpc.NewLineWriter(client, work.ID, proc.Alias, secrets...)
|
||||||
|
io.Copy(logstream, limitedPart)
|
||||||
|
|
||||||
|
file := &rpc.File{}
|
||||||
|
file.Mime = "application/json+logs"
|
||||||
|
file.Proc = proc.Alias
|
||||||
|
file.Name = "logs.json"
|
||||||
|
file.Data, _ = json.Marshal(logstream.Lines())
|
||||||
|
file.Size = len(file.Data)
|
||||||
|
file.Time = time.Now().Unix()
|
||||||
|
|
||||||
|
if serr := client.Upload(context.Background(), work.ID, file); serr != nil {
|
||||||
|
log.Printf("pipeline: cannot upload logs: %s: %s: %s", work.ID, file.Mime, serr)
|
||||||
|
} else {
|
||||||
|
log.Printf("pipeline: finish uploading logs: %s: step %s: %s", file.Mime, work.ID, proc.Alias)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
log.Printf("pipeline: finish uploading logs: %s: step %s", work.ID, proc.Alias)
|
||||||
|
uploads.Done()
|
||||||
|
}()
|
||||||
|
|
||||||
|
part, rerr = rc.NextPart()
|
||||||
|
if rerr != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// TODO should be configurable
|
||||||
|
limitedPart = io.LimitReader(part, maxFileUpload)
|
||||||
|
file = &rpc.File{}
|
||||||
|
file.Mime = part.Header().Get("Content-Type")
|
||||||
|
file.Proc = proc.Alias
|
||||||
|
file.Name = part.FileName()
|
||||||
|
file.Data, _ = ioutil.ReadAll(limitedPart)
|
||||||
|
file.Size = len(file.Data)
|
||||||
|
file.Time = time.Now().Unix()
|
||||||
|
|
||||||
|
if serr := client.Upload(context.Background(), work.ID, file); serr != nil {
|
||||||
|
log.Printf("pipeline: cannot upload artifact: %s: %s: %s", work.ID, file.Mime, serr)
|
||||||
|
} else {
|
||||||
|
log.Printf("pipeline: finish uploading artifact: %s: step %s: %s", file.Mime, work.ID, proc.Alias)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
defaultTracer := pipeline.TraceFunc(func(state *pipeline.State) error {
|
||||||
|
procState := rpc.State{
|
||||||
|
Proc: state.Pipeline.Step.Alias,
|
||||||
|
Exited: state.Process.Exited,
|
||||||
|
ExitCode: state.Process.ExitCode,
|
||||||
|
Started: time.Now().Unix(), // TODO do not do this
|
||||||
|
Finished: time.Now().Unix(),
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if uerr := client.Update(context.Background(), work.ID, procState); uerr != nil {
|
||||||
|
log.Printf("Pipeine: error updating pipeline step status: %s: %s: %s", work.ID, procState.Proc, uerr)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
if state.Process.Exited {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if state.Pipeline.Step.Environment == nil {
|
||||||
|
state.Pipeline.Step.Environment = map[string]string{}
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
|
||||||
|
state.Pipeline.Step.Environment["CI_JOB_STATUS"] = "success"
|
||||||
|
state.Pipeline.Step.Environment["CI_JOB_STARTED"] = strconv.FormatInt(state.Pipeline.Time, 10)
|
||||||
|
state.Pipeline.Step.Environment["CI_JOB_FINISHED"] = strconv.FormatInt(time.Now().Unix(), 10)
|
||||||
|
|
||||||
|
if state.Pipeline.Error != nil {
|
||||||
|
state.Pipeline.Step.Environment["CI_BUILD_STATUS"] = "failure"
|
||||||
|
state.Pipeline.Step.Environment["CI_JOB_STATUS"] = "failure"
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
err = pipeline.New(work.Config,
|
||||||
|
pipeline.WithContext(ctx),
|
||||||
|
pipeline.WithLogger(defaultLogger),
|
||||||
|
pipeline.WithTracer(defaultTracer),
|
||||||
|
pipeline.WithEngine(engine),
|
||||||
|
).Run()
|
||||||
|
|
||||||
|
state.Finished = time.Now().Unix()
|
||||||
|
state.Exited = true
|
||||||
|
if err != nil {
|
||||||
|
state.Error = err.Error()
|
||||||
|
if xerr, ok := err.(*pipeline.ExitError); ok {
|
||||||
|
state.ExitCode = xerr.Code
|
||||||
|
}
|
||||||
|
if xerr, ok := err.(*pipeline.OomError); ok {
|
||||||
|
state.ExitCode = xerr.Code
|
||||||
|
}
|
||||||
|
if cancelled.IsSet() {
|
||||||
|
state.ExitCode = 130
|
||||||
|
} else if state.ExitCode == 0 {
|
||||||
|
state.ExitCode = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("pipeline: execution complete: %s", work.ID)
|
||||||
|
|
||||||
|
uploads.Wait()
|
||||||
|
|
||||||
|
err = client.Done(context.Background(), work.ID, state)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Pipeine: error signaling pipeline done: %s: %s", work.ID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
97
cncd/pipeline/piped/once.go
Normal file
97
cncd/pipeline/piped/once.go
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"math"
|
||||||
|
"net/url"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/interrupt"
|
||||||
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/rpc"
|
||||||
|
|
||||||
|
_ "github.com/joho/godotenv/autoload"
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
var onceCommand = cli.Command{
|
||||||
|
Name: "once",
|
||||||
|
Usage: "execute one build",
|
||||||
|
Hidden: false,
|
||||||
|
Action: once,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "endpoint",
|
||||||
|
EnvVar: "PIPED_ENDPOINT,PIPED_SERVER",
|
||||||
|
Value: "ws://localhost:9999",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "token",
|
||||||
|
EnvVar: "PIPED_TOKEN,PIPED_SECRET",
|
||||||
|
},
|
||||||
|
cli.DurationFlag{
|
||||||
|
Name: "backoff",
|
||||||
|
EnvVar: "PIPED_BACKOFF",
|
||||||
|
Value: time.Second * 15,
|
||||||
|
},
|
||||||
|
cli.IntFlag{
|
||||||
|
Name: "retry-limit",
|
||||||
|
EnvVar: "PIPED_RETRY_LIMIT",
|
||||||
|
Value: math.MaxInt32,
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "platform",
|
||||||
|
EnvVar: "PIPED_PLATFORM",
|
||||||
|
Value: "linux/amd64",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "json",
|
||||||
|
EnvVar: "PIPED_JSON",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func once(c *cli.Context) error {
|
||||||
|
endpoint, err := url.Parse(
|
||||||
|
c.String("endpoint"),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err := rpc.NewClient(
|
||||||
|
endpoint.String(),
|
||||||
|
rpc.WithRetryLimit(
|
||||||
|
c.Int("retry-limit"),
|
||||||
|
),
|
||||||
|
rpc.WithBackoff(
|
||||||
|
c.Duration("backoff"),
|
||||||
|
),
|
||||||
|
rpc.WithToken(
|
||||||
|
c.String("token"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer client.Close()
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
ctx = interrupt.WithContextFunc(ctx, func() {
|
||||||
|
println("ctrl+c received, terminating process")
|
||||||
|
})
|
||||||
|
|
||||||
|
return run(ctx, &onceClient{client, c.String("json")}, rpc.NoFilter)
|
||||||
|
}
|
||||||
|
|
||||||
|
type onceClient struct {
|
||||||
|
*rpc.Client
|
||||||
|
json string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *onceClient) Next(ctx context.Context, filter rpc.Filter) (*rpc.Pipeline, error) {
|
||||||
|
in := []byte(c.json)
|
||||||
|
out := new(rpc.Pipeline)
|
||||||
|
err := json.Unmarshal(in, out)
|
||||||
|
return out, err
|
||||||
|
}
|
|
@ -3,9 +3,10 @@ package docker
|
||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/cncd/pipeline/pipeline/backend"
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/backend"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
)
|
)
|
||||||
|
@ -82,7 +83,10 @@ func toHostConfig(proc *backend.Step) *container.HostConfig {
|
||||||
config.Tmpfs[path] = ""
|
config.Tmpfs[path] = ""
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
parts := strings.Split(path, ":")
|
parts, err := splitVolumeParts(path)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
config.Tmpfs[parts[0]] = parts[1]
|
config.Tmpfs[parts[0]] = parts[1]
|
||||||
}
|
}
|
||||||
// if proc.OomKillDisable {
|
// if proc.OomKillDisable {
|
||||||
|
@ -97,7 +101,10 @@ func toHostConfig(proc *backend.Step) *container.HostConfig {
|
||||||
func toVol(paths []string) map[string]struct{} {
|
func toVol(paths []string) map[string]struct{} {
|
||||||
set := map[string]struct{}{}
|
set := map[string]struct{}{}
|
||||||
for _, path := range paths {
|
for _, path := range paths {
|
||||||
parts := strings.Split(path, ":")
|
parts, err := splitVolumeParts(path)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
if len(parts) < 2 {
|
if len(parts) < 2 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -121,10 +128,16 @@ func toEnv(env map[string]string) []string {
|
||||||
func toDev(paths []string) []container.DeviceMapping {
|
func toDev(paths []string) []container.DeviceMapping {
|
||||||
var devices []container.DeviceMapping
|
var devices []container.DeviceMapping
|
||||||
for _, path := range paths {
|
for _, path := range paths {
|
||||||
parts := strings.Split(path, ":")
|
parts, err := splitVolumeParts(path)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
if len(parts) < 2 {
|
if len(parts) < 2 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if strings.HasSuffix(parts[1], ":ro") || strings.HasSuffix(parts[1], ":rw") {
|
||||||
|
parts[1] = parts[1][:len(parts[1])-1]
|
||||||
|
}
|
||||||
devices = append(devices, container.DeviceMapping{
|
devices = append(devices, container.DeviceMapping{
|
||||||
PathOnHost: parts[0],
|
PathOnHost: parts[0],
|
||||||
PathInContainer: parts[1],
|
PathInContainer: parts[1],
|
||||||
|
@ -143,3 +156,24 @@ func encodeAuthToBase64(authConfig backend.Auth) (string, error) {
|
||||||
}
|
}
|
||||||
return base64.URLEncoding.EncodeToString(buf), nil
|
return base64.URLEncoding.EncodeToString(buf), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// helper function that split volume path
|
||||||
|
func splitVolumeParts(volumeParts string) ([]string, error) {
|
||||||
|
pattern := `^((?:[\w]\:)?[^\:]*)\:((?:[\w]\:)?[^\:]*)(?:\:([rwom]*))?`
|
||||||
|
r, err := regexp.Compile(pattern)
|
||||||
|
if err != nil {
|
||||||
|
return []string{}, err
|
||||||
|
}
|
||||||
|
if r.MatchString(volumeParts) {
|
||||||
|
results := r.FindStringSubmatch(volumeParts)[1:]
|
||||||
|
cleanResults := []string{}
|
||||||
|
for _, item := range results {
|
||||||
|
if item != "" {
|
||||||
|
cleanResults = append(cleanResults, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cleanResults, nil
|
||||||
|
} else {
|
||||||
|
return strings.Split(volumeParts, ":"), nil
|
||||||
|
}
|
||||||
|
}
|
74
cncd/pipeline/pipeline/backend/docker/convert_test.go
Normal file
74
cncd/pipeline/pipeline/backend/docker/convert_test.go
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
package docker
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSplitVolumeParts(t *testing.T) {
|
||||||
|
testdata := []struct {
|
||||||
|
from string
|
||||||
|
to []string
|
||||||
|
success bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
from: `Z::Z::rw`,
|
||||||
|
to: []string{`Z:`, `Z:`, `rw`},
|
||||||
|
success: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: `Z:\:Z:\:rw`,
|
||||||
|
to: []string{`Z:\`, `Z:\`, `rw`},
|
||||||
|
success: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: `Z:\git\refs:Z:\git\refs:rw`,
|
||||||
|
to: []string{`Z:\git\refs`, `Z:\git\refs`, `rw`},
|
||||||
|
success: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: `Z:\git\refs:Z:\git\refs`,
|
||||||
|
to: []string{`Z:\git\refs`, `Z:\git\refs`},
|
||||||
|
success: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: `Z:/:Z:/:rw`,
|
||||||
|
to: []string{`Z:/`, `Z:/`, `rw`},
|
||||||
|
success: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: `Z:/git/refs:Z:/git/refs:rw`,
|
||||||
|
to: []string{`Z:/git/refs`, `Z:/git/refs`, `rw`},
|
||||||
|
success: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: `Z:/git/refs:Z:/git/refs`,
|
||||||
|
to: []string{`Z:/git/refs`, `Z:/git/refs`},
|
||||||
|
success: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: `/test:/test`,
|
||||||
|
to: []string{`/test`, `/test`},
|
||||||
|
success: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: `test:/test`,
|
||||||
|
to: []string{`test`, `/test`},
|
||||||
|
success: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: `test:test`,
|
||||||
|
to: []string{`test`, `test`},
|
||||||
|
success: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range testdata {
|
||||||
|
results, err := splitVolumeParts(test.from)
|
||||||
|
if test.success == (err != nil) {
|
||||||
|
} else {
|
||||||
|
if reflect.DeepEqual(results, test.to) != test.success {
|
||||||
|
t.Errorf("Expect %q matches %q is %v", test.from, results, test.to)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
|
||||||
"github.com/cncd/pipeline/pipeline/backend"
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/backend"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/network"
|
"github.com/docker/docker/api/types/network"
|
|
@ -3,7 +3,7 @@ package docker
|
||||||
// import (
|
// import (
|
||||||
// "context"
|
// "context"
|
||||||
//
|
//
|
||||||
// "github.com/cncd/pipeline/pipeline/backend"
|
// "github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/backend"
|
||||||
// )
|
// )
|
||||||
//
|
//
|
||||||
// // Pool manages a pool of Docker clients.
|
// // Pool manages a pool of Docker clients.
|
61
cncd/pipeline/pipeline/backend/kubernetes/kubernetes.go
Normal file
61
cncd/pipeline/pipeline/backend/kubernetes/kubernetes.go
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
package kubernetes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/backend"
|
||||||
|
)
|
||||||
|
|
||||||
|
type engine struct {
|
||||||
|
namespace string
|
||||||
|
endpoint string
|
||||||
|
token string
|
||||||
|
}
|
||||||
|
|
||||||
|
// New returns a new Kubernetes Engine.
|
||||||
|
func New(namespace, endpoint, token string) backend.Engine {
|
||||||
|
return &engine{
|
||||||
|
namespace: namespace,
|
||||||
|
endpoint: endpoint,
|
||||||
|
token: token,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup the pipeline environment.
|
||||||
|
func (e *engine) Setup(context.Context, *backend.Config) error {
|
||||||
|
// POST /api/v1/namespaces
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the pipeline step.
|
||||||
|
func (e *engine) Exec(context.Context, *backend.Step) error {
|
||||||
|
// POST /api/v1/namespaces/{namespace}/pods
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEPRECATED
|
||||||
|
// Kill the pipeline step.
|
||||||
|
func (e *engine) Kill(context.Context, *backend.Step) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for the pipeline step to complete and returns
|
||||||
|
// the completion results.
|
||||||
|
func (e *engine) Wait(context.Context, *backend.Step) (*backend.State, error) {
|
||||||
|
// GET /api/v1/watch/namespaces/{namespace}/pods
|
||||||
|
// GET /api/v1/watch/namespaces/{namespace}/pods/{name}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tail the pipeline step logs.
|
||||||
|
func (e *engine) Tail(context.Context, *backend.Step) (io.ReadCloser, error) {
|
||||||
|
// GET /api/v1/namespaces/{namespace}/pods/{name}/log
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy the pipeline environment.
|
||||||
|
func (e *engine) Destroy(context.Context, *backend.Config) error {
|
||||||
|
// DELETE /api/v1/namespaces/{name}
|
||||||
|
return nil
|
||||||
|
}
|
26
cncd/pipeline/pipeline/error_test.go
Normal file
26
cncd/pipeline/pipeline/error_test.go
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
package pipeline
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestExitError(t *testing.T) {
|
||||||
|
err := ExitError{
|
||||||
|
Name: "build",
|
||||||
|
Code: 255,
|
||||||
|
}
|
||||||
|
got, want := err.Error(), "build : exit code 255"
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("Want error message %q, got %q", want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOomError(t *testing.T) {
|
||||||
|
err := OomError{
|
||||||
|
Name: "build",
|
||||||
|
}
|
||||||
|
got, want := err.Error(), "build : received oom kill"
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("Want error message %q, got %q", want, got)
|
||||||
|
}
|
||||||
|
}
|
|
@ -176,7 +176,7 @@ func (m *Metadata) EnvironDrone() map[string]string {
|
||||||
params := map[string]string{
|
params := map[string]string{
|
||||||
"CI": "drone",
|
"CI": "drone",
|
||||||
"DRONE": "true",
|
"DRONE": "true",
|
||||||
"DRONE_ARCH": "linux/amd64",
|
"DRONE_ARCH": m.Sys.Arch,
|
||||||
"DRONE_REPO": m.Repo.Name,
|
"DRONE_REPO": m.Repo.Name,
|
||||||
"DRONE_REPO_SCM": "git",
|
"DRONE_REPO_SCM": "git",
|
||||||
"DRONE_REPO_OWNER": owner,
|
"DRONE_REPO_OWNER": owner,
|
1
cncd/pipeline/pipeline/frontend/metadata_test.go
Normal file
1
cncd/pipeline/pipeline/frontend/metadata_test.go
Normal file
|
@ -0,0 +1 @@
|
||||||
|
package frontend
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/cncd/pipeline/pipeline/frontend/yaml"
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/frontend/yaml"
|
||||||
|
|
||||||
libcompose "github.com/docker/libcompose/yaml"
|
libcompose "github.com/docker/libcompose/yaml"
|
||||||
)
|
)
|
|
@ -3,9 +3,9 @@ package compiler
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/cncd/pipeline/pipeline/backend"
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/backend"
|
||||||
"github.com/cncd/pipeline/pipeline/frontend"
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/frontend"
|
||||||
"github.com/cncd/pipeline/pipeline/frontend/yaml"
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/frontend/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO(bradrydzewski) compiler should handle user-defined volumes from YAML
|
// TODO(bradrydzewski) compiler should handle user-defined volumes from YAML
|
||||||
|
@ -75,10 +75,17 @@ func (c *Compiler) Compile(conf *yaml.Config) *backend.Config {
|
||||||
})
|
})
|
||||||
|
|
||||||
// create a default network
|
// create a default network
|
||||||
config.Networks = append(config.Networks, &backend.Network{
|
if c.metadata.Sys.Arch == "windows/amd64" {
|
||||||
Name: fmt.Sprintf("%s_default", c.prefix),
|
config.Networks = append(config.Networks, &backend.Network{
|
||||||
Driver: "bridge",
|
Name: fmt.Sprintf("%s_default", c.prefix),
|
||||||
})
|
Driver: "nat",
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
config.Networks = append(config.Networks, &backend.Network{
|
||||||
|
Name: fmt.Sprintf("%s_default", c.prefix),
|
||||||
|
Driver: "bridge",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// overrides the default workspace paths when specified
|
// overrides the default workspace paths when specified
|
||||||
// in the YAML file.
|
// in the YAML file.
|
|
@ -0,0 +1 @@
|
||||||
|
package compiler
|
|
@ -5,8 +5,8 @@ import (
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/cncd/pipeline/pipeline/backend"
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/backend"
|
||||||
"github.com/cncd/pipeline/pipeline/frontend/yaml"
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/frontend/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Compiler) createProcess(name string, container *yaml.Container, section string) *backend.Step {
|
func (c *Compiler) createProcess(name string, container *yaml.Container, section string) *backend.Step {
|
||||||
|
@ -77,12 +77,11 @@ func (c *Compiler) createProcess(name string, container *yaml.Container, section
|
||||||
|
|
||||||
if len(container.Commands) != 0 {
|
if len(container.Commands) != 0 {
|
||||||
if c.metadata.Sys.Arch == "windows/amd64" {
|
if c.metadata.Sys.Arch == "windows/amd64" {
|
||||||
// TODO provide windows implementation
|
entrypoint = []string{"powershell", "-noprofile", "-noninteractive", "-command"}
|
||||||
entrypoint = []string{"/bin/sh", "-c"}
|
command = []string{"[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Env:CI_SCRIPT)) | iex"}
|
||||||
command = []string{"echo $CI_SCRIPT | base64 -d | /bin/sh -e"}
|
|
||||||
environment["CI_SCRIPT"] = generateScriptWindows(container.Commands)
|
environment["CI_SCRIPT"] = generateScriptWindows(container.Commands)
|
||||||
environment["HOME"] = "/root"
|
environment["HOME"] = "c:\\root"
|
||||||
environment["SHELL"] = "/bin/sh"
|
environment["SHELL"] = "powershell.exe"
|
||||||
} else {
|
} else {
|
||||||
entrypoint = []string{"/bin/sh", "-c"}
|
entrypoint = []string{"/bin/sh", "-c"}
|
||||||
command = []string{"echo $CI_SCRIPT | base64 -d | /bin/sh -e"}
|
command = []string{"echo $CI_SCRIPT | base64 -d | /bin/sh -e"}
|
|
@ -0,0 +1 @@
|
||||||
|
package compiler
|
244
cncd/pipeline/pipeline/frontend/yaml/compiler/image_test.go
Normal file
244
cncd/pipeline/pipeline/frontend/yaml/compiler/image_test.go
Normal file
|
@ -0,0 +1,244 @@
|
||||||
|
package compiler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestTrimImage(t *testing.T) {
|
||||||
|
testdata := []struct {
|
||||||
|
from string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
from: "golang",
|
||||||
|
want: "golang",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "golang:latest",
|
||||||
|
want: "golang",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "golang:1.0.0",
|
||||||
|
want: "golang",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "library/golang",
|
||||||
|
want: "golang",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "library/golang:latest",
|
||||||
|
want: "golang",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "library/golang:1.0.0",
|
||||||
|
want: "golang",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "index.docker.io/library/golang:1.0.0",
|
||||||
|
want: "golang",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "gcr.io/library/golang:1.0.0",
|
||||||
|
want: "gcr.io/library/golang",
|
||||||
|
},
|
||||||
|
// error cases, return input unmodified
|
||||||
|
{
|
||||||
|
from: "foo/bar?baz:boo",
|
||||||
|
want: "foo/bar?baz:boo",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range testdata {
|
||||||
|
got, want := trimImage(test.from), test.want
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("Want image %q trimmed to %q, got %q", test.from, want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExpandImage(t *testing.T) {
|
||||||
|
testdata := []struct {
|
||||||
|
from string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
from: "golang",
|
||||||
|
want: "golang:latest",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "golang:latest",
|
||||||
|
want: "golang:latest",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "golang:1.0.0",
|
||||||
|
want: "golang:1.0.0",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "library/golang",
|
||||||
|
want: "golang:latest",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "library/golang:latest",
|
||||||
|
want: "golang:latest",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "library/golang:1.0.0",
|
||||||
|
want: "golang:1.0.0",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "index.docker.io/library/golang:1.0.0",
|
||||||
|
want: "golang:1.0.0",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "gcr.io/golang",
|
||||||
|
want: "gcr.io/golang:latest",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "gcr.io/golang:1.0.0",
|
||||||
|
want: "gcr.io/golang:1.0.0",
|
||||||
|
},
|
||||||
|
// error cases, return input unmodified
|
||||||
|
{
|
||||||
|
from: "foo/bar?baz:boo",
|
||||||
|
want: "foo/bar?baz:boo",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range testdata {
|
||||||
|
got, want := expandImage(test.from), test.want
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("Want image %q expanded to %q, got %q", test.from, want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMatchImage(t *testing.T) {
|
||||||
|
testdata := []struct {
|
||||||
|
from, to string
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
from: "golang",
|
||||||
|
to: "golang",
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "golang:latest",
|
||||||
|
to: "golang",
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "library/golang:latest",
|
||||||
|
to: "golang",
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "index.docker.io/library/golang:1.0.0",
|
||||||
|
to: "golang",
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "golang",
|
||||||
|
to: "golang:latest",
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "library/golang:latest",
|
||||||
|
to: "library/golang",
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "gcr.io/golang",
|
||||||
|
to: "gcr.io/golang",
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "gcr.io/golang:1.0.0",
|
||||||
|
to: "gcr.io/golang",
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "gcr.io/golang:latest",
|
||||||
|
to: "gcr.io/golang",
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "gcr.io/golang",
|
||||||
|
to: "gcr.io/golang:latest",
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "golang",
|
||||||
|
to: "library/golang",
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "golang",
|
||||||
|
to: "gcr.io/project/golang",
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "golang",
|
||||||
|
to: "gcr.io/library/golang",
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "golang",
|
||||||
|
to: "gcr.io/golang",
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range testdata {
|
||||||
|
got, want := matchImage(test.from, test.to), test.want
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("Want image %q matching %q is %v", test.from, test.to, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMatchHostname(t *testing.T) {
|
||||||
|
testdata := []struct {
|
||||||
|
image, hostname string
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
image: "golang",
|
||||||
|
hostname: "docker.io",
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image: "golang:latest",
|
||||||
|
hostname: "docker.io",
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image: "library/golang:latest",
|
||||||
|
hostname: "docker.io",
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image: "docker.io/library/golang:1.0.0",
|
||||||
|
hostname: "docker.io",
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image: "gcr.io/golang",
|
||||||
|
hostname: "docker.io",
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image: "gcr.io/golang:1.0.0",
|
||||||
|
hostname: "gcr.io",
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
image: "1.2.3.4:8000/golang:1.0.0",
|
||||||
|
hostname: "1.2.3.4:8000",
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range testdata {
|
||||||
|
got, want := matchHostname(test.image, test.hostname), test.want
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("Want image %q matching hostname %q is %v", test.image, test.hostname, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/cncd/pipeline/pipeline/frontend"
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/frontend"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Option configures a compiler option.
|
// Option configures a compiler option.
|
261
cncd/pipeline/pipeline/frontend/yaml/compiler/option_test.go
Normal file
261
cncd/pipeline/pipeline/frontend/yaml/compiler/option_test.go
Normal file
|
@ -0,0 +1,261 @@
|
||||||
|
package compiler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/frontend"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestWithWorkspace(t *testing.T) {
|
||||||
|
compiler := New(
|
||||||
|
WithWorkspace(
|
||||||
|
"/pipeline",
|
||||||
|
"src/github.com/octocat/hello-world",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if compiler.base != "/pipeline" {
|
||||||
|
t.Errorf("WithWorkspace must set the base directory")
|
||||||
|
}
|
||||||
|
if compiler.path != "src/github.com/octocat/hello-world" {
|
||||||
|
t.Errorf("WithWorkspace must set the path directory")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWithEscalated(t *testing.T) {
|
||||||
|
compiler := New(
|
||||||
|
WithEscalated(
|
||||||
|
"docker",
|
||||||
|
"docker-dev",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if compiler.escalated[0] != "docker" || compiler.escalated[1] != "docker-dev" {
|
||||||
|
t.Errorf("WithEscalated must whitelist privileged images")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWithVolumes(t *testing.T) {
|
||||||
|
compiler := New(
|
||||||
|
WithVolumes(
|
||||||
|
"/tmp:/tmp",
|
||||||
|
"/foo:/foo",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if compiler.volumes[0] != "/tmp:/tmp" || compiler.volumes[1] != "/foo:/foo" {
|
||||||
|
t.Errorf("TestWithVolumes must set default volumes")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWithNetworks(t *testing.T) {
|
||||||
|
compiler := New(
|
||||||
|
WithNetworks(
|
||||||
|
"overlay_1",
|
||||||
|
"overlay_bar",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if compiler.networks[0] != "overlay_1" || compiler.networks[1] != "overlay_bar" {
|
||||||
|
t.Errorf("TestWithNetworks must set networks from parameters")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWithResourceLimit(t *testing.T) {
|
||||||
|
compiler := New(
|
||||||
|
WithResourceLimit(
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
5,
|
||||||
|
"0,2-5",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if compiler.reslimit.MemSwapLimit != 1 {
|
||||||
|
t.Errorf("TestWithResourceLimit must set MemSwapLimit from parameters")
|
||||||
|
}
|
||||||
|
if compiler.reslimit.MemLimit != 2 {
|
||||||
|
t.Errorf("TestWithResourceLimit must set MemLimit from parameters")
|
||||||
|
}
|
||||||
|
if compiler.reslimit.ShmSize != 3 {
|
||||||
|
t.Errorf("TestWithResourceLimit must set ShmSize from parameters")
|
||||||
|
}
|
||||||
|
if compiler.reslimit.CPUQuota != 4 {
|
||||||
|
t.Errorf("TestWithResourceLimit must set CPUQuota from parameters")
|
||||||
|
}
|
||||||
|
if compiler.reslimit.CPUShares != 5 {
|
||||||
|
t.Errorf("TestWithResourceLimit must set CPUShares from parameters")
|
||||||
|
}
|
||||||
|
if compiler.reslimit.CPUSet != "0,2-5" {
|
||||||
|
t.Errorf("TestWithResourceLimit must set CPUSet from parameters")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWithPrefix(t *testing.T) {
|
||||||
|
if New(WithPrefix("drone_")).prefix != "drone_" {
|
||||||
|
t.Errorf("WithPrefix must set the prefix")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWithMetadata(t *testing.T) {
|
||||||
|
metadata := frontend.Metadata{
|
||||||
|
Repo: frontend.Repo{
|
||||||
|
Name: "octocat/hello-world",
|
||||||
|
Private: true,
|
||||||
|
Link: "https://github.com/octocat/hello-world",
|
||||||
|
Remote: "https://github.com/octocat/hello-world.git",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
compiler := New(
|
||||||
|
WithMetadata(metadata),
|
||||||
|
)
|
||||||
|
if !reflect.DeepEqual(compiler.metadata, metadata) {
|
||||||
|
t.Errorf("WithMetadata must set compiler the metadata")
|
||||||
|
}
|
||||||
|
if compiler.env["CI_REPO_NAME"] != metadata.Repo.Name {
|
||||||
|
t.Errorf("WithMetadata must set CI_REPO_NAME")
|
||||||
|
}
|
||||||
|
if compiler.env["CI_REPO_LINK"] != metadata.Repo.Link {
|
||||||
|
t.Errorf("WithMetadata must set CI_REPO_LINK")
|
||||||
|
}
|
||||||
|
if compiler.env["CI_REPO_REMOTE"] != metadata.Repo.Remote {
|
||||||
|
t.Errorf("WithMetadata must set CI_REPO_REMOTE")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWithLocal(t *testing.T) {
|
||||||
|
if New(WithLocal(true)).local == false {
|
||||||
|
t.Errorf("WithLocal true must enable the local flag")
|
||||||
|
}
|
||||||
|
if New(WithLocal(false)).local == true {
|
||||||
|
t.Errorf("WithLocal false must disable the local flag")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWithNetrc(t *testing.T) {
|
||||||
|
compiler := New(
|
||||||
|
WithNetrc(
|
||||||
|
"octocat",
|
||||||
|
"password",
|
||||||
|
"github.com",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if compiler.env["CI_NETRC_USERNAME"] != "octocat" {
|
||||||
|
t.Errorf("WithNetrc should set CI_NETRC_USERNAME")
|
||||||
|
}
|
||||||
|
if compiler.env["CI_NETRC_PASSWORD"] != "password" {
|
||||||
|
t.Errorf("WithNetrc should set CI_NETRC_PASSWORD")
|
||||||
|
}
|
||||||
|
if compiler.env["CI_NETRC_MACHINE"] != "github.com" {
|
||||||
|
t.Errorf("WithNetrc should set CI_NETRC_MACHINE")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWithProxy(t *testing.T) {
|
||||||
|
// do not execute the test if the host machine sets http proxy
|
||||||
|
// environment variables to avoid interference with other tests.
|
||||||
|
if noProxy != "" || httpProxy != "" || httpsProxy != "" {
|
||||||
|
t.SkipNow()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// alter the default values
|
||||||
|
noProxy = "foo.com"
|
||||||
|
httpProxy = "bar.com"
|
||||||
|
httpsProxy = "baz.com"
|
||||||
|
|
||||||
|
// reset the default values
|
||||||
|
defer func() {
|
||||||
|
noProxy = ""
|
||||||
|
httpProxy = ""
|
||||||
|
httpsProxy = ""
|
||||||
|
}()
|
||||||
|
|
||||||
|
testdata := map[string]string{
|
||||||
|
"no_proxy": noProxy,
|
||||||
|
"NO_PROXY": noProxy,
|
||||||
|
"http_proxy": httpProxy,
|
||||||
|
"HTTP_PROXY": httpProxy,
|
||||||
|
"https_proxy": httpsProxy,
|
||||||
|
"HTTPS_PROXY": httpsProxy,
|
||||||
|
}
|
||||||
|
compiler := New(
|
||||||
|
WithProxy(),
|
||||||
|
)
|
||||||
|
for key, value := range testdata {
|
||||||
|
if compiler.env[key] != value {
|
||||||
|
t.Errorf("WithProxy should set %s=%s", key, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWithEnviron(t *testing.T) {
|
||||||
|
compiler := New(
|
||||||
|
WithEnviron(
|
||||||
|
map[string]string{
|
||||||
|
"RACK_ENV": "development",
|
||||||
|
"SHOW": "true",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if compiler.env["RACK_ENV"] != "development" {
|
||||||
|
t.Errorf("WithEnviron should set RACK_ENV")
|
||||||
|
}
|
||||||
|
if compiler.env["SHOW"] != "true" {
|
||||||
|
t.Errorf("WithEnviron should set SHOW")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetenv(t *testing.T) {
|
||||||
|
defer func() {
|
||||||
|
os.Unsetenv("X_TEST_FOO")
|
||||||
|
os.Unsetenv("x_test_bar")
|
||||||
|
os.Unsetenv("x_test_baz")
|
||||||
|
}()
|
||||||
|
os.Setenv("X_TEST_FOO", "foo")
|
||||||
|
os.Setenv("x_test_bar", "bar")
|
||||||
|
os.Setenv("x_test_baz", "")
|
||||||
|
if getenv("x_test_foo") != "foo" {
|
||||||
|
t.Errorf("Expect X_TEST_FOO=foo")
|
||||||
|
}
|
||||||
|
if getenv("X_TEST_BAR") != "bar" {
|
||||||
|
t.Errorf("Expect x_test_bar=bar")
|
||||||
|
}
|
||||||
|
if getenv("x_test_baz") != "" {
|
||||||
|
t.Errorf("Expect x_test_bar=bar is empty")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWithVolumeCacher(t *testing.T) {
|
||||||
|
compiler := New(
|
||||||
|
WithVolumeCacher("/cache"),
|
||||||
|
)
|
||||||
|
cacher, ok := compiler.cacher.(*volumeCacher)
|
||||||
|
if !ok {
|
||||||
|
t.Errorf("Expected volume cacher configured")
|
||||||
|
}
|
||||||
|
if got, want := cacher.base, "/cache"; got != want {
|
||||||
|
t.Errorf("Expected volume cacher with base %s, got %s", want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWithS3Cacher(t *testing.T) {
|
||||||
|
compiler := New(
|
||||||
|
WithS3Cacher("some-access-key", "some-secret-key", "some-region", "some-bucket"),
|
||||||
|
)
|
||||||
|
cacher, ok := compiler.cacher.(*s3Cacher)
|
||||||
|
if !ok {
|
||||||
|
t.Errorf("Expected s3 cacher configured")
|
||||||
|
}
|
||||||
|
if got, want := cacher.bucket, "some-bucket"; got != want {
|
||||||
|
t.Errorf("Expected s3 cacher with bucket %s, got %s", want, got)
|
||||||
|
}
|
||||||
|
if got, want := cacher.access, "some-access-key"; got != want {
|
||||||
|
t.Errorf("Expected s3 cacher with access key %s, got %s", want, got)
|
||||||
|
}
|
||||||
|
if got, want := cacher.region, "some-region"; got != want {
|
||||||
|
t.Errorf("Expected s3 cacher with region %s, got %s", want, got)
|
||||||
|
}
|
||||||
|
if got, want := cacher.secret, "some-secret-key"; got != want {
|
||||||
|
t.Errorf("Expected s3 cacher with secret key %s, got %s", want, got)
|
||||||
|
}
|
||||||
|
}
|
37
cncd/pipeline/pipeline/frontend/yaml/compiler/params_test.go
Normal file
37
cncd/pipeline/pipeline/frontend/yaml/compiler/params_test.go
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
package compiler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/kr/pretty"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParamsToEnv(t *testing.T) {
|
||||||
|
from := map[string]interface{}{
|
||||||
|
"skip": nil,
|
||||||
|
"string": "stringz",
|
||||||
|
"int": 1,
|
||||||
|
"float": 1.2,
|
||||||
|
"bool": true,
|
||||||
|
"map": map[string]string{"hello": "world"},
|
||||||
|
"slice": []int{1, 2, 3},
|
||||||
|
"complex": []struct{ Name string }{{"Jack"}, {"Jill"}},
|
||||||
|
}
|
||||||
|
want := map[string]string{
|
||||||
|
"PLUGIN_STRING": "stringz",
|
||||||
|
"PLUGIN_INT": "1",
|
||||||
|
"PLUGIN_FLOAT": "1.2",
|
||||||
|
"PLUGIN_BOOL": "true",
|
||||||
|
"PLUGIN_MAP": `{"hello":"world"}`,
|
||||||
|
"PLUGIN_SLICE": "1,2,3",
|
||||||
|
"PLUGIN_COMPLEX": `[{"name":"Jack"},{"name":"Jill"}]`,
|
||||||
|
}
|
||||||
|
got := map[string]string{}
|
||||||
|
paramsToEnv(from, got)
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(want, got) {
|
||||||
|
t.Errorf("Problem converting plugin parameters to environment variables")
|
||||||
|
pretty.Ldiff(t, want, got)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
package compiler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/kr/pretty"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGenerateScriptPosix(t *testing.T) {
|
||||||
|
testdata := []struct {
|
||||||
|
from []string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
from: []string{"echo ${PATH}", "go build", "go test"},
|
||||||
|
want: `
|
||||||
|
if [ -n "$CI_NETRC_MACHINE" ]; then
|
||||||
|
cat <<EOF > $HOME/.netrc
|
||||||
|
machine $CI_NETRC_MACHINE
|
||||||
|
login $CI_NETRC_USERNAME
|
||||||
|
password $CI_NETRC_PASSWORD
|
||||||
|
EOF
|
||||||
|
chmod 0600 $HOME/.netrc
|
||||||
|
fi
|
||||||
|
unset CI_NETRC_USERNAME
|
||||||
|
unset CI_NETRC_PASSWORD
|
||||||
|
unset CI_SCRIPT
|
||||||
|
unset DRONE_NETRC_USERNAME
|
||||||
|
unset DRONE_NETRC_PASSWORD
|
||||||
|
|
||||||
|
echo + "echo \${PATH}"
|
||||||
|
echo ${PATH}
|
||||||
|
|
||||||
|
echo + "go build"
|
||||||
|
go build
|
||||||
|
|
||||||
|
echo + "go test"
|
||||||
|
go test
|
||||||
|
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range testdata {
|
||||||
|
script := generateScriptPosix(test.from)
|
||||||
|
decoded, _ := base64.StdEncoding.DecodeString(script)
|
||||||
|
got := string(decoded)
|
||||||
|
|
||||||
|
if got != test.want {
|
||||||
|
t.Errorf("Want encoded script for %s", test.from)
|
||||||
|
pretty.Ldiff(t, got, test.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
49
cncd/pipeline/pipeline/frontend/yaml/compiler/script_win.go
Normal file
49
cncd/pipeline/pipeline/frontend/yaml/compiler/script_win.go
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
package compiler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func generateScriptWindows(commands []string) string {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
for _, command := range commands {
|
||||||
|
escaped := fmt.Sprintf("%q", command)
|
||||||
|
escaped = strings.Replace(escaped, "$", `\$`, -1)
|
||||||
|
buf.WriteString(fmt.Sprintf(
|
||||||
|
traceScriptWin,
|
||||||
|
escaped,
|
||||||
|
command,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
script := fmt.Sprintf(
|
||||||
|
setupScriptWin,
|
||||||
|
buf.String(),
|
||||||
|
)
|
||||||
|
return base64.StdEncoding.EncodeToString([]byte(script))
|
||||||
|
}
|
||||||
|
|
||||||
|
const setupScriptWin = `
|
||||||
|
$ErrorActionPreference = 'Stop';
|
||||||
|
&cmd /c "mkdir c:\root";
|
||||||
|
if ($Env:CI_NETRC_MACHINE) {
|
||||||
|
$netrc=[string]::Format("{0}\_netrc",$Env:HOME);
|
||||||
|
"machine $Env:CI_NETRC_MACHINE" >> $netrc;
|
||||||
|
"login $Env:CI_NETRC_USERNAME" >> $netrc;
|
||||||
|
"password $Env:CI_NETRC_PASSWORD" >> $netrc;
|
||||||
|
};
|
||||||
|
[Environment]::SetEnvironmentVariable("CI_NETRC_PASSWORD",$null);
|
||||||
|
[Environment]::SetEnvironmentVariable("CI_SCRIPT",$null);
|
||||||
|
[Environment]::SetEnvironmentVariable("DRONE_NETRC_USERNAME",$null);
|
||||||
|
[Environment]::SetEnvironmentVariable("DRONE_NETRC_PASSWORD",$null);
|
||||||
|
%s
|
||||||
|
`
|
||||||
|
|
||||||
|
// traceScript is a helper script that is added to the build script
|
||||||
|
// to trace a command.
|
||||||
|
const traceScriptWin = `
|
||||||
|
Write-Output ('+ %s');
|
||||||
|
& %s; if ($LASTEXITCODE -ne 0) {exit $LASTEXITCODE}
|
||||||
|
`
|
|
@ -0,0 +1 @@
|
||||||
|
package compiler
|
108
cncd/pipeline/pipeline/frontend/yaml/config_test.go
Normal file
108
cncd/pipeline/pipeline/frontend/yaml/config_test.go
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
package yaml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/docker/libcompose/yaml"
|
||||||
|
"github.com/franela/goblin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func xTestParse(t *testing.T) {
|
||||||
|
g := goblin.Goblin(t)
|
||||||
|
|
||||||
|
g.Describe("Parser", func() {
|
||||||
|
g.Describe("Given a yaml file", func() {
|
||||||
|
|
||||||
|
g.It("Should unmarshal a string", func() {
|
||||||
|
out, err := ParseString(sampleYaml)
|
||||||
|
if err != nil {
|
||||||
|
g.Fail(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
g.Assert(out.Workspace.Base).Equal("/go")
|
||||||
|
g.Assert(out.Workspace.Path).Equal("src/github.com/octocat/hello-world")
|
||||||
|
g.Assert(out.Volumes.Volumes[0].Name).Equal("custom")
|
||||||
|
g.Assert(out.Volumes.Volumes[0].Driver).Equal("blockbridge")
|
||||||
|
g.Assert(out.Networks.Networks[0].Name).Equal("custom")
|
||||||
|
g.Assert(out.Networks.Networks[0].Driver).Equal("overlay")
|
||||||
|
g.Assert(out.Services.Containers[0].Name).Equal("database")
|
||||||
|
g.Assert(out.Services.Containers[0].Image).Equal("mysql")
|
||||||
|
g.Assert(out.Pipeline.Containers[0].Name).Equal("test")
|
||||||
|
g.Assert(out.Pipeline.Containers[0].Image).Equal("golang")
|
||||||
|
g.Assert(out.Pipeline.Containers[0].Commands).Equal(yaml.Stringorslice{"go install", "go test"})
|
||||||
|
g.Assert(out.Pipeline.Containers[1].Name).Equal("build")
|
||||||
|
g.Assert(out.Pipeline.Containers[1].Image).Equal("golang")
|
||||||
|
g.Assert(out.Pipeline.Containers[1].Commands).Equal(yaml.Stringorslice{"go build"})
|
||||||
|
g.Assert(out.Pipeline.Containers[2].Name).Equal("notify")
|
||||||
|
g.Assert(out.Pipeline.Containers[2].Image).Equal("slack")
|
||||||
|
g.Assert(out.Pipeline.Containers[2].NetworkMode).Equal("container:name")
|
||||||
|
g.Assert(out.Labels["com.example.team"]).Equal("frontend")
|
||||||
|
g.Assert(out.Labels["com.example.type"]).Equal("build")
|
||||||
|
})
|
||||||
|
// Check to make sure variable expansion works in yaml.MapSlice
|
||||||
|
// g.It("Should unmarshal variables", func() {
|
||||||
|
// out, err := ParseString(sampleVarYaml)
|
||||||
|
// if err != nil {
|
||||||
|
// g.Fail(err)
|
||||||
|
// }
|
||||||
|
// g.Assert(out.Pipeline[0].Name).Equal("notify_fail")
|
||||||
|
// g.Assert(out.Pipeline[0].Image).Equal("plugins/slack")
|
||||||
|
// g.Assert(len(out.Pipeline[0].Constraints.Event.Include)).Equal(0)
|
||||||
|
// g.Assert(out.Pipeline[1].Name).Equal("notify_success")
|
||||||
|
// g.Assert(out.Pipeline[1].Image).Equal("plugins/slack")
|
||||||
|
// g.Assert(out.Pipeline[1].Constraints.Event.Include).Equal([]string{"success"})
|
||||||
|
// })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var sampleYaml = `
|
||||||
|
image: hello-world
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
workspace:
|
||||||
|
path: src/github.com/octocat/hello-world
|
||||||
|
base: /go
|
||||||
|
pipeline:
|
||||||
|
test:
|
||||||
|
image: golang
|
||||||
|
commands:
|
||||||
|
- go install
|
||||||
|
- go test
|
||||||
|
build:
|
||||||
|
image: golang
|
||||||
|
network_mode: container:name
|
||||||
|
commands:
|
||||||
|
- go build
|
||||||
|
when:
|
||||||
|
event: push
|
||||||
|
notify:
|
||||||
|
image: slack
|
||||||
|
channel: dev
|
||||||
|
when:
|
||||||
|
event: failure
|
||||||
|
services:
|
||||||
|
database:
|
||||||
|
image: mysql
|
||||||
|
networks:
|
||||||
|
custom:
|
||||||
|
driver: overlay
|
||||||
|
volumes:
|
||||||
|
custom:
|
||||||
|
driver: blockbridge
|
||||||
|
labels:
|
||||||
|
com.example.type: "build"
|
||||||
|
com.example.team: "frontend"
|
||||||
|
`
|
||||||
|
|
||||||
|
var sampleVarYaml = `
|
||||||
|
_slack: &SLACK
|
||||||
|
image: plugins/slack
|
||||||
|
pipeline:
|
||||||
|
notify_fail: *SLACK
|
||||||
|
notify_success:
|
||||||
|
<< : *SLACK
|
||||||
|
when:
|
||||||
|
event: success
|
||||||
|
`
|
|
@ -3,8 +3,8 @@ package yaml
|
||||||
import (
|
import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/cncd/pipeline/pipeline/frontend"
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/frontend"
|
||||||
"github.com/cncd/pipeline/pipeline/frontend/yaml/types"
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/frontend/yaml/types"
|
||||||
libcompose "github.com/docker/libcompose/yaml"
|
libcompose "github.com/docker/libcompose/yaml"
|
||||||
)
|
)
|
||||||
|
|
373
cncd/pipeline/pipeline/frontend/yaml/constraint_test.go
Normal file
373
cncd/pipeline/pipeline/frontend/yaml/constraint_test.go
Normal file
|
@ -0,0 +1,373 @@
|
||||||
|
package yaml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/frontend"
|
||||||
|
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestConstraint(t *testing.T) {
|
||||||
|
testdata := []struct {
|
||||||
|
conf string
|
||||||
|
with string
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
// string value
|
||||||
|
{
|
||||||
|
conf: "master",
|
||||||
|
with: "develop",
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conf: "master",
|
||||||
|
with: "master",
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conf: "feature/*",
|
||||||
|
with: "feature/foo",
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
// slice value
|
||||||
|
{
|
||||||
|
conf: "[ master, feature/* ]",
|
||||||
|
with: "develop",
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conf: "[ master, feature/* ]",
|
||||||
|
with: "master",
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conf: "[ master, feature/* ]",
|
||||||
|
with: "feature/foo",
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
// includes block
|
||||||
|
{
|
||||||
|
conf: "include: master",
|
||||||
|
with: "develop",
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conf: "include: master",
|
||||||
|
with: "master",
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conf: "include: feature/*",
|
||||||
|
with: "master",
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conf: "include: feature/*",
|
||||||
|
with: "feature/foo",
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conf: "include: [ master, feature/* ]",
|
||||||
|
with: "develop",
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conf: "include: [ master, feature/* ]",
|
||||||
|
with: "master",
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conf: "include: [ master, feature/* ]",
|
||||||
|
with: "feature/foo",
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
// excludes block
|
||||||
|
{
|
||||||
|
conf: "exclude: master",
|
||||||
|
with: "develop",
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conf: "exclude: master",
|
||||||
|
with: "master",
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conf: "exclude: feature/*",
|
||||||
|
with: "master",
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conf: "exclude: feature/*",
|
||||||
|
with: "feature/foo",
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conf: "exclude: [ master, develop ]",
|
||||||
|
with: "master",
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conf: "exclude: [ feature/*, bar ]",
|
||||||
|
with: "master",
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conf: "exclude: [ feature/*, bar ]",
|
||||||
|
with: "feature/foo",
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
// include and exclude blocks
|
||||||
|
{
|
||||||
|
conf: "{ include: [ master, feature/* ], exclude: [ develop ] }",
|
||||||
|
with: "master",
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conf: "{ include: [ master, feature/* ], exclude: [ feature/bar ] }",
|
||||||
|
with: "feature/bar",
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conf: "{ include: [ master, feature/* ], exclude: [ master, develop ] }",
|
||||||
|
with: "master",
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
// empty blocks
|
||||||
|
{
|
||||||
|
conf: "",
|
||||||
|
with: "master",
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range testdata {
|
||||||
|
c := parseConstraint(test.conf)
|
||||||
|
got, want := c.Match(test.with), test.want
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("Expect %q matches %q is %v", test.with, test.conf, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConstraintMap(t *testing.T) {
|
||||||
|
testdata := []struct {
|
||||||
|
conf string
|
||||||
|
with map[string]string
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
conf: "GOLANG: 1.7",
|
||||||
|
with: map[string]string{"GOLANG": "1.7"},
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conf: "GOLANG: tip",
|
||||||
|
with: map[string]string{"GOLANG": "1.7"},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conf: "{ GOLANG: 1.7, REDIS: 3.1 }",
|
||||||
|
with: map[string]string{"GOLANG": "1.7", "REDIS": "3.1", "MYSQL": "5.6"},
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conf: "{ GOLANG: 1.7, REDIS: 3.1 }",
|
||||||
|
with: map[string]string{"GOLANG": "1.7", "REDIS": "3.0"},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
// TODO(bradrydzewski) eventually we should enable wildcard matching
|
||||||
|
{
|
||||||
|
conf: "{ GOLANG: 1.7, REDIS: 3.* }",
|
||||||
|
with: map[string]string{"GOLANG": "1.7", "REDIS": "3.0"},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
// include syntax
|
||||||
|
{
|
||||||
|
conf: "include: { GOLANG: 1.7 }",
|
||||||
|
with: map[string]string{"GOLANG": "1.7"},
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conf: "include: { GOLANG: tip }",
|
||||||
|
with: map[string]string{"GOLANG": "1.7"},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conf: "include: { GOLANG: 1.7, REDIS: 3.1 }",
|
||||||
|
with: map[string]string{"GOLANG": "1.7", "REDIS": "3.1", "MYSQL": "5.6"},
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conf: "include: { GOLANG: 1.7, REDIS: 3.1 }",
|
||||||
|
with: map[string]string{"GOLANG": "1.7", "REDIS": "3.0"},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
// exclude syntax
|
||||||
|
{
|
||||||
|
conf: "exclude: { GOLANG: 1.7 }",
|
||||||
|
with: map[string]string{"GOLANG": "1.7"},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conf: "exclude: { GOLANG: tip }",
|
||||||
|
with: map[string]string{"GOLANG": "1.7"},
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conf: "exclude: { GOLANG: 1.7, REDIS: 3.1 }",
|
||||||
|
with: map[string]string{"GOLANG": "1.7", "REDIS": "3.1", "MYSQL": "5.6"},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conf: "exclude: { GOLANG: 1.7, REDIS: 3.1 }",
|
||||||
|
with: map[string]string{"GOLANG": "1.7", "REDIS": "3.0"},
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
// exclude AND include values
|
||||||
|
{
|
||||||
|
conf: "{ include: { GOLANG: 1.7 }, exclude: { GOLANG: 1.7 } }",
|
||||||
|
with: map[string]string{"GOLANG": "1.7"},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
// blanks
|
||||||
|
{
|
||||||
|
conf: "",
|
||||||
|
with: map[string]string{"GOLANG": "1.7", "REDIS": "3.0"},
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conf: "GOLANG: 1.7",
|
||||||
|
with: map[string]string{},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conf: "{ GOLANG: 1.7, REDIS: 3.0 }",
|
||||||
|
with: map[string]string{},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conf: "include: { GOLANG: 1.7, REDIS: 3.1 }",
|
||||||
|
with: map[string]string{},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conf: "exclude: { GOLANG: 1.7, REDIS: 3.1 }",
|
||||||
|
with: map[string]string{},
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range testdata {
|
||||||
|
c := parseConstraintMap(test.conf)
|
||||||
|
got, want := c.Match(test.with), test.want
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("Expect %q matches %q is %v", test.with, test.conf, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConstraints(t *testing.T) {
|
||||||
|
testdata := []struct {
|
||||||
|
conf string
|
||||||
|
with frontend.Metadata
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
// no constraints, must match
|
||||||
|
{
|
||||||
|
conf: "",
|
||||||
|
with: frontend.Metadata{},
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
// branch constraint
|
||||||
|
{
|
||||||
|
conf: "{ branch: develop }",
|
||||||
|
with: frontend.Metadata{Curr: frontend.Build{Commit: frontend.Commit{Branch: "master"}}},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conf: "{ branch: master }",
|
||||||
|
with: frontend.Metadata{Curr: frontend.Build{Commit: frontend.Commit{Branch: "master"}}},
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
// environment constraint
|
||||||
|
// {
|
||||||
|
// conf: "{ branch: develop }",
|
||||||
|
// with: frontend.Metadata{Curr: frontend.Build{Commit: frontend.Commit{Branch: "master"}}},
|
||||||
|
// want: false,
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// conf: "{ branch: master }",
|
||||||
|
// with: frontend.Metadata{Curr: frontend.Build{Commit: frontend.Commit{Branch: "master"}}},
|
||||||
|
// want: true,
|
||||||
|
// },
|
||||||
|
// repo constraint
|
||||||
|
{
|
||||||
|
conf: "{ repo: drone/* }",
|
||||||
|
with: frontend.Metadata{Repo: frontend.Repo{Name: "drone/drone"}},
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conf: "{ repo: octocat/* }",
|
||||||
|
with: frontend.Metadata{Repo: frontend.Repo{Name: "drone/drone"}},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
// ref constraint
|
||||||
|
{
|
||||||
|
conf: "{ ref: refs/tags/* }",
|
||||||
|
with: frontend.Metadata{Curr: frontend.Build{Commit: frontend.Commit{Ref: "refs/tags/v1.0.0"}}},
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conf: "{ ref: refs/tags/* }",
|
||||||
|
with: frontend.Metadata{Curr: frontend.Build{Commit: frontend.Commit{Ref: "refs/heads/master"}}},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
// platform constraint
|
||||||
|
{
|
||||||
|
conf: "{ platform: linux/amd64 }",
|
||||||
|
with: frontend.Metadata{Sys: frontend.System{Arch: "linux/amd64"}},
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conf: "{ repo: linux/amd64 }",
|
||||||
|
with: frontend.Metadata{Sys: frontend.System{Arch: "windows/amd64"}},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
// instance constraint
|
||||||
|
{
|
||||||
|
conf: "{ instance: drone.io }",
|
||||||
|
with: frontend.Metadata{Sys: frontend.System{Host: "drone.io"}},
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conf: "{ instance: drone.io }",
|
||||||
|
with: frontend.Metadata{Sys: frontend.System{Host: "beta.drone.io"}},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range testdata {
|
||||||
|
c := parseConstraints(test.conf)
|
||||||
|
got, want := c.Match(test.with), test.want
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("Expect %+v matches %q is %v", test.with, test.conf, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseConstraints(s string) *Constraints {
|
||||||
|
c := &Constraints{}
|
||||||
|
yaml.Unmarshal([]byte(s), c)
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseConstraint(s string) *Constraint {
|
||||||
|
c := &Constraint{}
|
||||||
|
yaml.Unmarshal([]byte(s), c)
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseConstraintMap(s string) *ConstraintMap {
|
||||||
|
c := &ConstraintMap{}
|
||||||
|
yaml.Unmarshal([]byte(s), c)
|
||||||
|
return c
|
||||||
|
}
|
187
cncd/pipeline/pipeline/frontend/yaml/container_test.go
Normal file
187
cncd/pipeline/pipeline/frontend/yaml/container_test.go
Normal file
|
@ -0,0 +1,187 @@
|
||||||
|
package yaml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
libcompose "github.com/docker/libcompose/yaml"
|
||||||
|
"github.com/kr/pretty"
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
var containerYaml = []byte(`
|
||||||
|
image: golang:latest
|
||||||
|
auth_config:
|
||||||
|
username: janedoe
|
||||||
|
password: password
|
||||||
|
cap_add: [ ALL ]
|
||||||
|
cap_drop: [ NET_ADMIN, SYS_ADMIN ]
|
||||||
|
command: bundle exec thin -p 3000
|
||||||
|
commands:
|
||||||
|
- go build
|
||||||
|
- go test
|
||||||
|
cpu_quota: 11
|
||||||
|
cpuset: 1,2
|
||||||
|
cpu_shares: 99
|
||||||
|
detach: true
|
||||||
|
devices:
|
||||||
|
- /dev/ttyUSB0:/dev/ttyUSB0
|
||||||
|
dns: 8.8.8.8
|
||||||
|
dns_search: example.com
|
||||||
|
entrypoint: /code/entrypoint.sh
|
||||||
|
environment:
|
||||||
|
- RACK_ENV=development
|
||||||
|
- SHOW=true
|
||||||
|
extra_hosts:
|
||||||
|
- somehost:162.242.195.82
|
||||||
|
- otherhost:50.31.209.229
|
||||||
|
isolation: hyperv
|
||||||
|
name: my-build-container
|
||||||
|
network_mode: bridge
|
||||||
|
networks:
|
||||||
|
- some-network
|
||||||
|
- other-network
|
||||||
|
pull: true
|
||||||
|
privileged: true
|
||||||
|
labels:
|
||||||
|
com.example.type: build
|
||||||
|
com.example.team: frontend
|
||||||
|
shm_size: 1kb
|
||||||
|
mem_limit: 1kb
|
||||||
|
memswap_limit: 1kb
|
||||||
|
mem_swappiness: 1kb
|
||||||
|
volumes:
|
||||||
|
- /var/lib/mysql
|
||||||
|
- /opt/data:/var/lib/mysql
|
||||||
|
- /etc/configs:/etc/configs/:ro
|
||||||
|
ulimits:
|
||||||
|
nofile:
|
||||||
|
soft: 20000
|
||||||
|
hard: 40000
|
||||||
|
tmpfs:
|
||||||
|
- /var/lib/test
|
||||||
|
when:
|
||||||
|
branch: master
|
||||||
|
`)
|
||||||
|
|
||||||
|
func TestUnmarshalContainer(t *testing.T) {
|
||||||
|
want := Container{
|
||||||
|
AuthConfig: AuthConfig{
|
||||||
|
Username: "janedoe",
|
||||||
|
Password: "password",
|
||||||
|
},
|
||||||
|
CapAdd: []string{"ALL"},
|
||||||
|
CapDrop: []string{"NET_ADMIN", "SYS_ADMIN"},
|
||||||
|
Command: libcompose.Command{"bundle", "exec", "thin", "-p", "3000"},
|
||||||
|
Commands: libcompose.Stringorslice{"go build", "go test"},
|
||||||
|
CPUQuota: libcompose.StringorInt(11),
|
||||||
|
CPUSet: "1,2",
|
||||||
|
CPUShares: libcompose.StringorInt(99),
|
||||||
|
Detached: true,
|
||||||
|
Devices: []string{"/dev/ttyUSB0:/dev/ttyUSB0"},
|
||||||
|
DNS: libcompose.Stringorslice{"8.8.8.8"},
|
||||||
|
DNSSearch: libcompose.Stringorslice{"example.com"},
|
||||||
|
Entrypoint: libcompose.Command{"/code/entrypoint.sh"},
|
||||||
|
Environment: libcompose.SliceorMap{"RACK_ENV": "development", "SHOW": "true"},
|
||||||
|
ExtraHosts: []string{"somehost:162.242.195.82", "otherhost:50.31.209.229"},
|
||||||
|
Image: "golang:latest",
|
||||||
|
Isolation: "hyperv",
|
||||||
|
Labels: libcompose.SliceorMap{"com.example.type": "build", "com.example.team": "frontend"},
|
||||||
|
MemLimit: libcompose.MemStringorInt(1024),
|
||||||
|
MemSwapLimit: libcompose.MemStringorInt(1024),
|
||||||
|
MemSwappiness: libcompose.MemStringorInt(1024),
|
||||||
|
Name: "my-build-container",
|
||||||
|
Networks: libcompose.Networks{
|
||||||
|
Networks: []*libcompose.Network{
|
||||||
|
{Name: "some-network"},
|
||||||
|
{Name: "other-network"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
NetworkMode: "bridge",
|
||||||
|
Pull: true,
|
||||||
|
Privileged: true,
|
||||||
|
ShmSize: libcompose.MemStringorInt(1024),
|
||||||
|
Tmpfs: libcompose.Stringorslice{"/var/lib/test"},
|
||||||
|
Ulimits: libcompose.Ulimits{
|
||||||
|
Elements: []libcompose.Ulimit{
|
||||||
|
libcompose.NewUlimit("nofile", 20000, 40000),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Volumes: libcompose.Volumes{
|
||||||
|
Volumes: []*libcompose.Volume{
|
||||||
|
{Source: "", Destination: "/var/lib/mysql"},
|
||||||
|
{Source: "/opt/data", Destination: "/var/lib/mysql"},
|
||||||
|
{Source: "/etc/configs", Destination: "/etc/configs/", AccessMode: "ro"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Constraints: Constraints{
|
||||||
|
Branch: Constraint{
|
||||||
|
Include: []string{"master"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
got := Container{}
|
||||||
|
err := yaml.Unmarshal(containerYaml, &got)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
} else if !reflect.DeepEqual(want, got) {
|
||||||
|
t.Errorf("problem parsing container")
|
||||||
|
pretty.Ldiff(t, want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestUnmarshalContainersErr unmarshals a map of containers. The order is
|
||||||
|
// retained and the container key may be used as the container name if a
|
||||||
|
// name is not explicitly provided.
|
||||||
|
func TestUnmarshalContainers(t *testing.T) {
|
||||||
|
testdata := []struct {
|
||||||
|
from string
|
||||||
|
want []*Container
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
from: "build: { image: golang }",
|
||||||
|
want: []*Container{
|
||||||
|
{
|
||||||
|
Name: "build",
|
||||||
|
Image: "golang",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "test: { name: unit_test, image: node }",
|
||||||
|
want: []*Container{
|
||||||
|
{
|
||||||
|
Name: "unit_test",
|
||||||
|
Image: "node",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range testdata {
|
||||||
|
in := []byte(test.from)
|
||||||
|
got := Containers{}
|
||||||
|
err := yaml.Unmarshal(in, &got)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
} else if !reflect.DeepEqual(test.want, got.Containers) {
|
||||||
|
t.Errorf("problem parsing containers %q", test.from)
|
||||||
|
pretty.Ldiff(t, test.want, got.Containers)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestUnmarshalContainersErr unmarshals a container map where invalid inputs
|
||||||
|
// are provided to verify error messages are returned.
|
||||||
|
func TestUnmarshalContainersErr(t *testing.T) {
|
||||||
|
testdata := []string{
|
||||||
|
"foo: { name: [ foo, bar] }",
|
||||||
|
"- foo",
|
||||||
|
}
|
||||||
|
for _, test := range testdata {
|
||||||
|
in := []byte(test)
|
||||||
|
err := yaml.Unmarshal(in, new(Containers))
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("wanted error for containers %q", test)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,7 @@ package linter
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/cncd/pipeline/pipeline/frontend/yaml"
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/frontend/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
131
cncd/pipeline/pipeline/frontend/yaml/linter/linter_test.go
Normal file
131
cncd/pipeline/pipeline/frontend/yaml/linter/linter_test.go
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
package linter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/frontend/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLint(t *testing.T) {
|
||||||
|
testdata := `
|
||||||
|
pipeline:
|
||||||
|
build:
|
||||||
|
image: docker
|
||||||
|
privileged: true
|
||||||
|
network_mode: host
|
||||||
|
volumes:
|
||||||
|
- /tmp:/tmp
|
||||||
|
commands:
|
||||||
|
- go build
|
||||||
|
- go test
|
||||||
|
publish:
|
||||||
|
image: plugins/docker
|
||||||
|
repo: foo/bar
|
||||||
|
services:
|
||||||
|
redis:
|
||||||
|
image: redis
|
||||||
|
entrypoint: [ /bin/redis-server ]
|
||||||
|
command: [ -v ]
|
||||||
|
`
|
||||||
|
|
||||||
|
conf, err := yaml.ParseString(testdata)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Cannot unmarshal yaml %q. Error: %s", testdata, err)
|
||||||
|
}
|
||||||
|
if err := New(WithTrusted(true)).Lint(conf); err != nil {
|
||||||
|
t.Errorf("Expected lint returns no errors, got %q", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLintErrors(t *testing.T) {
|
||||||
|
testdata := []struct {
|
||||||
|
from string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
from: "",
|
||||||
|
want: "Invalid or missing pipeline section",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "pipeline: { build: { image: '' } }",
|
||||||
|
want: "Invalid or missing image",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "pipeline: { build: { image: golang, privileged: true } }",
|
||||||
|
want: "Insufficient privileges to use privileged mode",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "pipeline: { build: { image: golang, shm_size: 10gb } }",
|
||||||
|
want: "Insufficient privileges to override shm_size",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "pipeline: { build: { image: golang, dns: [ 8.8.8.8 ] } }",
|
||||||
|
want: "Insufficient privileges to use custom dns",
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
from: "pipeline: { build: { image: golang, dns_search: [ example.com ] } }",
|
||||||
|
want: "Insufficient privileges to use dns_search",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "pipeline: { build: { image: golang, devices: [ '/dev/tty0:/dev/tty0' ] } }",
|
||||||
|
want: "Insufficient privileges to use devices",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "pipeline: { build: { image: golang, extra_hosts: [ 'somehost:162.242.195.82' ] } }",
|
||||||
|
want: "Insufficient privileges to use extra_hosts",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "pipeline: { build: { image: golang, network_mode: host } }",
|
||||||
|
want: "Insufficient privileges to use network_mode",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "pipeline: { build: { image: golang, networks: [ outside, default ] } }",
|
||||||
|
want: "Insufficient privileges to use networks",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "pipeline: { build: { image: golang, volumes: [ '/opt/data:/var/lib/mysql' ] } }",
|
||||||
|
want: "Insufficient privileges to use volumes",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "pipeline: { build: { image: golang, network_mode: 'container:name' } }",
|
||||||
|
want: "Insufficient privileges to use network_mode",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "pipeline: { build: { image: golang, sysctls: [ net.core.somaxconn=1024 ] } }",
|
||||||
|
want: "Insufficient privileges to use sysctls",
|
||||||
|
},
|
||||||
|
// cannot override entypoint, command for script steps
|
||||||
|
{
|
||||||
|
from: "pipeline: { build: { image: golang, commands: [ 'go build' ], entrypoint: [ '/bin/bash' ] } }",
|
||||||
|
want: "Cannot override container entrypoint",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "pipeline: { build: { image: golang, commands: [ 'go build' ], command: [ '/bin/bash' ] } }",
|
||||||
|
want: "Cannot override container command",
|
||||||
|
},
|
||||||
|
// cannot override entypoint, command for plugin steps
|
||||||
|
{
|
||||||
|
from: "pipeline: { publish: { image: plugins/docker, repo: foo/bar, entrypoint: [ '/bin/bash' ] } }",
|
||||||
|
want: "Cannot override container entrypoint",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "pipeline: { publish: { image: plugins/docker, repo: foo/bar, command: [ '/bin/bash' ] } }",
|
||||||
|
want: "Cannot override container command",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testdata {
|
||||||
|
conf, err := yaml.ParseString(test.from)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Cannot unmarshal yaml %q. Error: %s", test.from, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
lerr := New().Lint(conf)
|
||||||
|
if lerr == nil {
|
||||||
|
t.Errorf("Expected lint error for configuration %q", test.from)
|
||||||
|
} else if lerr.Error() != test.want {
|
||||||
|
t.Errorf("Want error %q, got %q", test.want, lerr.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
70
cncd/pipeline/pipeline/frontend/yaml/matrix/matrix_test.go
Normal file
70
cncd/pipeline/pipeline/frontend/yaml/matrix/matrix_test.go
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
package matrix
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/franela/goblin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMatrix(t *testing.T) {
|
||||||
|
|
||||||
|
g := goblin.Goblin(t)
|
||||||
|
g.Describe("Calculate matrix", func() {
|
||||||
|
|
||||||
|
axis, _ := ParseString(fakeMatrix)
|
||||||
|
|
||||||
|
g.It("Should calculate permutations", func() {
|
||||||
|
g.Assert(len(axis)).Equal(24)
|
||||||
|
})
|
||||||
|
|
||||||
|
g.It("Should not duplicate permutations", func() {
|
||||||
|
set := map[string]bool{}
|
||||||
|
for _, perm := range axis {
|
||||||
|
set[perm.String()] = true
|
||||||
|
}
|
||||||
|
g.Assert(len(set)).Equal(24)
|
||||||
|
})
|
||||||
|
|
||||||
|
g.It("Should return nil if no matrix", func() {
|
||||||
|
axis, err := ParseString("")
|
||||||
|
g.Assert(err == nil).IsTrue()
|
||||||
|
g.Assert(axis == nil).IsTrue()
|
||||||
|
})
|
||||||
|
|
||||||
|
g.It("Should return included axis", func() {
|
||||||
|
axis, err := ParseString(fakeMatrixInclude)
|
||||||
|
g.Assert(err == nil).IsTrue()
|
||||||
|
g.Assert(len(axis)).Equal(2)
|
||||||
|
g.Assert(axis[0]["go_version"]).Equal("1.5")
|
||||||
|
g.Assert(axis[1]["go_version"]).Equal("1.6")
|
||||||
|
g.Assert(axis[0]["python_version"]).Equal("3.4")
|
||||||
|
g.Assert(axis[1]["python_version"]).Equal("3.4")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var fakeMatrix = `
|
||||||
|
matrix:
|
||||||
|
go_version:
|
||||||
|
- go1
|
||||||
|
- go1.2
|
||||||
|
python_version:
|
||||||
|
- 3.2
|
||||||
|
- 3.3
|
||||||
|
django_version:
|
||||||
|
- 1.7
|
||||||
|
- 1.7.1
|
||||||
|
- 1.7.2
|
||||||
|
redis_version:
|
||||||
|
- 2.6
|
||||||
|
- 2.8
|
||||||
|
`
|
||||||
|
|
||||||
|
var fakeMatrixInclude = `
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- go_version: 1.5
|
||||||
|
python_version: 3.4
|
||||||
|
- go_version: 1.6
|
||||||
|
python_version: 3.4
|
||||||
|
`
|
108
cncd/pipeline/pipeline/frontend/yaml/network_test.go
Normal file
108
cncd/pipeline/pipeline/frontend/yaml/network_test.go
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
package yaml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/kr/pretty"
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestUnmarshalNetwork(t *testing.T) {
|
||||||
|
testdata := []struct {
|
||||||
|
from string
|
||||||
|
want Network
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
from: "{ name: foo, driver: bar }",
|
||||||
|
want: Network{
|
||||||
|
Name: "foo",
|
||||||
|
Driver: "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "{ name: foo, driver: bar, driver_opts: { baz: qux } }",
|
||||||
|
want: Network{
|
||||||
|
Name: "foo",
|
||||||
|
Driver: "bar",
|
||||||
|
DriverOpts: map[string]string{
|
||||||
|
"baz": "qux",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testdata {
|
||||||
|
in := []byte(test.from)
|
||||||
|
got := Network{}
|
||||||
|
err := yaml.Unmarshal(in, &got)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
} else if !reflect.DeepEqual(test.want, got) {
|
||||||
|
t.Errorf("problem parsing network %q", test.from)
|
||||||
|
pretty.Ldiff(t, test.want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnmarshalNetworks(t *testing.T) {
|
||||||
|
testdata := []struct {
|
||||||
|
from string
|
||||||
|
want []*Network
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
from: "foo: { driver: bar }",
|
||||||
|
want: []*Network{
|
||||||
|
{
|
||||||
|
Name: "foo",
|
||||||
|
Driver: "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "foo: { name: baz }",
|
||||||
|
want: []*Network{
|
||||||
|
{
|
||||||
|
Name: "baz",
|
||||||
|
Driver: "bridge",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "foo: { name: baz, driver: bar }",
|
||||||
|
want: []*Network{
|
||||||
|
{
|
||||||
|
Name: "baz",
|
||||||
|
Driver: "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testdata {
|
||||||
|
in := []byte(test.from)
|
||||||
|
got := Networks{}
|
||||||
|
err := yaml.Unmarshal(in, &got)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
} else if !reflect.DeepEqual(test.want, got.Networks) {
|
||||||
|
t.Errorf("problem parsing network %q", test.from)
|
||||||
|
pretty.Ldiff(t, test.want, got.Networks)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnmarshalNetworkErr(t *testing.T) {
|
||||||
|
testdata := []string{
|
||||||
|
"foo: { name: [ foo, bar] }",
|
||||||
|
"- foo",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testdata {
|
||||||
|
in := []byte(test)
|
||||||
|
err := yaml.Unmarshal(in, new(Networks))
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("wanted error for networks %q", test)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
64
cncd/pipeline/pipeline/frontend/yaml/secret_test.go
Normal file
64
cncd/pipeline/pipeline/frontend/yaml/secret_test.go
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
package yaml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/kr/pretty"
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestUnmarshalSecrets(t *testing.T) {
|
||||||
|
testdata := []struct {
|
||||||
|
from string
|
||||||
|
want []*Secret
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
from: "[ mysql_username, mysql_password]",
|
||||||
|
want: []*Secret{
|
||||||
|
{
|
||||||
|
Source: "mysql_username",
|
||||||
|
Target: "mysql_username",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Source: "mysql_password",
|
||||||
|
Target: "mysql_password",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "[ { source: mysql_prod_username, target: mysql_username } ]",
|
||||||
|
want: []*Secret{
|
||||||
|
{
|
||||||
|
Source: "mysql_prod_username",
|
||||||
|
Target: "mysql_username",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "[ { source: mysql_prod_username, target: mysql_username }, { source: redis_username, target: redis_username } ]",
|
||||||
|
want: []*Secret{
|
||||||
|
{
|
||||||
|
Source: "mysql_prod_username",
|
||||||
|
Target: "mysql_username",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Source: "redis_username",
|
||||||
|
Target: "redis_username",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testdata {
|
||||||
|
in := []byte(test.from)
|
||||||
|
got := Secrets{}
|
||||||
|
err := yaml.Unmarshal(in, &got)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
} else if !reflect.DeepEqual(test.want, got.Secrets) {
|
||||||
|
t.Errorf("problem parsing secrets %q", test.from)
|
||||||
|
pretty.Ldiff(t, test.want, got.Secrets)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
54
cncd/pipeline/pipeline/frontend/yaml/types/bool_test.go
Normal file
54
cncd/pipeline/pipeline/frontend/yaml/types/bool_test.go
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/franela/goblin"
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBoolTrue(t *testing.T) {
|
||||||
|
g := goblin.Goblin(t)
|
||||||
|
|
||||||
|
g.Describe("Yaml bool type", func() {
|
||||||
|
g.Describe("given a yaml file", func() {
|
||||||
|
|
||||||
|
g.It("should unmarshal true", func() {
|
||||||
|
in := []byte("true")
|
||||||
|
out := BoolTrue{}
|
||||||
|
err := yaml.Unmarshal(in, &out)
|
||||||
|
if err != nil {
|
||||||
|
g.Fail(err)
|
||||||
|
}
|
||||||
|
g.Assert(out.Bool()).Equal(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
g.It("should unmarshal false", func() {
|
||||||
|
in := []byte("false")
|
||||||
|
out := BoolTrue{}
|
||||||
|
err := yaml.Unmarshal(in, &out)
|
||||||
|
if err != nil {
|
||||||
|
g.Fail(err)
|
||||||
|
}
|
||||||
|
g.Assert(out.Bool()).Equal(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
g.It("should unmarshal true when empty", func() {
|
||||||
|
in := []byte("")
|
||||||
|
out := BoolTrue{}
|
||||||
|
err := yaml.Unmarshal(in, &out)
|
||||||
|
if err != nil {
|
||||||
|
g.Fail(err)
|
||||||
|
}
|
||||||
|
g.Assert(out.Bool()).Equal(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
g.It("should throw error when invalid", func() {
|
||||||
|
in := []byte("{ }") // string value should fail parse
|
||||||
|
out := BoolTrue{}
|
||||||
|
err := yaml.Unmarshal(in, &out)
|
||||||
|
g.Assert(err != nil).IsTrue("expects error")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
108
cncd/pipeline/pipeline/frontend/yaml/volume_test.go
Normal file
108
cncd/pipeline/pipeline/frontend/yaml/volume_test.go
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
package yaml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/kr/pretty"
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestUnmarshalVolume(t *testing.T) {
|
||||||
|
testdata := []struct {
|
||||||
|
from string
|
||||||
|
want Volume
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
from: "{ name: foo, driver: bar }",
|
||||||
|
want: Volume{
|
||||||
|
Name: "foo",
|
||||||
|
Driver: "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "{ name: foo, driver: bar, driver_opts: { baz: qux } }",
|
||||||
|
want: Volume{
|
||||||
|
Name: "foo",
|
||||||
|
Driver: "bar",
|
||||||
|
DriverOpts: map[string]string{
|
||||||
|
"baz": "qux",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testdata {
|
||||||
|
in := []byte(test.from)
|
||||||
|
got := Volume{}
|
||||||
|
err := yaml.Unmarshal(in, &got)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
} else if !reflect.DeepEqual(test.want, got) {
|
||||||
|
t.Errorf("problem parsing volume %q", test.from)
|
||||||
|
pretty.Ldiff(t, test.want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnmarshalVolumes(t *testing.T) {
|
||||||
|
testdata := []struct {
|
||||||
|
from string
|
||||||
|
want []*Volume
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
from: "foo: { driver: bar }",
|
||||||
|
want: []*Volume{
|
||||||
|
{
|
||||||
|
Name: "foo",
|
||||||
|
Driver: "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "foo: { name: baz }",
|
||||||
|
want: []*Volume{
|
||||||
|
{
|
||||||
|
Name: "baz",
|
||||||
|
Driver: "local",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: "foo: { name: baz, driver: bar }",
|
||||||
|
want: []*Volume{
|
||||||
|
{
|
||||||
|
Name: "baz",
|
||||||
|
Driver: "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testdata {
|
||||||
|
in := []byte(test.from)
|
||||||
|
got := Volumes{}
|
||||||
|
err := yaml.Unmarshal(in, &got)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
} else if !reflect.DeepEqual(test.want, got.Volumes) {
|
||||||
|
t.Errorf("problem parsing volumes %q", test.from)
|
||||||
|
pretty.Ldiff(t, test.want, got.Volumes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnmarshalVolumesErr(t *testing.T) {
|
||||||
|
testdata := []string{
|
||||||
|
"foo: { name: [ foo, bar] }",
|
||||||
|
"- foo",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testdata {
|
||||||
|
in := []byte(test)
|
||||||
|
err := yaml.Unmarshal(in, new(Volumes))
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("wanted error for volumes %q", test)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
package pipeline
|
package pipeline
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/cncd/pipeline/pipeline/backend"
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/backend"
|
||||||
"github.com/cncd/pipeline/pipeline/multipart"
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/multipart"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Logger handles the process logging.
|
// Logger handles the process logging.
|
1
cncd/pipeline/pipeline/multipart/analysis/doc.go
Normal file
1
cncd/pipeline/pipeline/multipart/analysis/doc.go
Normal file
|
@ -0,0 +1 @@
|
||||||
|
package analysis
|
58
cncd/pipeline/pipeline/multipart/coverage/coverage.go
Normal file
58
cncd/pipeline/pipeline/multipart/coverage/coverage.go
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
package coverage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"mime/multipart"
|
||||||
|
"net/textproto"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MimeType used by coverage reports.
|
||||||
|
const MimeType = "application/json+coverage"
|
||||||
|
|
||||||
|
type (
|
||||||
|
// Report represents a coverage report.
|
||||||
|
Report struct {
|
||||||
|
Timestamp int64 `json:"timestmp,omitempty"`
|
||||||
|
Command string `json:"command_name,omitempty"`
|
||||||
|
Files []File `json:"files"`
|
||||||
|
Metrics Metrics `json:"metrics"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// File represents a coverage report for a single file.
|
||||||
|
File struct {
|
||||||
|
Name string `json:"filename"`
|
||||||
|
Digest string `json:"checksum,omitempty"`
|
||||||
|
Coverage []*int `json:"coverage"`
|
||||||
|
Covered float64 `json:"covered_percent,omitempty"`
|
||||||
|
CoveredStrength float64 `json:"covered_strength,omitempty"`
|
||||||
|
CoveredLines int `json:"covered_lines,omitempty"`
|
||||||
|
TotalLines int `json:"lines_of_code"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Metrics represents total coverage metrics for all files.
|
||||||
|
Metrics struct {
|
||||||
|
Covered float64 `json:"covered_percent"`
|
||||||
|
CoveredStrength float64 `json:"covered_strength"`
|
||||||
|
CoveredLines int `json:"covered_lines"`
|
||||||
|
TotalLines int `json:"total_lines"`
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// WriteTo writes the report to multipart.Writer w.
|
||||||
|
func (r *Report) WriteTo(w *multipart.Writer) error {
|
||||||
|
header := textproto.MIMEHeader{}
|
||||||
|
header.Set("Content-Type", MimeType)
|
||||||
|
header.Set("X-Covered", fmt.Sprintf("%.2f", r.Metrics.Covered))
|
||||||
|
header.Set("X-Covered-Lines", strconv.Itoa(r.Metrics.CoveredLines))
|
||||||
|
header.Set("X-Total-Lines", strconv.Itoa(r.Metrics.TotalLines))
|
||||||
|
part, err := w.CreatePart(header)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
encoder := json.NewEncoder(part)
|
||||||
|
encoder.SetIndent("", " ")
|
||||||
|
return encoder.Encode(r)
|
||||||
|
}
|
1
cncd/pipeline/pipeline/multipart/coverage/doc.go
Normal file
1
cncd/pipeline/pipeline/multipart/coverage/doc.go
Normal file
|
@ -0,0 +1 @@
|
||||||
|
package coverage
|
76
cncd/pipeline/pipeline/multipart/reader_test.go
Normal file
76
cncd/pipeline/pipeline/multipart/reader_test.go
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
package multipart
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io/ioutil"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestReader(t *testing.T) {
|
||||||
|
b := bytes.NewBufferString(sample)
|
||||||
|
m := New(b)
|
||||||
|
|
||||||
|
part, err := m.NextPart()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
header := part.Header()
|
||||||
|
if got, want := header.Get("Content-Type"), "text/plain"; got != want {
|
||||||
|
t.Errorf("Want Content-Type %q, got %q", want, got)
|
||||||
|
}
|
||||||
|
body, err := ioutil.ReadAll(part)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if got, want := string(body), sampleTextPlain; got != want {
|
||||||
|
t.Errorf("Want body %q, got %q", want, got)
|
||||||
|
}
|
||||||
|
|
||||||
|
part, err = m.NextPart()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
header = part.Header()
|
||||||
|
if got, want := header.Get("Content-Type"), "application/json+coverage"; got != want {
|
||||||
|
t.Errorf("Want Content-Type %q, got %q", want, got)
|
||||||
|
}
|
||||||
|
if got, want := header.Get("X-Covered"), "96.00"; got != want {
|
||||||
|
t.Errorf("Want X-Covered %q, got %q", want, got)
|
||||||
|
}
|
||||||
|
if got, want := header.Get("X-Covered-Lines"), "96"; got != want {
|
||||||
|
t.Errorf("Want X-Covered-Lines %q, got %q", want, got)
|
||||||
|
}
|
||||||
|
if got, want := header.Get("X-Total-Lines"), "100"; got != want {
|
||||||
|
t.Errorf("Want X-Total-Lines %q, got %q", want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var sample = `PIPELINE
|
||||||
|
Content-Type: multipart/mixed; boundary=boundary
|
||||||
|
|
||||||
|
--boundary
|
||||||
|
Content-Type: text/plain
|
||||||
|
|
||||||
|
match: pipeline/frontend/yaml/compiler/coverage.out
|
||||||
|
match: pipeline/frontend/yaml/coverage.out
|
||||||
|
match: pipeline/frontend/yaml/linter/coverage.out
|
||||||
|
|
||||||
|
--boundary
|
||||||
|
Content-Type: application/json+coverage
|
||||||
|
X-Covered: 96.00
|
||||||
|
X-Covered-Lines: 96
|
||||||
|
X-Total-Lines: 100
|
||||||
|
|
||||||
|
{"metrics":{"covered_lines":96,"total_lines":100}}
|
||||||
|
|
||||||
|
--boundary--
|
||||||
|
`
|
||||||
|
|
||||||
|
var sampleTextPlain = `match: pipeline/frontend/yaml/compiler/coverage.out
|
||||||
|
match: pipeline/frontend/yaml/coverage.out
|
||||||
|
match: pipeline/frontend/yaml/linter/coverage.out
|
||||||
|
`
|
1
cncd/pipeline/pipeline/multipart/selenium/doc.go
Normal file
1
cncd/pipeline/pipeline/multipart/selenium/doc.go
Normal file
|
@ -0,0 +1 @@
|
||||||
|
package selenium
|
1
cncd/pipeline/pipeline/multipart/terminal/doc.go
Normal file
1
cncd/pipeline/pipeline/multipart/terminal/doc.go
Normal file
|
@ -0,0 +1 @@
|
||||||
|
package terminal
|
|
@ -3,7 +3,7 @@ package pipeline
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/cncd/pipeline/pipeline/backend"
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/backend"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Option configures a runtime option.
|
// Option configures a runtime option.
|
1
cncd/pipeline/pipeline/option_test.go
Normal file
1
cncd/pipeline/pipeline/option_test.go
Normal file
|
@ -0,0 +1 @@
|
||||||
|
package pipeline
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/cncd/pipeline/pipeline/backend"
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/backend"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Parse parses the pipeline config from an io.Reader.
|
// Parse parses the pipeline config from an io.Reader.
|
1
cncd/pipeline/pipeline/parse_test.go
Normal file
1
cncd/pipeline/pipeline/parse_test.go
Normal file
|
@ -0,0 +1 @@
|
||||||
|
package pipeline
|
|
@ -6,8 +6,8 @@ import (
|
||||||
|
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
|
|
||||||
"github.com/cncd/pipeline/pipeline/backend"
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/backend"
|
||||||
"github.com/cncd/pipeline/pipeline/multipart"
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/multipart"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
|
@ -6,8 +6,8 @@ import (
|
||||||
"time"
|
"time"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/cncd/pipeline/pipeline/backend"
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/backend"
|
||||||
"github.com/cncd/pipeline/pipeline/rpc/proto"
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/rpc/proto"
|
||||||
|
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
|
@ -5,8 +5,8 @@ import (
|
||||||
// "encoding/json"
|
// "encoding/json"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
// "github.com/cncd/pipeline/pipeline/backend"
|
// "github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/backend"
|
||||||
"github.com/cncd/pipeline/pipeline/rpc/proto"
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/rpc/proto"
|
||||||
|
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
1
cncd/pipeline/pipeline/rpc/client_test.go
Normal file
1
cncd/pipeline/pipeline/rpc/client_test.go
Normal file
|
@ -0,0 +1 @@
|
||||||
|
package rpc
|
18
cncd/pipeline/pipeline/rpc/line_test.go
Normal file
18
cncd/pipeline/pipeline/rpc/line_test.go
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
package rpc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLine(t *testing.T) {
|
||||||
|
line := Line{
|
||||||
|
Proc: "redis",
|
||||||
|
Time: 60,
|
||||||
|
Pos: 1,
|
||||||
|
Out: "starting redis server",
|
||||||
|
}
|
||||||
|
got, want := line.String(), "[redis:L1:60s] starting redis server"
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("Wanted line string %q, got %q", want, got)
|
||||||
|
}
|
||||||
|
}
|
1
cncd/pipeline/pipeline/rpc/option_test.go
Normal file
1
cncd/pipeline/pipeline/rpc/option_test.go
Normal file
|
@ -0,0 +1 @@
|
||||||
|
package rpc
|
|
@ -3,7 +3,7 @@ package rpc
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/cncd/pipeline/pipeline/backend"
|
"github.com/laszlocph/drone-oss-08/cncd/pipeline/pipeline/backend"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrCancelled signals the pipeine is cancelled.
|
// ErrCancelled signals the pipeine is cancelled.
|
1
cncd/pipeline/pipeline/rpc/server_test.go
Normal file
1
cncd/pipeline/pipeline/rpc/server_test.go
Normal file
|
@ -0,0 +1 @@
|
||||||
|
package rpc
|
11
cncd/pipeline/samples/sample_1/README.md
Normal file
11
cncd/pipeline/samples/sample_1/README.md
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
Compile the yaml to the intermediate representation:
|
||||||
|
|
||||||
|
```
|
||||||
|
pipec compile
|
||||||
|
```
|
||||||
|
|
||||||
|
Execute the intermediate representation:
|
||||||
|
|
||||||
|
```
|
||||||
|
pipec exec
|
||||||
|
```
|
159
cncd/pipeline/samples/sample_1/pipeline.json
Normal file
159
cncd/pipeline/samples/sample_1/pipeline.json
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
{
|
||||||
|
"pipeline": [
|
||||||
|
{
|
||||||
|
"name": "pipeline_clone_0",
|
||||||
|
"alias": "git",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"name": "pipeline_clone_0",
|
||||||
|
"alias": "git",
|
||||||
|
"image": "plugins/git:latest",
|
||||||
|
"working_dir": "/go/src/github.com/drone/envsubst",
|
||||||
|
"environment": {
|
||||||
|
"CI": "pipec",
|
||||||
|
"CI_BUILD_CREATED": "1486119586",
|
||||||
|
"CI_BUILD_EVENT": "push",
|
||||||
|
"CI_BUILD_NUMBER": "6",
|
||||||
|
"CI_BUILD_STARTED": "1486119585",
|
||||||
|
"CI_COMMIT_AUTHOR": "bradrydzewski",
|
||||||
|
"CI_COMMIT_AUTHOR_NAME": "bradrydzewski",
|
||||||
|
"CI_COMMIT_BRANCH": "master",
|
||||||
|
"CI_COMMIT_MESSAGE": "added a few more test cases for escaping behavior",
|
||||||
|
"CI_COMMIT_REF": "refs/heads/master",
|
||||||
|
"CI_COMMIT_SHA": "d0876d3176965f9552a611cbd56e24a9264355e6",
|
||||||
|
"CI_REMOTE_URL": "https://github.com/drone/envsubst.git",
|
||||||
|
"CI_REPO": "drone/envsubst",
|
||||||
|
"CI_REPO_LINK": "https://github.com/drone/envsubst",
|
||||||
|
"CI_REPO_NAME": "drone/envsubst",
|
||||||
|
"CI_REPO_REMOTE": "https://github.com/drone/envsubst.git",
|
||||||
|
"CI_SYSTEM": "pipec",
|
||||||
|
"CI_SYSTEM_ARCH": "linux/amd64",
|
||||||
|
"CI_SYSTEM_LINK": "https://github.com/cncd/pipec",
|
||||||
|
"CI_SYSTEM_NAME": "pipec",
|
||||||
|
"CI_WORKSPACE": "/go/src/github.com/drone/envsubst",
|
||||||
|
"DRONE_BUILD_CREATED": "1486119586",
|
||||||
|
"DRONE_BUILD_EVENT": "push",
|
||||||
|
"DRONE_BUILD_NUMBER": "6",
|
||||||
|
"DRONE_BUILD_STARTED": "1486119585",
|
||||||
|
"DRONE_COMMIT_AUTHOR": "bradrydzewski",
|
||||||
|
"DRONE_COMMIT_AUTHOR_NAME": "bradrydzewski",
|
||||||
|
"DRONE_COMMIT_BRANCH": "master",
|
||||||
|
"DRONE_COMMIT_MESSAGE": "added a few more test cases for escaping behavior",
|
||||||
|
"DRONE_COMMIT_REF": "refs/heads/master",
|
||||||
|
"DRONE_COMMIT_SHA": "d0876d3176965f9552a611cbd56e24a9264355e6",
|
||||||
|
"DRONE_REMOTE_URL": "https://github.com/drone/envsubst.git",
|
||||||
|
"DRONE_REPO": "drone/envsubst",
|
||||||
|
"DRONE_REPO_LINK": "https://github.com/drone/envsubst",
|
||||||
|
"DRONE_REPO_NAME": "drone/envsubst",
|
||||||
|
"DRONE_REPO_REMOTE": "https://github.com/drone/envsubst.git",
|
||||||
|
"DRONE_SYSTEM": "pipec",
|
||||||
|
"DRONE_SYSTEM_ARCH": "linux/amd64",
|
||||||
|
"DRONE_SYSTEM_LINK": "https://github.com/cncd/pipec",
|
||||||
|
"DRONE_SYSTEM_NAME": "pipec",
|
||||||
|
"DRONE_WORKSPACE": "/go/src/github.com/drone/envsubst",
|
||||||
|
"PLUGIN_DEPTH": "50"
|
||||||
|
},
|
||||||
|
"volumes": [
|
||||||
|
"pipeline_default:/go"
|
||||||
|
],
|
||||||
|
"networks": [
|
||||||
|
{
|
||||||
|
"name": "pipeline_default",
|
||||||
|
"aliases": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"on_success": true,
|
||||||
|
"auth_config": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "pipeline_stage_0",
|
||||||
|
"alias": "build",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"name": "pipeline_step_0",
|
||||||
|
"alias": "build",
|
||||||
|
"image": "golang:1.7",
|
||||||
|
"working_dir": "/go/src/github.com/drone/envsubst",
|
||||||
|
"environment": {
|
||||||
|
"CI": "pipec",
|
||||||
|
"CI_BUILD_CREATED": "1486119586",
|
||||||
|
"CI_BUILD_EVENT": "push",
|
||||||
|
"CI_BUILD_NUMBER": "6",
|
||||||
|
"CI_BUILD_STARTED": "1486119585",
|
||||||
|
"CI_COMMIT_AUTHOR": "bradrydzewski",
|
||||||
|
"CI_COMMIT_AUTHOR_NAME": "bradrydzewski",
|
||||||
|
"CI_COMMIT_BRANCH": "master",
|
||||||
|
"CI_COMMIT_MESSAGE": "added a few more test cases for escaping behavior",
|
||||||
|
"CI_COMMIT_REF": "refs/heads/master",
|
||||||
|
"CI_COMMIT_SHA": "d0876d3176965f9552a611cbd56e24a9264355e6",
|
||||||
|
"CI_REMOTE_URL": "https://github.com/drone/envsubst.git",
|
||||||
|
"CI_REPO": "drone/envsubst",
|
||||||
|
"CI_REPO_LINK": "https://github.com/drone/envsubst",
|
||||||
|
"CI_REPO_NAME": "drone/envsubst",
|
||||||
|
"CI_REPO_REMOTE": "https://github.com/drone/envsubst.git",
|
||||||
|
"CI_SCRIPT": "CmlmIFsgLW4gIiRDSV9ORVRSQ19NQUNISU5FIiBdOyB0aGVuCmNhdCA8PEVPRiA+ICRIT01FLy5uZXRyYwptYWNoaW5lICRDSV9ORVRSQ19NQUNISU5FCmxvZ2luICRDSV9ORVRSQ19VU0VSTkFNRQpwYXNzd29yZCAkQ0lfTkVUUkNfUEFTU1dPUkQKRU9GCmNobW9kIDA2MDAgJEhPTUUvLm5ldHJjCmZpCnVuc2V0IENJX05FVFJDX1VTRVJOQU1FCnVuc2V0IENJX05FVFJDX1BBU1NXT1JECnVuc2V0IENJX1NDUklQVAoKZWNobyArICJnbyBnZXQgLXQgLi8uLi4iCmdvIGdldCAtdCAuLy4uLgoKZWNobyArICJnbyBidWlsZCIKZ28gYnVpbGQKCmVjaG8gKyAiZ28gdGVzdCAtdiIKZ28gdGVzdCAtdgoK",
|
||||||
|
"CI_SYSTEM": "pipec",
|
||||||
|
"CI_SYSTEM_ARCH": "linux/amd64",
|
||||||
|
"CI_SYSTEM_LINK": "https://github.com/cncd/pipec",
|
||||||
|
"CI_SYSTEM_NAME": "pipec",
|
||||||
|
"CI_WORKSPACE": "/go/src/github.com/drone/envsubst",
|
||||||
|
"DRONE_BUILD_CREATED": "1486119586",
|
||||||
|
"DRONE_BUILD_EVENT": "push",
|
||||||
|
"DRONE_BUILD_NUMBER": "6",
|
||||||
|
"DRONE_BUILD_STARTED": "1486119585",
|
||||||
|
"DRONE_COMMIT_AUTHOR": "bradrydzewski",
|
||||||
|
"DRONE_COMMIT_AUTHOR_NAME": "bradrydzewski",
|
||||||
|
"DRONE_COMMIT_BRANCH": "master",
|
||||||
|
"DRONE_COMMIT_MESSAGE": "added a few more test cases for escaping behavior",
|
||||||
|
"DRONE_COMMIT_REF": "refs/heads/master",
|
||||||
|
"DRONE_COMMIT_SHA": "d0876d3176965f9552a611cbd56e24a9264355e6",
|
||||||
|
"DRONE_REMOTE_URL": "https://github.com/drone/envsubst.git",
|
||||||
|
"DRONE_REPO": "drone/envsubst",
|
||||||
|
"DRONE_REPO_LINK": "https://github.com/drone/envsubst",
|
||||||
|
"DRONE_REPO_NAME": "drone/envsubst",
|
||||||
|
"DRONE_REPO_REMOTE": "https://github.com/drone/envsubst.git",
|
||||||
|
"DRONE_SYSTEM": "pipec",
|
||||||
|
"DRONE_SYSTEM_ARCH": "linux/amd64",
|
||||||
|
"DRONE_SYSTEM_LINK": "https://github.com/cncd/pipec",
|
||||||
|
"DRONE_SYSTEM_NAME": "pipec",
|
||||||
|
"DRONE_WORKSPACE": "/go/src/github.com/drone/envsubst",
|
||||||
|
"HOME": "/root",
|
||||||
|
"SHELL": "/bin/sh"
|
||||||
|
},
|
||||||
|
"entrypoint": [
|
||||||
|
"/bin/sh",
|
||||||
|
"-c"
|
||||||
|
],
|
||||||
|
"command": [
|
||||||
|
"echo $CI_SCRIPT | base64 -d | /bin/sh -e"
|
||||||
|
],
|
||||||
|
"volumes": [
|
||||||
|
"pipeline_default:/go"
|
||||||
|
],
|
||||||
|
"networks": [
|
||||||
|
{
|
||||||
|
"name": "pipeline_default",
|
||||||
|
"aliases": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"on_success": true,
|
||||||
|
"auth_config": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"networks": [
|
||||||
|
{
|
||||||
|
"name": "pipeline_default",
|
||||||
|
"driver": "bridge"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"volumes": [
|
||||||
|
{
|
||||||
|
"name": "pipeline_default",
|
||||||
|
"driver": "local"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
16
cncd/pipeline/samples/sample_1/pipeline.yml
Normal file
16
cncd/pipeline/samples/sample_1/pipeline.yml
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
workspace:
|
||||||
|
base: /go
|
||||||
|
path: src/github.com/drone/envsubst
|
||||||
|
|
||||||
|
clone:
|
||||||
|
git:
|
||||||
|
image: plugins/git
|
||||||
|
depth: 50
|
||||||
|
|
||||||
|
pipeline:
|
||||||
|
build:
|
||||||
|
image: golang:1.7
|
||||||
|
commands:
|
||||||
|
- go get -t ./...
|
||||||
|
- go build
|
||||||
|
- go test -v
|
11
cncd/pipeline/samples/sample_10_windows/README.md
Normal file
11
cncd/pipeline/samples/sample_10_windows/README.md
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
Compile the yaml to the intermediate representation:
|
||||||
|
|
||||||
|
```
|
||||||
|
pipec compile --system-arch windows/amd64
|
||||||
|
```
|
||||||
|
|
||||||
|
Execute the intermediate representation:
|
||||||
|
|
||||||
|
```
|
||||||
|
pipec exec
|
||||||
|
```
|
170
cncd/pipeline/samples/sample_10_windows/pipeline.json
Normal file
170
cncd/pipeline/samples/sample_10_windows/pipeline.json
Normal file
|
@ -0,0 +1,170 @@
|
||||||
|
{
|
||||||
|
"pipeline": [
|
||||||
|
{
|
||||||
|
"name": "pipeline_clone_0",
|
||||||
|
"alias": "git",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"name": "pipeline_clone_0",
|
||||||
|
"alias": "git",
|
||||||
|
"image": "plugins/git:windows",
|
||||||
|
"working_dir": "c:\\gopath/src\\github.com\\drone\\envsubst",
|
||||||
|
"environment": {
|
||||||
|
"CI": "drone",
|
||||||
|
"CI_BUILD_CREATED": "1486119586",
|
||||||
|
"CI_BUILD_EVENT": "push",
|
||||||
|
"CI_BUILD_NUMBER": "6",
|
||||||
|
"CI_BUILD_STARTED": "1486119585",
|
||||||
|
"CI_COMMIT_AUTHOR": "bradrydzewski",
|
||||||
|
"CI_COMMIT_AUTHOR_NAME": "bradrydzewski",
|
||||||
|
"CI_COMMIT_BRANCH": "master",
|
||||||
|
"CI_COMMIT_MESSAGE": "added a few more test cases for escaping behavior",
|
||||||
|
"CI_COMMIT_REF": "refs/heads/master",
|
||||||
|
"CI_COMMIT_SHA": "d0876d3176965f9552a611cbd56e24a9264355e6",
|
||||||
|
"CI_REMOTE_URL": "https://github.com/drone/envsubst.git",
|
||||||
|
"CI_REPO": "drone/envsubst",
|
||||||
|
"CI_REPO_LINK": "https://github.com/drone/envsubst",
|
||||||
|
"CI_REPO_NAME": "drone/envsubst",
|
||||||
|
"CI_REPO_REMOTE": "https://github.com/drone/envsubst.git",
|
||||||
|
"CI_SYSTEM": "pipec",
|
||||||
|
"CI_SYSTEM_ARCH": "windows/amd64",
|
||||||
|
"CI_SYSTEM_LINK": "https://github.com/cncd/pipec",
|
||||||
|
"CI_SYSTEM_NAME": "pipec",
|
||||||
|
"CI_WORKSPACE": "c:\\gopath/src\\github.com\\drone\\envsubst",
|
||||||
|
"DRONE": "true",
|
||||||
|
"DRONE_ARCH": "windows/amd64",
|
||||||
|
"DRONE_BRANCH": "master",
|
||||||
|
"DRONE_BUILD_CREATED": "1486119586",
|
||||||
|
"DRONE_BUILD_EVENT": "push",
|
||||||
|
"DRONE_BUILD_LINK": "https://github.com/cncd/pipec/drone/envsubst/6",
|
||||||
|
"DRONE_BUILD_NUMBER": "6",
|
||||||
|
"DRONE_BUILD_STARTED": "1486119585",
|
||||||
|
"DRONE_COMMIT": "d0876d3176965f9552a611cbd56e24a9264355e6",
|
||||||
|
"DRONE_COMMIT_AUTHOR": "bradrydzewski",
|
||||||
|
"DRONE_COMMIT_BRANCH": "master",
|
||||||
|
"DRONE_COMMIT_MESSAGE": "added a few more test cases for escaping behavior",
|
||||||
|
"DRONE_COMMIT_REF": "refs/heads/master",
|
||||||
|
"DRONE_COMMIT_SHA": "d0876d3176965f9552a611cbd56e24a9264355e6",
|
||||||
|
"DRONE_JOB_STARTED": "1486119585",
|
||||||
|
"DRONE_REMOTE_URL": "https://github.com/drone/envsubst.git",
|
||||||
|
"DRONE_REPO": "drone/envsubst",
|
||||||
|
"DRONE_REPO_LINK": "https://github.com/drone/envsubst",
|
||||||
|
"DRONE_REPO_NAME": "envsubst",
|
||||||
|
"DRONE_REPO_OWNER": "drone",
|
||||||
|
"DRONE_REPO_SCM": "git",
|
||||||
|
"DRONE_WORKSPACE": "c:\\gopath/src\\github.com\\drone\\envsubst",
|
||||||
|
"PLUGIN_DEPTH": "50"
|
||||||
|
},
|
||||||
|
"volumes": [
|
||||||
|
"pipeline_default:c:\\gopath"
|
||||||
|
],
|
||||||
|
"networks": [
|
||||||
|
{
|
||||||
|
"name": "pipeline_default",
|
||||||
|
"aliases": [
|
||||||
|
"git"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"on_success": true,
|
||||||
|
"auth_config": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "pipeline_stage_0",
|
||||||
|
"alias": "build",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"name": "pipeline_step_0",
|
||||||
|
"alias": "build",
|
||||||
|
"image": "golang:1.10.1-nanoserver-sac2016",
|
||||||
|
"working_dir": "c:\\gopath/src\\github.com\\drone\\envsubst",
|
||||||
|
"environment": {
|
||||||
|
"CI": "drone",
|
||||||
|
"CI_BUILD_CREATED": "1486119586",
|
||||||
|
"CI_BUILD_EVENT": "push",
|
||||||
|
"CI_BUILD_NUMBER": "6",
|
||||||
|
"CI_BUILD_STARTED": "1486119585",
|
||||||
|
"CI_COMMIT_AUTHOR": "bradrydzewski",
|
||||||
|
"CI_COMMIT_AUTHOR_NAME": "bradrydzewski",
|
||||||
|
"CI_COMMIT_BRANCH": "master",
|
||||||
|
"CI_COMMIT_MESSAGE": "added a few more test cases for escaping behavior",
|
||||||
|
"CI_COMMIT_REF": "refs/heads/master",
|
||||||
|
"CI_COMMIT_SHA": "d0876d3176965f9552a611cbd56e24a9264355e6",
|
||||||
|
"CI_REMOTE_URL": "https://github.com/drone/envsubst.git",
|
||||||
|
"CI_REPO": "drone/envsubst",
|
||||||
|
"CI_REPO_LINK": "https://github.com/drone/envsubst",
|
||||||
|
"CI_REPO_NAME": "drone/envsubst",
|
||||||
|
"CI_REPO_REMOTE": "https://github.com/drone/envsubst.git",
|
||||||
|
"CI_SCRIPT": "CiRFcnJvckFjdGlvblByZWZlcmVuY2UgPSAnU3RvcCc7CiZjbWQgL2MgIm1rZGlyIGM6XHJvb3QiOwppZiAoJEVudjpDSV9ORVRSQ19NQUNISU5FKSB7CiRuZXRyYz1bc3RyaW5nXTo6Rm9ybWF0KCJ7MH1cX25ldHJjIiwkRW52OkhPTUUpOwoibWFjaGluZSAkRW52OkNJX05FVFJDX01BQ0hJTkUiID4+ICRuZXRyYzsKImxvZ2luICRFbnY6Q0lfTkVUUkNfVVNFUk5BTUUiID4+ICRuZXRyYzsKInBhc3N3b3JkICRFbnY6Q0lfTkVUUkNfUEFTU1dPUkQiID4+ICRuZXRyYzsKfTsKW0Vudmlyb25tZW50XTo6U2V0RW52aXJvbm1lbnRWYXJpYWJsZSgiQ0lfTkVUUkNfUEFTU1dPUkQiLCRudWxsKTsKW0Vudmlyb25tZW50XTo6U2V0RW52aXJvbm1lbnRWYXJpYWJsZSgiQ0lfU0NSSVBUIiwkbnVsbCk7CltFbnZpcm9ubWVudF06OlNldEVudmlyb25tZW50VmFyaWFibGUoIkRST05FX05FVFJDX1VTRVJOQU1FIiwkbnVsbCk7CltFbnZpcm9ubWVudF06OlNldEVudmlyb25tZW50VmFyaWFibGUoIkRST05FX05FVFJDX1BBU1NXT1JEIiwkbnVsbCk7CgpXcml0ZS1PdXRwdXQgKCcrICJnbyBnZXQgLXQgLlxcLi4uIicpOyAgW0NvbnNvbGVdOjpPdXQuRmx1c2goKQomIGdvIGdldCAtdCAuXC4uLjsgaWYgKCRMQVNURVhJVENPREUgLW5lIDApIHtleGl0ICRMQVNURVhJVENPREV9CgpXcml0ZS1PdXRwdXQgKCcrICJnbyBidWlsZCInKTsgIFtDb25zb2xlXTo6T3V0LkZsdXNoKCkKJiBnbyBidWlsZDsgaWYgKCRMQVNURVhJVENPREUgLW5lIDApIHtleGl0ICRMQVNURVhJVENPREV9CgpXcml0ZS1PdXRwdXQgKCcrICJnbyB0ZXN0IC12IicpOyAgW0NvbnNvbGVdOjpPdXQuRmx1c2goKQomIGdvIHRlc3QgLXY7IGlmICgkTEFTVEVYSVRDT0RFIC1uZSAwKSB7ZXhpdCAkTEFTVEVYSVRDT0RFfQoK",
|
||||||
|
"CI_SYSTEM": "pipec",
|
||||||
|
"CI_SYSTEM_ARCH": "windows/amd64",
|
||||||
|
"CI_SYSTEM_LINK": "https://github.com/cncd/pipec",
|
||||||
|
"CI_SYSTEM_NAME": "pipec",
|
||||||
|
"CI_WORKSPACE": "c:\\gopath/src\\github.com\\drone\\envsubst",
|
||||||
|
"DRONE": "true",
|
||||||
|
"DRONE_ARCH": "windows/amd64",
|
||||||
|
"DRONE_BRANCH": "master",
|
||||||
|
"DRONE_BUILD_CREATED": "1486119586",
|
||||||
|
"DRONE_BUILD_EVENT": "push",
|
||||||
|
"DRONE_BUILD_LINK": "https://github.com/cncd/pipec/drone/envsubst/6",
|
||||||
|
"DRONE_BUILD_NUMBER": "6",
|
||||||
|
"DRONE_BUILD_STARTED": "1486119585",
|
||||||
|
"DRONE_COMMIT": "d0876d3176965f9552a611cbd56e24a9264355e6",
|
||||||
|
"DRONE_COMMIT_AUTHOR": "bradrydzewski",
|
||||||
|
"DRONE_COMMIT_BRANCH": "master",
|
||||||
|
"DRONE_COMMIT_MESSAGE": "added a few more test cases for escaping behavior",
|
||||||
|
"DRONE_COMMIT_REF": "refs/heads/master",
|
||||||
|
"DRONE_COMMIT_SHA": "d0876d3176965f9552a611cbd56e24a9264355e6",
|
||||||
|
"DRONE_JOB_STARTED": "1486119585",
|
||||||
|
"DRONE_REMOTE_URL": "https://github.com/drone/envsubst.git",
|
||||||
|
"DRONE_REPO": "drone/envsubst",
|
||||||
|
"DRONE_REPO_LINK": "https://github.com/drone/envsubst",
|
||||||
|
"DRONE_REPO_NAME": "envsubst",
|
||||||
|
"DRONE_REPO_OWNER": "drone",
|
||||||
|
"DRONE_REPO_SCM": "git",
|
||||||
|
"DRONE_WORKSPACE": "c:\\gopath/src\\github.com\\drone\\envsubst",
|
||||||
|
"HOME": "c:\\root",
|
||||||
|
"SHELL": "powershell.exe"
|
||||||
|
},
|
||||||
|
"entrypoint": [
|
||||||
|
"powershell",
|
||||||
|
"-noprofile",
|
||||||
|
"-noninteractive",
|
||||||
|
"-command"
|
||||||
|
],
|
||||||
|
"command": [
|
||||||
|
"[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($Env:CI_SCRIPT)) | iex"
|
||||||
|
],
|
||||||
|
"volumes": [
|
||||||
|
"pipeline_default:c:\\gopath"
|
||||||
|
],
|
||||||
|
"networks": [
|
||||||
|
{
|
||||||
|
"name": "pipeline_default",
|
||||||
|
"aliases": [
|
||||||
|
"build"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"on_success": true,
|
||||||
|
"auth_config": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"networks": [
|
||||||
|
{
|
||||||
|
"name": "pipeline_default",
|
||||||
|
"driver": "nat"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"volumes": [
|
||||||
|
{
|
||||||
|
"name": "pipeline_default",
|
||||||
|
"driver": "local"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"secrets": null
|
||||||
|
}
|
18
cncd/pipeline/samples/sample_10_windows/pipeline.yml
Normal file
18
cncd/pipeline/samples/sample_10_windows/pipeline.yml
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
platform: windows/amd64
|
||||||
|
|
||||||
|
workspace:
|
||||||
|
base: c:\gopath
|
||||||
|
path: src\github.com\drone\envsubst
|
||||||
|
|
||||||
|
clone:
|
||||||
|
git:
|
||||||
|
image: plugins/git:windows
|
||||||
|
depth: 50
|
||||||
|
|
||||||
|
pipeline:
|
||||||
|
build:
|
||||||
|
image: golang:1.10.1-nanoserver-sac2016
|
||||||
|
commands:
|
||||||
|
- go get -t .\...
|
||||||
|
- go build
|
||||||
|
- go test -v
|
231
cncd/pipeline/samples/sample_2/pipeline.json
Normal file
231
cncd/pipeline/samples/sample_2/pipeline.json
Normal file
|
@ -0,0 +1,231 @@
|
||||||
|
{
|
||||||
|
"pipeline": [
|
||||||
|
{
|
||||||
|
"name": "pipeline_clone",
|
||||||
|
"alias": "clone",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"name": "pipeline_clone",
|
||||||
|
"image": "plugins/git:latest",
|
||||||
|
"working_dir": "/go/src/github.com/go-sql-driver/mysql",
|
||||||
|
"environment": {
|
||||||
|
"CI": "pipec",
|
||||||
|
"CI_BUILD_CREATED": "1486119586",
|
||||||
|
"CI_BUILD_EVENT": "push",
|
||||||
|
"CI_BUILD_NUMBER": "530",
|
||||||
|
"CI_BUILD_STARTED": "1486119585",
|
||||||
|
"CI_COMMIT_AUTHOR": "egorsmkv",
|
||||||
|
"CI_COMMIT_AUTHOR_NAME": "egorsmkv",
|
||||||
|
"CI_COMMIT_BRANCH": "master",
|
||||||
|
"CI_COMMIT_MESSAGE": "Fix many urls",
|
||||||
|
"CI_COMMIT_REF": "refs/heads/master",
|
||||||
|
"CI_COMMIT_SHA": "2e00b5cd70399450106cec6431c2e2ce3cae5034",
|
||||||
|
"CI_REMOTE_URL": "https://github.com/go-sql-driver/mysql.git",
|
||||||
|
"CI_REPO": "go-sql-driver/mysql",
|
||||||
|
"CI_REPO_LINK": "https://github.com/go-sql-driver/mysql",
|
||||||
|
"CI_REPO_NAME": "go-sql-driver/mysql",
|
||||||
|
"CI_REPO_REMOTE": "https://github.com/go-sql-driver/mysql.git",
|
||||||
|
"CI_SYSTEM": "pipec",
|
||||||
|
"CI_SYSTEM_ARCH": "linux/amd64",
|
||||||
|
"CI_SYSTEM_LINK": "https://github.com/cncd/pipec",
|
||||||
|
"CI_SYSTEM_NAME": "pipec",
|
||||||
|
"CI_WORKSPACE": "/go/src/github.com/go-sql-driver/mysql",
|
||||||
|
"DRONE_BUILD_CREATED": "1486119586",
|
||||||
|
"DRONE_BUILD_EVENT": "push",
|
||||||
|
"DRONE_BUILD_NUMBER": "530",
|
||||||
|
"DRONE_BUILD_STARTED": "1486119585",
|
||||||
|
"DRONE_COMMIT_AUTHOR": "egorsmkv",
|
||||||
|
"DRONE_COMMIT_AUTHOR_NAME": "egorsmkv",
|
||||||
|
"DRONE_COMMIT_BRANCH": "master",
|
||||||
|
"DRONE_COMMIT_MESSAGE": "Fix many urls",
|
||||||
|
"DRONE_COMMIT_REF": "refs/heads/master",
|
||||||
|
"DRONE_COMMIT_SHA": "2e00b5cd70399450106cec6431c2e2ce3cae5034",
|
||||||
|
"DRONE_REMOTE_URL": "https://github.com/go-sql-driver/mysql.git",
|
||||||
|
"DRONE_REPO": "go-sql-driver/mysql",
|
||||||
|
"DRONE_REPO_LINK": "https://github.com/go-sql-driver/mysql",
|
||||||
|
"DRONE_REPO_NAME": "go-sql-driver/mysql",
|
||||||
|
"DRONE_REPO_REMOTE": "https://github.com/go-sql-driver/mysql.git",
|
||||||
|
"DRONE_SYSTEM": "pipec",
|
||||||
|
"DRONE_SYSTEM_ARCH": "linux/amd64",
|
||||||
|
"DRONE_SYSTEM_LINK": "https://github.com/cncd/pipec",
|
||||||
|
"DRONE_SYSTEM_NAME": "pipec",
|
||||||
|
"DRONE_WORKSPACE": "/go/src/github.com/go-sql-driver/mysql",
|
||||||
|
"PLUGIN_DEPTH": "0"
|
||||||
|
},
|
||||||
|
"volumes": [
|
||||||
|
"pipeline_default:/go"
|
||||||
|
],
|
||||||
|
"networks": [
|
||||||
|
{
|
||||||
|
"name": "pipeline_default",
|
||||||
|
"aliases": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"on_success": true,
|
||||||
|
"auth_config": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "pipeline_services",
|
||||||
|
"alias": "services",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"name": "pipeline_services_0",
|
||||||
|
"alias": "database",
|
||||||
|
"image": "mysql:latest",
|
||||||
|
"detach": true,
|
||||||
|
"environment": {
|
||||||
|
"CI": "pipec",
|
||||||
|
"CI_BUILD_CREATED": "1486119586",
|
||||||
|
"CI_BUILD_EVENT": "push",
|
||||||
|
"CI_BUILD_NUMBER": "530",
|
||||||
|
"CI_BUILD_STARTED": "1486119585",
|
||||||
|
"CI_COMMIT_AUTHOR": "egorsmkv",
|
||||||
|
"CI_COMMIT_AUTHOR_NAME": "egorsmkv",
|
||||||
|
"CI_COMMIT_BRANCH": "master",
|
||||||
|
"CI_COMMIT_MESSAGE": "Fix many urls",
|
||||||
|
"CI_COMMIT_REF": "refs/heads/master",
|
||||||
|
"CI_COMMIT_SHA": "2e00b5cd70399450106cec6431c2e2ce3cae5034",
|
||||||
|
"CI_REMOTE_URL": "https://github.com/go-sql-driver/mysql.git",
|
||||||
|
"CI_REPO": "go-sql-driver/mysql",
|
||||||
|
"CI_REPO_LINK": "https://github.com/go-sql-driver/mysql",
|
||||||
|
"CI_REPO_NAME": "go-sql-driver/mysql",
|
||||||
|
"CI_REPO_REMOTE": "https://github.com/go-sql-driver/mysql.git",
|
||||||
|
"CI_SYSTEM": "pipec",
|
||||||
|
"CI_SYSTEM_ARCH": "linux/amd64",
|
||||||
|
"CI_SYSTEM_LINK": "https://github.com/cncd/pipec",
|
||||||
|
"CI_SYSTEM_NAME": "pipec",
|
||||||
|
"CI_WORKSPACE": "/go/src/github.com/go-sql-driver/mysql",
|
||||||
|
"DRONE_BUILD_CREATED": "1486119586",
|
||||||
|
"DRONE_BUILD_EVENT": "push",
|
||||||
|
"DRONE_BUILD_NUMBER": "530",
|
||||||
|
"DRONE_BUILD_STARTED": "1486119585",
|
||||||
|
"DRONE_COMMIT_AUTHOR": "egorsmkv",
|
||||||
|
"DRONE_COMMIT_AUTHOR_NAME": "egorsmkv",
|
||||||
|
"DRONE_COMMIT_BRANCH": "master",
|
||||||
|
"DRONE_COMMIT_MESSAGE": "Fix many urls",
|
||||||
|
"DRONE_COMMIT_REF": "refs/heads/master",
|
||||||
|
"DRONE_COMMIT_SHA": "2e00b5cd70399450106cec6431c2e2ce3cae5034",
|
||||||
|
"DRONE_REMOTE_URL": "https://github.com/go-sql-driver/mysql.git",
|
||||||
|
"DRONE_REPO": "go-sql-driver/mysql",
|
||||||
|
"DRONE_REPO_LINK": "https://github.com/go-sql-driver/mysql",
|
||||||
|
"DRONE_REPO_NAME": "go-sql-driver/mysql",
|
||||||
|
"DRONE_REPO_REMOTE": "https://github.com/go-sql-driver/mysql.git",
|
||||||
|
"DRONE_SYSTEM": "pipec",
|
||||||
|
"DRONE_SYSTEM_ARCH": "linux/amd64",
|
||||||
|
"DRONE_SYSTEM_LINK": "https://github.com/cncd/pipec",
|
||||||
|
"DRONE_SYSTEM_NAME": "pipec",
|
||||||
|
"DRONE_WORKSPACE": "/go/src/github.com/go-sql-driver/mysql",
|
||||||
|
"MYSQL_ALLOW_EMPTY_PASSWORD": "yes",
|
||||||
|
"MYSQL_DATABASE": "gotest"
|
||||||
|
},
|
||||||
|
"volumes": [
|
||||||
|
"pipeline_default:/go"
|
||||||
|
],
|
||||||
|
"networks": [
|
||||||
|
{
|
||||||
|
"name": "pipeline_default",
|
||||||
|
"aliases": [
|
||||||
|
"database"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"on_success": true,
|
||||||
|
"auth_config": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "pipeline_stage_0",
|
||||||
|
"alias": "build",
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"name": "pipeline_step_0",
|
||||||
|
"alias": "build",
|
||||||
|
"image": "golang:1.7",
|
||||||
|
"working_dir": "/go/src/github.com/go-sql-driver/mysql",
|
||||||
|
"environment": {
|
||||||
|
"CI": "pipec",
|
||||||
|
"CI_BUILD_CREATED": "1486119586",
|
||||||
|
"CI_BUILD_EVENT": "push",
|
||||||
|
"CI_BUILD_NUMBER": "530",
|
||||||
|
"CI_BUILD_STARTED": "1486119585",
|
||||||
|
"CI_COMMIT_AUTHOR": "egorsmkv",
|
||||||
|
"CI_COMMIT_AUTHOR_NAME": "egorsmkv",
|
||||||
|
"CI_COMMIT_BRANCH": "master",
|
||||||
|
"CI_COMMIT_MESSAGE": "Fix many urls",
|
||||||
|
"CI_COMMIT_REF": "refs/heads/master",
|
||||||
|
"CI_COMMIT_SHA": "2e00b5cd70399450106cec6431c2e2ce3cae5034",
|
||||||
|
"CI_REMOTE_URL": "https://github.com/go-sql-driver/mysql.git",
|
||||||
|
"CI_REPO": "go-sql-driver/mysql",
|
||||||
|
"CI_REPO_LINK": "https://github.com/go-sql-driver/mysql",
|
||||||
|
"CI_REPO_NAME": "go-sql-driver/mysql",
|
||||||
|
"CI_REPO_REMOTE": "https://github.com/go-sql-driver/mysql.git",
|
||||||
|
"CI_SCRIPT": "CmlmIFsgLW4gIiRDSV9ORVRSQ19NQUNISU5FIiBdOyB0aGVuCmNhdCA8PEVPRiA+ICRIT01FLy5uZXRyYwptYWNoaW5lICRDSV9ORVRSQ19NQUNISU5FCmxvZ2luICRDSV9ORVRSQ19VU0VSTkFNRQpwYXNzd29yZCAkQ0lfTkVUUkNfUEFTU1dPUkQKRU9GCmNobW9kIDA2MDAgJEhPTUUvLm5ldHJjCmZpCnVuc2V0IENJX05FVFJDX1VTRVJOQU1FCnVuc2V0IENJX05FVFJDX1BBU1NXT1JECnVuc2V0IENJX1NDUklQVAoKZWNobyArICJzbGVlcCAyMCIKc2xlZXAgMjAKCmVjaG8gKyAiZ28gZ2V0IC12IC10IgpnbyBnZXQgLXYgLXQKCmVjaG8gKyAiZ28gdGVzdCAtdiIKZ28gdGVzdCAtdgoK",
|
||||||
|
"CI_SYSTEM": "pipec",
|
||||||
|
"CI_SYSTEM_ARCH": "linux/amd64",
|
||||||
|
"CI_SYSTEM_LINK": "https://github.com/cncd/pipec",
|
||||||
|
"CI_SYSTEM_NAME": "pipec",
|
||||||
|
"CI_WORKSPACE": "/go/src/github.com/go-sql-driver/mysql",
|
||||||
|
"DRONE_BUILD_CREATED": "1486119586",
|
||||||
|
"DRONE_BUILD_EVENT": "push",
|
||||||
|
"DRONE_BUILD_NUMBER": "530",
|
||||||
|
"DRONE_BUILD_STARTED": "1486119585",
|
||||||
|
"DRONE_COMMIT_AUTHOR": "egorsmkv",
|
||||||
|
"DRONE_COMMIT_AUTHOR_NAME": "egorsmkv",
|
||||||
|
"DRONE_COMMIT_BRANCH": "master",
|
||||||
|
"DRONE_COMMIT_MESSAGE": "Fix many urls",
|
||||||
|
"DRONE_COMMIT_REF": "refs/heads/master",
|
||||||
|
"DRONE_COMMIT_SHA": "2e00b5cd70399450106cec6431c2e2ce3cae5034",
|
||||||
|
"DRONE_REMOTE_URL": "https://github.com/go-sql-driver/mysql.git",
|
||||||
|
"DRONE_REPO": "go-sql-driver/mysql",
|
||||||
|
"DRONE_REPO_LINK": "https://github.com/go-sql-driver/mysql",
|
||||||
|
"DRONE_REPO_NAME": "go-sql-driver/mysql",
|
||||||
|
"DRONE_REPO_REMOTE": "https://github.com/go-sql-driver/mysql.git",
|
||||||
|
"DRONE_SYSTEM": "pipec",
|
||||||
|
"DRONE_SYSTEM_ARCH": "linux/amd64",
|
||||||
|
"DRONE_SYSTEM_LINK": "https://github.com/cncd/pipec",
|
||||||
|
"DRONE_SYSTEM_NAME": "pipec",
|
||||||
|
"DRONE_WORKSPACE": "/go/src/github.com/go-sql-driver/mysql",
|
||||||
|
"HOME": "/root",
|
||||||
|
"MYSQL_TEST_ADDR": "database:3306",
|
||||||
|
"SHELL": "/bin/sh"
|
||||||
|
},
|
||||||
|
"entrypoint": [
|
||||||
|
"/bin/sh",
|
||||||
|
"-c"
|
||||||
|
],
|
||||||
|
"command": [
|
||||||
|
"echo $CI_SCRIPT | base64 -d | /bin/sh -e"
|
||||||
|
],
|
||||||
|
"volumes": [
|
||||||
|
"pipeline_default:/go"
|
||||||
|
],
|
||||||
|
"networks": [
|
||||||
|
{
|
||||||
|
"name": "pipeline_default",
|
||||||
|
"aliases": [
|
||||||
|
"database"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"on_success": true,
|
||||||
|
"auth_config": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"networks": [
|
||||||
|
{
|
||||||
|
"name": "pipeline_default",
|
||||||
|
"driver": "bridge"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"volumes": [
|
||||||
|
{
|
||||||
|
"name": "pipeline_default",
|
||||||
|
"driver": "local"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
20
cncd/pipeline/samples/sample_2/pipeline.yml
Normal file
20
cncd/pipeline/samples/sample_2/pipeline.yml
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
workspace:
|
||||||
|
base: /go
|
||||||
|
path: src/github.com/go-sql-driver/mysql
|
||||||
|
|
||||||
|
pipeline:
|
||||||
|
build:
|
||||||
|
image: golang:1.7
|
||||||
|
environment:
|
||||||
|
MYSQL_TEST_ADDR: database:3306
|
||||||
|
commands:
|
||||||
|
- sleep 20
|
||||||
|
- go get -v -t
|
||||||
|
- go test -v
|
||||||
|
|
||||||
|
services:
|
||||||
|
database:
|
||||||
|
image: mysql
|
||||||
|
environment:
|
||||||
|
- MYSQL_DATABASE=gotest
|
||||||
|
- MYSQL_ALLOW_EMPTY_PASSWORD=yes
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue